diff --git a/README.en.md b/README.en.md index 8de3e0535c0d52b7e91712129c13f081f675a399..b3ad9facb764180553b54dc69fa456697afe7ae9 100644 --- a/README.en.md +++ b/README.en.md @@ -10,37 +10,47 @@ This sample demonstrates video playback, manual and automatic invocation of Pict ## How to Use -1. On the home page, touch a video to access the corresponding video playback page. -2. On the video playback page, touch **Enable**. The app starts a PiP window. Touch **Disable**. The PiP window is closed. -3. On the video playback page, enable **Auto PiP**. When you return to the home screen, the app starts a PiP window. -4. The video playback page displays callback information. +1. On the video playback page, touch **Enable**. The app starts a PiP window. Touch **Disable**. The PiP window is closed. +2. On the video playback page, enable **Auto PiP**. When you return to the home screen, the app starts a PiP window. +3. The video playback page displays callback information. ## Project Directory +Here is the English translation of your directory structure, maintaining the original format and spacing: + ``` -├──entry/src/main/ets // Core code +window-pip +├──windowpiplibrary/src/main/ets +│ ├──component +│ │ ├──ImageWidthTitle.ets // Default player image +│ │ ├──VideoPlayComponent.ets // Video playback component class +│ │ └──WindowPipComponent.ets // Picture-in-Picture component class │ ├──constants -│ │ └──Constants.ets // Constants +│ │ └──CommonConstants.ets // Constants class +│ ├──player +│ │ └──AVPlayer.ets // Video playback +│ ├──utils +│ │ ├───BreakpointSystem.ets // Multi-device adaptation class +│ │ ├───Logger.ets // Logging class +│ │ └───WindowUtil.ets // General window utility class +│ └───WindowPipController.ets // Controller class, window control +└────windowpiplibrary/src/main/resources // Resources directory +├──windowpipsample/src/main/ets │ ├──entryability -│ │ └──EntryAbility.ets +│ │ └──EntryAbility.ets // Application lifecycle class │ ├──pages -│ │ ├──AVPlayer.ets // Video playback -│ │ ├──Index.ets // Home page -│ │ └──VideoPlay.ets // Video playback page -│ └──utils -│ └──Logger.ets // Log utility -└──entry/src/main/resources // Static resources +│ │ └──Index.ets // Main page +└────windowpipsample/src/main/resources // Resources directory ``` ## How to Implement -- The sample uses the **Navigation** component to construct the pages. Five clickable videos are placed on the home page. When you touch a video, the corresponding video playback page is displayed. - The video playback page can be divided into three areas: XComponent on the top, PIP control buttons in the middle, and callback information in the lower part. - After you touch **Enable**, the app starts a PiP window, and the video is played in the PiP window. When you return to the home screen, the video is still played in the PiP window. After you touch **Disable**, the video is played in the XComponent area, and no PiP window is started when you return to the home screen. - After you enable **Auto PiP**, the app automatically starts a PiP window when you return to the home screen, and the video is played in the PiP window. - When a video is displayed in the PiP window, the XComponent area displays the message "The video is being played in PiP mode." -- The callback information shows the status, error cause, and button event and status. For details, see [VideoPlay.ets](windowpiplibrary/src/main/ets/pages/VideoPlay.ets). +- The callback information shows the status, error cause, and button event and status. For details, see [VideoPlay.ets](windowpiplibrary/src/main/ets/component/VideoPlayComponent.ets). ## Required Permissions diff --git a/README.md b/README.md index 9ba3b962985c4ae87a27f4465c018e2348e3a097..677deccf300439d25b6916b4303df128009233a9 100644 --- a/README.md +++ b/README.md @@ -10,37 +10,46 @@ ## 使用说明 -1. 在主界面,可以**点击对应视频按钮**进入**视频播放页面**; -2. 视频播放页面**点击开启**,应用**拉起画中画**,点击**关闭**,**关闭画中画**; -3. 视频播放页面**点击自动开启画中画**,在返回桌面时会**自动拉起画中画**; -4. 视频播放页面会显示一些**回调信息**。 +1. 视频播放页面**点击开启**,应用**拉起画中画**,点击**关闭**,**关闭画中画**; +2. 视频播放页面**点击自动开启画中画**,在返回桌面时会**自动拉起画中画**; +3. 视频播放页面会显示一些**回调信息**。 ## 工程目录 ``` -├──entry/src/main/ets // 代码区 +window-pip +├──windowpiplibrary/src/main/ets +│ ├──component +│ │ ├──ImageWidthTitle.ets // 播放器默认图 +│ │ ├──VideoPlayComponent.ets // 视频播放组件类 +│ │ └──WindowPipComponent.ets // 画中画组件类 │ ├──constants -│ │ └──Constants.ets // 常量类 +│ │ └──CommonConstants.ets // 常量类 +│ ├──player +│ │ └──AVPlayer.ets // 视频播放 +│ ├──utils +│ │ ├───BreakpointSystem.ets // 一多类 +│ │ ├───Logger.ets // 打印信息类 +│ │ └───WindowUtil.ets // 通用窗口类 +│ └───WindowPipController.ets // 控制器类,窗口控制 +└────windowpiplibrary/src/main/resources // 资源目录 +├──windowpipsample/src/main/ets │ ├──entryability -│ │ └──EntryAbility.ets +│ │ └──EntryAbility.ets // 应用生命周期类 │ ├──pages -│ │ ├──AVPlayer.ets // 视频播放 -│ │ ├──Index.ets // 首页 -│ │ └──VideoPlay.ets // 视频播放页面 -│ └──utils -│ └──Logger.ets // 日志工具类 -└──entry/src/main/resources // 应用资源目录 +│ │ └──Index.ets // 主页面 +└────windowpipsample/src/main/resources // 资源目录 + ``` ## 具体实现 -- 整个示例用**Navigation**构建页面,主页面放置五个可点击视频框,点击之后进入视频播放页面。 - 进入视频播放页面后,有三块区域,最上方的**XComponent**,中间的**画中画控制按钮**以及下方的**回调信息显示框**。 - 点击**开启**后,应用手动拉起画中画,视频在画中画播放,返回桌面视频依旧画中画播放;点击**关闭**后,画中画播放的视频返回**XComponent**播放,同时返回桌面不会拉起画中画。 - 点击**自动拉起画中画**后,返回桌面时应用自动拉起画中画,视频画中画播放。 - 在播放页面进行画中画播放时,XComponent框会提示**当前视频正在以画中画播放**。 -- 回调信息显示框会显示**当前状态**,**错误原因**以及**按钮事件和状态**,参考:[VideoPlay.ets](windowpiplibrary/src/main/ets/pages/VideoPlay.ets)。 +- 回调信息显示框会显示**当前状态**,**错误原因**以及**按钮事件和状态**,参考:[VideoPlay.ets](windowpiplibrary/src/main/ets/component/VideoPlayComponent.ets)。 ## 相关权限 diff --git a/windowpiplibrary/Index.ets b/windowpiplibrary/Index.ets index 2a08d875b30832bd47b39c4abca8acf4cc82603e..128520f228b4d96ca55f593e8509dba91ca2935c 100644 --- a/windowpiplibrary/Index.ets +++ b/windowpiplibrary/Index.ets @@ -1,2 +1,3 @@ -export { WindowPipPage } from './src/main/ets/pages/WindowPipPage'; -export { WindowUtil } from './src/main/ets/utils/WindowUtil'; +export { WindowPipComponent } from './src/main/ets/component/WindowPipComponent'; + +export { WindowPipController } from './src/main/ets/WindowPipController'; diff --git a/windowpiplibrary/build-profile.json5 b/windowpiplibrary/build-profile.json5 index 312d38eb08629793b3484c7373213f22840c8d82..cda3307123ec7c43181580a86ef7e82a18319a34 100644 --- a/windowpiplibrary/build-profile.json5 +++ b/windowpiplibrary/build-profile.json5 @@ -8,7 +8,7 @@ "arkOptions": { "obfuscation": { "ruleOptions": { - "enable": true, + "enable": false, "files": [ "./obfuscation-rules.txt" ] diff --git a/windowpiplibrary/src/main/ets/WindowPipController.ets b/windowpiplibrary/src/main/ets/WindowPipController.ets new file mode 100644 index 0000000000000000000000000000000000000000..c3e13cbfc89af447586806099620fd306009b6b7 --- /dev/null +++ b/windowpiplibrary/src/main/ets/WindowPipController.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 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 { window } from '@kit.ArkUI'; +import { WindowUtil } from './utils/WindowUtil'; +import { common } from '@kit.AbilityKit'; + +export class WindowPipController { + public static initWindowConfig(windowStage: window.WindowStage): void { + WindowUtil.initialize(windowStage); + } + + public static updatedColorMode(context: common.UIAbilityContext): void { + WindowUtil.updatedColorMode(context); + } +} \ No newline at end of file diff --git a/windowpiplibrary/src/main/ets/component/ImageWidthTitle.ets b/windowpiplibrary/src/main/ets/component/ImageWidthTitle.ets new file mode 100644 index 0000000000000000000000000000000000000000..fc3cb267b0bb30a8b6a8467690bdc42b0bc8347e --- /dev/null +++ b/windowpiplibrary/src/main/ets/component/ImageWidthTitle.ets @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 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 { CommonConstants } from '../constants/CommonConstants'; +import Logger from '../utils/Logger'; + +@Component +export struct ImageWidthTitle { + @State imageHeight: number = 0; + @Link pageInfos: NavPathStack; + @State titleResource?: Resource | undefined = undefined; + + build() { + Column() { + Image($r('app.media.btn_ground')) + .width(CommonConstants.FULL_PERCENT) + .height(this.imageHeight) + .borderRadius({ + topLeft: $r('sys.float.corner_radius_level6'), + topRight: $r('sys.float.corner_radius_level6') + }) + .objectFit(ImageFit.Cover) + .draggable(false) + Text(this.titleResource) + .fontSize($r('sys.float.Subtitle_M')) + .fontColor($r('sys.color.font_primary')) + .margin($r('sys.float.corner_radius_level4')) + } + .borderRadius($r('sys.float.corner_radius_level6')) + .backgroundColor($r('sys.color.comp_background_primary')) + .alignItems(HorizontalAlign.Start) + .onClick(() => { + this.getUIContext().getHostContext()!.eventHub.emit('onStateChange', true); + this.pageInfos?.pushPath({ name: CommonConstants.NAV_DESTINATION_NAME }, { launchMode: 3 }); + }) + .onAreaChange((oldArea: Area, newArea: Area) => { + let width: number = newArea.width as number; + this.imageHeight = width * 9 / 16; + Logger.info(`[onAreaChange] oldArea:${oldArea} ,newArea:${newArea}`); + }) + } +} + diff --git a/windowpiplibrary/src/main/ets/pages/VideoPlay.ets b/windowpiplibrary/src/main/ets/component/VideoPlayComponent.ets similarity index 53% rename from windowpiplibrary/src/main/ets/pages/VideoPlay.ets rename to windowpiplibrary/src/main/ets/component/VideoPlayComponent.ets index c587f60d4390538c6e71ad2f58b61681881ee57c..5e59bb04020dc5dfabcd25bdb10e49dc36fdc235 100644 --- a/windowpiplibrary/src/main/ets/pages/VideoPlay.ets +++ b/windowpiplibrary/src/main/ets/component/VideoPlayComponent.ets @@ -14,11 +14,12 @@ */ import { PiPWindow } from '@kit.ArkUI'; -import { Constants } from '../constants/Constants'; -import { AVPlayer } from './AVPlayer'; +import { AVPlayer } from '../player/AVPlayer'; import Logger from '../utils/Logger'; +import { CommonConstants } from '../constants/CommonConstants'; +import { BreakpointTypeEnum } from '../utils/BreakpointSystem'; -const TAG = Constants.NAV_DESTINATION_NAME; +const TAG = CommonConstants.NAV_DESTINATION_NAME; @Extend(Text) function textType() { @@ -37,7 +38,7 @@ function msgType() { @Extend(Row) function twoTextRow() { .height(22) - .width(Constants.FULL_PERCENT) + .width(CommonConstants.FULL_PERCENT) .justifyContent(FlexAlign.SpaceBetween) } @@ -52,7 +53,7 @@ function twoTextDivider() { function dataListColumn() { .justifyContent(FlexAlign.SpaceBetween) .backgroundColor($r('sys.color.comp_background_primary')) - .width(Constants.FULL_PERCENT) + .width(CommonConstants.FULL_PERCENT) .padding({ right: $r('sys.float.corner_radius_level6'), left: $r('sys.float.corner_radius_level6') @@ -60,8 +61,8 @@ function dataListColumn() { } @Component -export struct PlayVideo { - @StorageLink('currentBreakpoint') curBp: string = Constants.BREAK_POINT_SM; +export struct VideoPlayComponent { + @StorageLink(CommonConstants.KEY_PREFIX_BREAKPOINT) curBp: string = BreakpointTypeEnum.SM; @State curState: string = ''; @State curError: ResourceStr = ''; @State buttonAction: string = ''; @@ -69,13 +70,11 @@ export struct PlayVideo { @State hintMsgVisibility: boolean = false; private mXComponentController = new XComponentController(); private surfaceId = ''; - private navigationId: string = ''; + @State navigationId: string = ''; private player?: AVPlayer; private pipController: PiPWindow.PiPController | undefined = undefined; - private eventHub = getContext().eventHub; + private eventHub = this.getUIContext().getHostContext()!.eventHub; private scrollerForScroll: Scroller = new Scroller(); - private defaultListData: Array = [1, 2, 3, 4, 5, 6]; - private pathStack: NavPathStack = new NavPathStack(); aboutToAppear(): void { this.eventHub.on('onStateChange', (fg: boolean) => { @@ -92,14 +91,9 @@ export struct PlayVideo { this.player = undefined; } this.eventHub?.off('onStateChange'); - this.pipController?.off('stateChange'); - this.pipController?.off('controlPanelActionEvent'); } async startPip(): Promise { - if (!this.pipController) { - await this.createPipController(); - } if (!this.pipController) { Logger.info(`[${TAG}] pipController create error`); return; @@ -115,14 +109,24 @@ export struct PlayVideo { await this.pipController.stopPiP(); } + async createPip(): Promise { + if (this.pipController) { + this.pipController.off('stateChange'); + this.pipController.off('controlPanelActionEvent'); + await this.pipController.stopPiP(); + } + await this.createPipController(); + await this.startPip(); + } + async createPipController(): Promise { this.pipController = await PiPWindow.create({ - context: getContext(this), + context: this.getUIContext().getHostContext()!, componentController: this.mXComponentController, navigationId: this.navigationId, templateType: PiPWindow.PiPTemplateType.VIDEO_PLAY, contentWidth: this.curBp === 'sm' ? 16 : this.curBp === 'md' ? 16 : 3, - contentHeight: this.curBp === 'sm' ? 9 : this.curBp === 'md' ? 9 : 2, + contentHeight: this.curBp === 'sm' ? 9 : this.curBp === 'md' ? 9 : 2 }); this.pipController.on('stateChange', (state: PiPWindow.PiPState, reason: string) => { this.onStateChange(state, reason); @@ -193,6 +197,17 @@ export struct PlayVideo { Logger.info(`[${TAG}] onActionEvent: ${this.buttonAction} status:${status}}`); } + showToast() { + try { + this.getUIContext().getPromptAction().showToast(({ + message: $r('app.string.notsupport'), + duration: 2000 + })); + } catch (error) { + Logger.error(`showToast args error code is ${error.code}, message is ${error.message}}`); + } + } + @Builder AutoPip() { Row() { @@ -205,14 +220,20 @@ export struct PlayVideo { .selectedColor($r('sys.color.brand')) .onChange(async (isOn: boolean) => { this.isAutoPull = isOn; - if (!this.pipController) { - await this.createPipController(); + if (isOn) { + if (this.curBp === 'xl') { + this.showToast(); + return; + } + if (!this.pipController) { + await this.createPipController(); + } + this.pipController?.setAutoStartEnabled(this.isAutoPull); + this.hintMsgVisibility = true; } - this.pipController?.setAutoStartEnabled(this.isAutoPull); - this.hintMsgVisibility = true; }) } - .width(Constants.FULL_PERCENT) + .width(CommonConstants.FULL_PERCENT) .height($r('app.integer.auto_pip_height')) .backgroundColor($r('sys.color.comp_background_primary')) .borderRadius($r('sys.float.corner_radius_level8')) @@ -228,7 +249,7 @@ export struct PlayVideo { Column() { Text($r('app.string.callback_message')) .fontSize($r('sys.float.Subtitle_L')) - .width(Constants.FULL_PERCENT) + .width(CommonConstants.FULL_PERCENT) .fontColor($r('sys.color.font_secondary')) .padding({ right: $r('sys.float.corner_radius_level6'), @@ -303,179 +324,105 @@ export struct PlayVideo { } } - @Builder - defaultListPage() { - Row() { - } - .backgroundColor($r('sys.color.comp_background_primary')) - .height(60) - .width(Constants.FULL_PERCENT) - .borderRadius($r('sys.float.corner_radius_level6')) - .margin({ - top: $r('sys.float.padding_level8'), - right: $r('sys.float.padding_level8'), - left: $r('sys.float.padding_level8') - }) - } - build() { - Column() { - NavDestination() { - SideBarContainer(SideBarContainerType.Embed) { - Column() { - ForEach(this.defaultListData, () => { - this.defaultListPage() - }, (item: number, index: number) => (item + index).toString()) - } - .backgroundColor($r('sys.color.background_secondary')) - .padding({ - top: $r('sys.float.padding_level16') - }) - .margin({ - right: $r('sys.float.padding_level8'), - left: $r('sys.float.padding_level8') - }) - - Column({ space: Constants.SPACE }) { - Stack() { - RelativeContainer() { - XComponent({ - id: 'video', - type: XComponentType.SURFACE, - controller: this.mXComponentController - }) - .onLoad(() => { - Logger.info(`[${TAG}] XComponent onLoad`); - this.surfaceId = this.mXComponentController.getXComponentSurfaceId(); - this.player = new AVPlayer(this.surfaceId, Constants.AVPLAYER_TYPE); - this.player.avPlayerFdSrc(); - }) - .onDestroy(() => { - this.player?.stopAvPlayer(); - Logger.info(`[${TAG}] XComponent onDestroy`); - }) - .size({ - width: Constants.X_COMPONENT_WIDTH, - height: '100%' - }) - .backgroundColor($r('app.color.video_background_dark')) - .align(Alignment.Bottom) - .id('x_component') - - Row() { - SymbolGlyph($r('sys.symbol.chevron_left')) - .fontColor([$r('sys.color.icon_on_primary')]) - .fontSize($r('sys.float.Title_M')) - } - .justifyContent(FlexAlign.Center) - .alignItems(VerticalAlign.Center) - .backgroundColor($r('app.color.icon_background_dark')) - .height(40) - .aspectRatio(1) - .alignRules({ - top: { anchor: '__container__', align: VerticalAlign.Top }, - left: { anchor: '__container__', align: HorizontalAlign.Start } - }) - .borderRadius($r('sys.float.corner_radius_level12')) - .margin({ - top: $r('sys.float.padding_level16'), - left: this.curBp === 'sm' ? $r('sys.float.padding_level6') : $r('sys.float.padding_level12') - }) - .onClick(() => { - this.pathStack.pop(); - }) + NavDestination() { + Column({ space: CommonConstants.SPACE }) { + Stack() { + RelativeContainer() { + XComponent({ + id: 'video', + type: XComponentType.SURFACE, + controller: this.mXComponentController + }) + .onLoad(() => { + Logger.info(`[${TAG}] XComponent onLoad`); + this.surfaceId = this.mXComponentController.getXComponentSurfaceId(); + this.player = new AVPlayer(this.surfaceId, CommonConstants.AVPLAYER_TYPE, this.getUIContext().getHostContext()!); + this.player.avPlayerFdSrc(); + }) + .onDestroy(() => { + this.player?.stopAvPlayer(); + Logger.info(`[${TAG}] XComponent onDestroy`); + }) + .size({ + width: CommonConstants.X_COMPONENT_WIDTH, + height: '100%' + }) + .backgroundColor($r('app.color.video_background_dark')) + .align(Alignment.Bottom) + .id('x_component') - Row() { - SymbolGlyph(this.curState === 'STOPPED' ? $r('sys.symbol.enlarge_window') : - $r('sys.symbol.smal_window_playback')) - .fontColor([$r('sys.color.icon_on_primary')]) - .fontSize($r('sys.float.Title_M')) - } - .justifyContent(FlexAlign.Center) - .alignItems(VerticalAlign.Center) - .backgroundColor($r('app.color.icon_background_dark')) - .height(40) - .aspectRatio(1) - .alignRules({ - top: { anchor: '__container__', align: VerticalAlign.Top }, - right: { anchor: '__container__', align: HorizontalAlign.End } - }) - .borderRadius($r('sys.float.corner_radius_level12')) - .margin({ - top: $r('sys.float.padding_level16'), - right: this.curBp === 'sm' ? $r('sys.float.padding_level6') : $r('sys.float.padding_level12') - }) - .onClick(() => { - if (this.curState === 'STARTED') { - this.stopPip(); - this.hintMsgVisibility = false; - } else if (this.curState === 'STOPPED') { - this.startPip(); - this.hintMsgVisibility = true; - } else { - this.startPip(); - this.hintMsgVisibility = true; - } - }) - } + Row() { + SymbolGlyph(this.curState === 'STOPPED' ? $r('sys.symbol.enlarge_window') : + $r('sys.symbol.smal_window_playback')) + .fontColor([$r('sys.color.icon_on_primary')]) + .fontSize($r('sys.float.Title_M')) } - .backgroundColor($r('sys.color.background_primary')) - .size({ - width: Constants.X_COMPONENT_WIDTH, - height: this.curBp === 'sm' ? '30%' : this.curBp === 'md' ? '45%' : '40%' + .justifyContent(FlexAlign.Center) + .alignItems(VerticalAlign.Center) + .backgroundColor($r('app.color.icon_background_dark')) + .height(40) + .aspectRatio(1) + .alignRules({ + top: { anchor: '__container__', align: VerticalAlign.Top }, + right: { anchor: '__container__', align: HorizontalAlign.End } }) - - Scroll(this.scrollerForScroll) { - Column({ space: Constants.SPACE }) { - this.AutoPip() - this.CallbackMessage() + .borderRadius($r('sys.float.corner_radius_level12')) + .margin({ + top: $r('sys.float.padding_level16'), + right: this.curBp === 'sm' ? $r('sys.float.padding_level6') : $r('sys.float.padding_level12') + }) + .onClick(() => { + if (this.curBp === 'xl') { + this.showToast(); + return; + } + if (this.curState === 'STARTED') { + this.stopPip(); + this.hintMsgVisibility = false; + } else if (this.curState === 'STOPPED') { + this.startPip(); + this.hintMsgVisibility = true; + } else { + this.createPip(); + this.hintMsgVisibility = true; } - .height(Constants.FULL_PERCENT) - .justifyContent(FlexAlign.Start) - .width(Constants.NAV_DESTINATION_WIDTH) - } - .layoutWeight(Constants.SCROLL_LAY_OUT_WEIGHT) - .scrollable(ScrollDirection.Vertical) - .scrollBar(BarState.Off) - .edgeEffect(EdgeEffect.Spring) - .padding({ - right: $r('sys.float.corner_radius_level6'), - left: $r('sys.float.corner_radius_level6') }) } - .width(Constants.NAV_DESTINATION_WIDTH) - .height(Constants.NAV_DESTINATION_HEIGHT) } - .divider({ - strokeWidth: 0.3, - color: $r('sys.color.icon_fourth') + .backgroundColor($r('sys.color.background_primary')) + .size({ + width: CommonConstants.X_COMPONENT_WIDTH, + height: this.curBp === 'sm' ? '30%' : this.curBp === 'md' ? '45%' : '40%' }) - .showSideBar(this.curBp === 'lg' ? true : false) - .sideBarPosition(SideBarPosition.End) - .sideBarWidth(320) - .minSideBarWidth(320) - .maxSideBarWidth(400) - .showControlButton(false) - .autoHide(false) - .onChange((value: boolean) => { - Logger.info('status:' + value); + + Scroll(this.scrollerForScroll) { + Column({ space: CommonConstants.SPACE }) { + this.AutoPip() + this.CallbackMessage() + } + .height(CommonConstants.FULL_PERCENT) + .justifyContent(FlexAlign.Start) + .width(CommonConstants.NAV_DESTINATION_WIDTH) + } + .layoutWeight(CommonConstants.SCROLL_LAY_OUT_WEIGHT) + .scrollable(ScrollDirection.Vertical) + .scrollBar(BarState.Off) + .edgeEffect(EdgeEffect.Spring) + .padding({ + right: $r('sys.float.corner_radius_level6'), + left: $r('sys.float.corner_radius_level6') }) } - .width(Constants.FULL_PERCENT) - .height(Constants.FULL_PERCENT) - .hideTitleBar(true) - .backgroundColor($r('sys.color.background_secondary')) - .onBackPressed(() => { - // Go back to the previous page and pass the result into push's onPop callback. - this.pathStack.pop(); - return true; - }) - .onReady((context: NavDestinationContext) => { - this.pathStack = context.pathStack; - }) + .width(CommonConstants.NAV_DESTINATION_WIDTH) + .height(CommonConstants.NAV_DESTINATION_HEIGHT) } - .width(Constants.FULL_PERCENT) - .height(Constants.FULL_PERCENT) + .width(CommonConstants.FULL_PERCENT) + .height(CommonConstants.FULL_PERCENT) + .hideTitleBar(true) .backgroundColor($r('sys.color.background_secondary')) + .onBackPressed(() => { + return true; + }) } } \ No newline at end of file diff --git a/windowpiplibrary/src/main/ets/pages/WindowPipPage.ets b/windowpiplibrary/src/main/ets/component/WindowPipComponent.ets similarity index 49% rename from windowpiplibrary/src/main/ets/pages/WindowPipPage.ets rename to windowpiplibrary/src/main/ets/component/WindowPipComponent.ets index 3e909fd34236c6d1576afdaa3fef2e7b5770c541..227704e9a21e67cd7f089893ce753fd5c2555fcd 100644 --- a/windowpiplibrary/src/main/ets/pages/WindowPipPage.ets +++ b/windowpiplibrary/src/main/ets/component/WindowPipComponent.ets @@ -1,52 +1,27 @@ -import { Constants } from "../constants/Constants"; -import Logger from "../utils/Logger"; -import { PlayVideo } from "./VideoPlay"; +/* + * Copyright (c) 2024 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 { VideoPlayComponent } from './VideoPlayComponent'; +import { ImageWidthTitle } from './ImageWidthTitle'; +import { CommonConstants } from '../constants/CommonConstants'; +import { BreakpointTypeEnum } from '../utils/BreakpointSystem'; @Component -struct ImageWidthTitle { - @State imageHeight: number = 0; - @Link pageInfos: NavPathStack; - private titleResource?: Resource; - - build() { - Column() { - Image($r('app.media.btn_ground')) - .width(Constants.NAV_DESTINATION_HEIGHT) - .height(this.imageHeight) - .borderRadius({ - topLeft: $r('sys.float.corner_radius_level6'), - topRight: $r('sys.float.corner_radius_level6') - }) - .objectFit(ImageFit.Cover) - .draggable(false) - Text(this.titleResource) - .fontSize($r('sys.float.Subtitle_M')) - .fontColor($r('sys.color.font_primary')) - .margin($r('sys.float.corner_radius_level4')) - } - .borderRadius($r('sys.float.corner_radius_level6')) - .backgroundColor($r('sys.color.comp_background_primary')) - .alignItems(HorizontalAlign.Start) - .onClick(() => { - getContext().eventHub.emit('onStateChange', true); - this.pageInfos?.pushPath({ name: Constants.NAV_DESTINATION_NAME }, { launchMode: 3 }); - }) - .onAreaChange((oldArea: Area, newArea: Area) => { - let width: number = newArea.width as number; - this.imageHeight = width * 9 / 16; - Logger.info(`[onAreaChange] oldArea:${oldArea} ,newArea:${newArea}`); - }) - } -} - -@Component -export struct WindowPipPage { - @StorageLink('topRectHeight') topRectHeight: number = 0; - @StorageLink('bottomRectHeight') bottomRectHeight: number = 0; - @StorageLink('currentBreakpoint') curBp: string = Constants.BREAK_POINT_SM; - @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack(); - @State curState: string = ''; +export struct WindowPipComponent { + @StorageLink(CommonConstants.KEY_PREFIX_BREAKPOINT) curBp: string = BreakpointTypeEnum.SM; + @Provide(CommonConstants.KEY_PREFIX_SYSTEM_PAGE_INFO) pageInfos: NavPathStack = new NavPathStack(); private navigationId: string = 'navId'; private videoList: Array = [ $r('app.string.video1'), $r('app.string.video2'), $r('app.string.video3'), @@ -58,11 +33,15 @@ export struct WindowPipPage { @Builder PageMap(name: string) { - if (name === Constants.NAV_DESTINATION_NAME) { - PlayVideo({ navigationId: this.navigationId }) + if (name === CommonConstants.NAV_DESTINATION_NAME) { + VideoPlayComponent({ navigationId: this.navigationId }) } } + aboutToAppear(): void { + this.getUIContext().getHostContext()!.eventHub.emit('onStateChange', true); + this.pageInfos?.pushPath({ name: CommonConstants.NAV_DESTINATION_NAME }, { launchMode: 3, animated: false }); + } build() { Navigation(this.pageInfos) { @@ -87,19 +66,19 @@ export struct WindowPipPage { } .padding({ bottom: this.videoList.length - 1 === index ? $r('sys.float.padding_level8') : - $r('sys.float.padding_level0') + $r('sys.float.padding_level0') }) }, (item: Resource) => item.id.toString()) } - .width(Constants.FULL_PERCENT) - .height(Constants.FULL_PERCENT) - .columnsTemplate(this.curBp === 'sm' ? Constants.COLUMNS_TEMPLATE_SM : - this.curBp === 'md' ? Constants.COLUMNS_TEMPLATE_MD : Constants.COLUMNS_TEMPLATE_LG) + .width(CommonConstants.FULL_PERCENT) + .layoutWeight(1) + .columnsTemplate(this.curBp === 'sm' ? CommonConstants.COLUMNS_TEMPLATE_SM : + this.curBp === 'md' ? CommonConstants.COLUMNS_TEMPLATE_MD : CommonConstants.COLUMNS_TEMPLATE_LG) .columnsGap(this.curBp === 'lg' ? $r('sys.float.padding_level8') : $r('sys.float.padding_level6')) .rowsGap(this.curBp === 'lg' ? $r('sys.float.padding_level8') : $r('sys.float.padding_level6')) .scrollBar(BarState.Off) } - .width(Constants.FULL_PERCENT) + .width(CommonConstants.FULL_PERCENT) .padding({ top: this.curBp === 'lg' ? $r('sys.float.padding_level8') : $r('sys.float.padding_level6'), right: this.curBp === 'lg' ? $r('sys.float.padding_level8') : $r('sys.float.padding_level6'), @@ -113,9 +92,7 @@ export struct WindowPipPage { .mode(NavigationMode.Stack) .hideBackButton(true) .backgroundColor($r('sys.color.background_secondary')) - .size({ width: Constants.NAV_DESTINATION_WIDTH, height: Constants.NAV_DESTINATION_HEIGHT }) + .size({ width: CommonConstants.NAV_DESTINATION_WIDTH, height: CommonConstants.NAV_DESTINATION_HEIGHT }) .id(this.navigationId) } -} - - +} \ No newline at end of file diff --git a/windowpiplibrary/src/main/ets/constants/Constants.ets b/windowpiplibrary/src/main/ets/constants/CommonConstants.ets similarity index 48% rename from windowpiplibrary/src/main/ets/constants/Constants.ets rename to windowpiplibrary/src/main/ets/constants/CommonConstants.ets index 2b3a9bb82ef47e49b482ec9b5cbca6050a44c520..9569d461471a8dc90b49768edd19503a5e7731a6 100644 --- a/windowpiplibrary/src/main/ets/constants/Constants.ets +++ b/windowpiplibrary/src/main/ets/constants/CommonConstants.ets @@ -13,91 +13,128 @@ * limitations under the License. */ -export class Constants { +export class CommonConstants { /** - * NavDestination page name. + * Full percent. */ - public static readonly NAV_DESTINATION_NAME: string = 'PlayVideo'; + public static readonly FULL_PERCENT: string = '100%'; + /** - * Control width. + * None percent. */ - public static readonly CONTROL_WIDTH: string = '95%'; + public static readonly NONE_PERCENT: string = '0'; + /** - * NavDestination width. + * Swiper initially currentIndex. */ - public static readonly NAV_DESTINATION_WIDTH: string = '100%'; + public static readonly INITIALLY_CURRENT_INDEX: number = -1; + /** - * avDestination height. + * Swiper slide index. */ - public static readonly NAV_DESTINATION_HEIGHT: string = '100%'; + public static readonly SLIDE_INDEX: number = -1; + /** - * The hundred percent of the components + * Swiper image duration. */ - public static readonly FULL_PERCENT: string = '100%'; + public static readonly IMAGE_DURATION: number = 300; + /** - * XComponent width. + * Swiper duration. */ - public static readonly X_COMPONENT_WIDTH: string = '100%'; + public static readonly DURATION: number = 3000; + /** - * Scroll layout width. + * Swiper interval. */ - public static readonly SCROLL_LAY_OUT_WEIGHT: number = 1; + public static readonly INTERVAL: number = 3000; + /** - * Default error information. + * Swiper item space. */ - public static readonly ERROR_BY_DEFAULT: string = '无'; + public static readonly ITEM_SPACE: number = 0; + /** - * Layout Element Spacing. + * Swiper cached count. */ - public static readonly SPACE: number = 24; + public static readonly SWIPER_CACHED_COUNT: number = 2; + /** - * Error type. + * Progress wrap height. */ - public static readonly AVPLAYER_TYPE: number = 1; + public static readonly PROGRESS_WRAP_HEIGHT: number = 50; + + /** + * zIndex. + */ + public static readonly Z_INDEX_0: number = 0; + + /** + * zIndex. + */ + public static readonly Z_INDEX_1: number = 1; + /** - * Idle state. + * zIndex. */ - public static readonly IDLE_STATUS: string = 'idle'; + public static readonly Z_INDEX_2: number = 2; + /** - * Resource Initialization. + * Layout weight. */ - public static readonly INITIALIZED_STATUS: string = 'initialized'; + public static readonly LAYOUT_WEIGHT: number = 1; + /** - * Prepared state. + * Row space. */ - public static readonly PREPARED_STATUS: string = 'prepared'; + public static readonly ROW_SPACE: number = 5; + /** - * Playing status. + * Column space. */ - public static readonly PLAYING_STATUS: string = 'playing'; + public static readonly COLUMN_SPACE: number = 16; + + /** + * Column space inside. + */ + public static readonly COLUMN_SPACE_INSIDE: number = 8; + + /** + * NavDestination page name. + */ + public static readonly NAV_DESTINATION_NAME: string = 'PlayVideo'; + /** + * Control width. + */ + public static readonly CONTROL_WIDTH: string = '95%'; /** - * Paused status. + * NavDestination width. */ - public static readonly PAUSED_STATUS: string = 'paused'; + public static readonly NAV_DESTINATION_WIDTH: string = '100%'; /** - * Play to end state. + * avDestination height. */ - public static readonly COMPLETED_STATUS: string = 'completed'; + public static readonly NAV_DESTINATION_HEIGHT: string = '100%'; /** - * Stopped status. + * XComponent width. */ - public static readonly STOPPED_STATUS: string = 'stopped'; + public static readonly X_COMPONENT_WIDTH: string = '100%'; /** - * Destruction Status. + * Scroll layout width. */ - public static readonly RELEASED_STATUS: string = 'released'; + public static readonly SCROLL_LAY_OUT_WEIGHT: number = 1; /** - * Breakpoint sm. + * Default error information. */ - public static readonly BREAK_POINT_SM: string = 'sm'; + public static readonly ERROR_BY_DEFAULT: string = '无'; /** - * Breakpoint md. + * Layout Element Spacing. */ - public static readonly BREAK_POINT_MD: string = 'md'; + public static readonly SPACE: number = 24; /** - * Breakpoint lg. + * Error type. */ - public static readonly BREAK_POINT_LG: string = 'lg'; + public static readonly AVPLAYER_TYPE: number = 1; /** * ColumnsTemplate sm. */ @@ -110,4 +147,15 @@ export class Constants { * ColumnsTemplate lg. */ public static readonly COLUMNS_TEMPLATE_LG: string = '1fr 1fr 1fr 1fr 1fr'; -} \ No newline at end of file + + /** + * AppStorage key prefix. + */ + public static readonly KEY_PREFIX: string = 'WindowPip'; + public static readonly KEY_PREFIX_BREAKPOINT: string = CommonConstants.KEY_PREFIX + 'WindowPipCurrentBreakpoint'; + public static readonly KEY_PREFIX_NAVIGATOR_BAR_HEIGHT: string = CommonConstants.KEY_PREFIX + 'WindowPipNavigatorBarHeight'; + public static readonly KEY_PREFIX_STATUS_BAR_HEIGHT: string = CommonConstants.KEY_PREFIX + 'WindowPipStatusBarHeight'; + public static readonly KEY_PREFIX_SYSTEM_COLOR_MODE: string = CommonConstants.KEY_PREFIX + 'WindowPipSystemColorMode'; + public static readonly KEY_PREFIX_SYSTEM_UICONTEXT: string = CommonConstants.KEY_PREFIX + 'WindowPipUIContext'; + public static readonly KEY_PREFIX_SYSTEM_PAGE_INFO: string = CommonConstants.KEY_PREFIX + 'WindowPipPageInfos'; +} diff --git a/windowpiplibrary/src/main/ets/pages/AVPlayer.ets b/windowpiplibrary/src/main/ets/player/AVPlayer.ets similarity index 82% rename from windowpiplibrary/src/main/ets/pages/AVPlayer.ets rename to windowpiplibrary/src/main/ets/player/AVPlayer.ets index f9b537452b3f7cb10ed43890bdfc67f6de43adf3..5aadbe24b0587940d6c0d422e36f1df9ec9a38eb 100644 --- a/windowpiplibrary/src/main/ets/pages/AVPlayer.ets +++ b/windowpiplibrary/src/main/ets/player/AVPlayer.ets @@ -17,7 +17,6 @@ import { common } from '@kit.AbilityKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { resourceManager } from '@kit.LocalizationKit'; import { media } from '@kit.MediaKit'; -import { Constants } from '../constants/Constants'; import Logger from '../utils/Logger'; export class AVPlayer { @@ -29,17 +28,19 @@ export class AVPlayer { public type: number = 0; private state: string = ''; private playStatus: boolean = true; + private context: Context; - constructor(surfaceID: string, type: number) { + constructor(surfaceID: string, type: number, context: Context) { this.surfaceID = surfaceID; this.type = type; - getContext().eventHub.on('appStateChange', (fg: boolean) => { + this.context = context; + this.context.eventHub.on('appStateChange', (fg: boolean) => { if (fg) { - if (this.state === Constants.PAUSED_STATUS) { + if (this.state === 'paused') { this.avPlayer?.play(); } } else { - if (this.state === Constants.PLAYING_STATUS) { + if (this.state === 'playing') { this.avPlayer?.pause(); } } @@ -71,20 +72,19 @@ export class AVPlayer { this.state = state; switch (state) { // After the RESET API is successfully called, the state machine is triggered. - case Constants.IDLE_STATUS: + case 'idle': Logger.info('AVPlayer state idle called.'); if (!this.jumpNext) { // Call the release operation to destroy the instance object. this.avPlayer?.release(); } else { - let context = getContext(this) as common.UIAbilityContext; - let fileDescriptor: resourceManager.RawFileDescriptor; - fileDescriptor = await context.resourceManager.getRawFd('video.mov'); + const context = this.context as common.UIAbilityContext; + const fileDescriptor: resourceManager.RawFileDescriptor = await context.resourceManager.getRawFd('video.mp4'); this.avPlayer.fdSrc = fileDescriptor; } break; // After avplayer sets the playback source, this status is reported. - case Constants.INITIALIZED_STATUS: + case 'initialized': Logger.info('AVPlayer state initialized called.'); // You don't need to set the display screen when the playback asset is audio-only. this.avPlayer.surfaceId = this.surfaceID; @@ -95,7 +95,7 @@ export class AVPlayer { }); break; // After the prepare call is successful, the state machine is reported. - case Constants.PREPARED_STATUS: + case 'prepared': Logger.info('AVPlayer state prepared called.'); // Call the playback API to start playback. if (this.playStatus) { @@ -103,27 +103,27 @@ export class AVPlayer { } break; // After the play is successfully invoked, the state machine is triggered. - case Constants.PLAYING_STATUS: + case 'playing': Logger.info('AVPlayer state playing called.'); this.jumpNext = false; break; // After pause is successfully invoked, the state machine is triggered. - case Constants.PAUSED_STATUS: + case 'paused': Logger.info('AVPlayer state paused called.'); break; // After the playback ends, the state machine is triggered. - case Constants.COMPLETED_STATUS: + case 'completed': Logger.info('AVPlayer state completed called.'); // Call the playback end API. this.playNext(); break; // After the stop API is successfully called, the state machine is triggered. - case Constants.STOPPED_STATUS: + case 'stopped': Logger.info('AVPlayer state stopped called.'); // Call the reset operation to initialize the avplayer state. this.avPlayer.reset(); break; - case Constants.RELEASED_STATUS: + case 'released': Logger.info('AVPlayer state released called.'); this.avPlayer.release(); break; @@ -133,7 +133,7 @@ export class AVPlayer { } }); this.avPlayer?.on('videoSizeChange', (width: number, height: number) => { - getContext().eventHub.emit('videoSizeRatio', width, height); + this.context.eventHub.emit('videoSizeRatio', width, height); }) } @@ -146,8 +146,8 @@ export class AVPlayer { this.avPlayer = await media.createAVPlayer(); // Create a callback function for state machine changes. this.setAVPlayerCallback(); - let context = getContext(this) as common.UIAbilityContext; - let fileDescriptor = await context.resourceManager.getRawFd('video.mov'); + const context = this.context as common.UIAbilityContext; + const fileDescriptor = await context.resourceManager.getRawFd('video.mp4'); // Assign a value to fdSrc to trigger an initialized state machine report. this.avPlayer.fdSrc = fileDescriptor; } @@ -161,14 +161,14 @@ export class AVPlayer { } play(): void { - if ((this.state === Constants.PAUSED_STATUS || this.state === Constants.PREPARED_STATUS) && + if ((this.state === 'paused' || this.state === 'prepared') && this.playStatus === true) { this.avPlayer?.play(); } } pause(): void { - if (this.state === Constants.PLAYING_STATUS) { + if (this.state === 'playing') { this.avPlayer?.pause(); } } diff --git a/windowpiplibrary/src/main/ets/utils/BreakpointSystem.ets b/windowpiplibrary/src/main/ets/utils/BreakpointSystem.ets index aa7581b2047323eac83c8d9a031e21faabc55bd2..fc714de8bbed9a5962588691f65d6cd0617113de 100644 --- a/windowpiplibrary/src/main/ets/utils/BreakpointSystem.ets +++ b/windowpiplibrary/src/main/ets/utils/BreakpointSystem.ets @@ -16,6 +16,7 @@ import { window } from '@kit.ArkUI'; import type { BusinessError } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; +import { CommonConstants } from '../constants/CommonConstants'; const TAG: string = '[BreakpointSystem]'; @@ -67,9 +68,11 @@ export class BreakpointType { } } + export class BreakpointSystem { private static instance: BreakpointSystem; private currentBreakpoint: BreakpointTypeEnum = BreakpointTypeEnum.MD; + private uiContext: UIContext = AppStorage.get(CommonConstants.KEY_PREFIX_BREAKPOINT) as UIContext; private constructor() { } @@ -82,10 +85,8 @@ export class BreakpointSystem { } public updateCurrentBreakpoint(breakpoint: BreakpointTypeEnum): void { - if (this.currentBreakpoint !== breakpoint) { - this.currentBreakpoint = breakpoint; - AppStorage.setOrCreate('currentBreakpoint', this.currentBreakpoint); - } + this.currentBreakpoint = breakpoint; + AppStorage.setOrCreate(CommonConstants.KEY_PREFIX_BREAKPOINT, this.currentBreakpoint); } public onWindowSizeChange(window: window.Window): void { @@ -96,7 +97,7 @@ export class BreakpointSystem { try { const mainWindow: window.WindowProperties = window.getWindowProperties(); const windowWidth: number = mainWindow.windowRect.width; - const windowWidthVp = px2vp(windowWidth); + const windowWidthVp = this.uiContext.px2vp(windowWidth); let widthBp: BreakpointTypeEnum = BreakpointTypeEnum.MD; if (windowWidthVp < 320) { widthBp = BreakpointTypeEnum.XS; diff --git a/windowpiplibrary/src/main/ets/utils/WindowUtil.ets b/windowpiplibrary/src/main/ets/utils/WindowUtil.ets index e059b5d42a30b23c32d1a60fc6c899fb809a72d2..65a9a52f86aab8119d7cce4e1712f6b8d2db8aa7 100644 --- a/windowpiplibrary/src/main/ets/utils/WindowUtil.ets +++ b/windowpiplibrary/src/main/ets/utils/WindowUtil.ets @@ -15,17 +15,37 @@ import { window } from '@kit.ArkUI'; import type { BusinessError } from '@kit.BasicServicesKit'; -import { BreakpointSystem } from './BreakpointSystem'; import { hilog } from '@kit.PerformanceAnalysisKit'; +import { common, ConfigurationConstant } from '@kit.AbilityKit'; +import { CommonConstants } from '../constants/CommonConstants'; +import { BreakpointSystem } from './BreakpointSystem'; const TAG: string = '[WindowUtil]'; export class WindowUtil { + private static windowClass?: window.Window; + private static uiContext: UIContext; + + public static initialize(windowStage: window.WindowStage) { + try { + WindowUtil.windowClass = windowStage.getMainWindowSync(); + const uiContext: UIContext = WindowUtil.windowClass.getUIContext(); + WindowUtil.uiContext = uiContext; + AppStorage.setOrCreate(CommonConstants.KEY_PREFIX_SYSTEM_UICONTEXT, uiContext); + WindowUtil.registerBreakPoint(windowStage); + WindowUtil.requestFullScreen(windowStage); + } catch (err) { + hilog.error(0x0000, TAG, `WindowUtil initialize failed. Cause: ${err.code} ${err.message}`); + } + } + public static requestFullScreen(windowStage: window.WindowStage): void { windowStage.getMainWindow((err: BusinessError, data: window.Window) => { if (err.code) { return; } + let sysBarProps: window.SystemBarProperties = { statusBarContentColor: '#FFFFFF' }; + data.setWindowSystemBarProperties(sysBarProps); const windowClass: window.Window = data; // Realize the immersive effect. try { @@ -33,11 +53,11 @@ export class WindowUtil { promise.then(() => { hilog.info(0x0000, TAG, 'Succeeded in setting the window layout to full-screen mode.'); }).catch((err: BusinessError) => { - hilog.info(0x0000, TAG, + hilog.error(0x0000, TAG, `Failed to set the window layout to full-screen mode. Cause: ${err.code}, ${err.message}`); }); } catch { - hilog.error(0x0000, TAG, 'Failed to set the window layout to full-screen mode. '); + hilog.error(0x0000, TAG, 'Failed to set the window layout to full-screen mode.'); } }); } @@ -49,8 +69,15 @@ export class WindowUtil { return; } BreakpointSystem.getInstance().updateWidthBp(data); + let avoidArea = data.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR); + AppStorage.setOrCreate(CommonConstants.KEY_PREFIX_NAVIGATOR_BAR_HEIGHT, + WindowUtil.uiContext.px2vp(avoidArea.bottomRect.height)); + avoidArea = data.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); + AppStorage.setOrCreate(CommonConstants.KEY_PREFIX_STATUS_BAR_HEIGHT, + WindowUtil.uiContext.px2vp(avoidArea.topRect.height)); data.on('windowSizeChange', () => BreakpointSystem.getInstance().onWindowSizeChange(data)); data.on('avoidAreaChange', (avoidAreaOption) => { + WindowUtil.setAvoidArea(avoidAreaOption.type, avoidAreaOption.area); if (avoidAreaOption.type === window.AvoidAreaType.TYPE_SYSTEM || avoidAreaOption.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) { WindowUtil.setAvoidArea(avoidAreaOption.type, avoidAreaOption.area); @@ -62,9 +89,15 @@ export class WindowUtil { // Get status bar height and indicator height. public static setAvoidArea(type: window.AvoidAreaType, area: window.AvoidArea) { if (type === window.AvoidAreaType.TYPE_SYSTEM) { - AppStorage.setOrCreate('topRectHeight', px2vp(area.topRect.height)); + AppStorage.setOrCreate(CommonConstants.KEY_PREFIX_STATUS_BAR_HEIGHT, + WindowUtil.uiContext.px2vp(area.topRect.height)); } else { - AppStorage.setOrCreate('bottomRectHeight', px2vp(area.bottomRect.height)); + AppStorage.setOrCreate(CommonConstants.KEY_PREFIX_NAVIGATOR_BAR_HEIGHT, + WindowUtil.uiContext.px2vp(area.bottomRect.height)); } } + + public static updatedColorMode(context: common.UIAbilityContext): void { + context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + } } \ No newline at end of file diff --git a/windowpiplibrary/src/main/resources/base/element/color.json b/windowpiplibrary/src/main/resources/base/element/color.json index 0741552588f758da0a8c8cbf4405817087ed5765..a62281ace6ac5a0b981cf5b71675d4331055e847 100644 --- a/windowpiplibrary/src/main/resources/base/element/color.json +++ b/windowpiplibrary/src/main/resources/base/element/color.json @@ -1,9 +1,5 @@ { "color": [ - { - "name": "start_window_background", - "value": "#FFFFFF" - }, { "name": "video_background_dark", "value": "#1a1a1a" diff --git a/windowpiplibrary/src/main/resources/base/element/string.json b/windowpiplibrary/src/main/resources/base/element/string.json index 272977c561fbec97d0b0270cae813a97f34e9e2b..6c409f3924a08791c1be34fed74ccb12fc060af0 100644 --- a/windowpiplibrary/src/main/resources/base/element/string.json +++ b/windowpiplibrary/src/main/resources/base/element/string.json @@ -1,17 +1,5 @@ { "string": [ - { - "name": "module_desc", - "value": "module description" - }, - { - "name": "EntryAbility_desc", - "value": "description" - }, - { - "name": "EntryAbility_label", - "value": "WindowPiP" - }, { "name": "video1", "value": "Video1" @@ -99,6 +87,10 @@ { "name": "current_error_hint", "value": "Without" + }, + { + "name": "notsupport", + "value": "PC Does Not Support Picture-in-picture" } ] } \ No newline at end of file diff --git a/windowpiplibrary/src/main/resources/en_US/element/string.json b/windowpiplibrary/src/main/resources/en_US/element/string.json index 272977c561fbec97d0b0270cae813a97f34e9e2b..2f6a2eb8ead0123459f6cfffa448cf32181ea50d 100644 --- a/windowpiplibrary/src/main/resources/en_US/element/string.json +++ b/windowpiplibrary/src/main/resources/en_US/element/string.json @@ -1,17 +1,5 @@ { "string": [ - { - "name": "module_desc", - "value": "module description" - }, - { - "name": "EntryAbility_desc", - "value": "description" - }, - { - "name": "EntryAbility_label", - "value": "WindowPiP" - }, { "name": "video1", "value": "Video1" diff --git a/windowpiplibrary/src/main/resources/rawfile/video.mov b/windowpiplibrary/src/main/resources/rawfile/video.mov deleted file mode 100644 index 68c87f00df82a782c34695c9ee403995a16d5274..0000000000000000000000000000000000000000 Binary files a/windowpiplibrary/src/main/resources/rawfile/video.mov and /dev/null differ diff --git a/windowpiplibrary/src/main/resources/rawfile/video.mp4 b/windowpiplibrary/src/main/resources/rawfile/video.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..c0f7b4c9d463e652a74568dfe64a7ef60b37af33 Binary files /dev/null and b/windowpiplibrary/src/main/resources/rawfile/video.mp4 differ diff --git a/windowpiplibrary/src/main/resources/zh_CN/element/string.json b/windowpiplibrary/src/main/resources/zh_CN/element/string.json index a06655a089fa5e4a46347466478ca8349dda3c31..02776658a00f176cf796474a673df0d2995811bb 100644 --- a/windowpiplibrary/src/main/resources/zh_CN/element/string.json +++ b/windowpiplibrary/src/main/resources/zh_CN/element/string.json @@ -1,17 +1,5 @@ { "string": [ - { - "name": "module_desc", - "value": "模块描述" - }, - { - "name": "EntryAbility_desc", - "value": "description" - }, - { - "name": "EntryAbility_label", - "value": "WindowPiP" - }, { "name": "video1", "value": "视频1" @@ -99,6 +87,10 @@ { "name": "current_error_hint", "value": "无" + }, + { + "name": "notsupport", + "value": "PC暂时不支持画中画" } ] } \ No newline at end of file diff --git a/windowpipsample/src/main/ets/entryability/EntryAbility.ets b/windowpipsample/src/main/ets/entryability/EntryAbility.ets index 2e837e54f4bc1ab0d66cc7aaad1dc24ef596f2c5..76c02c310773957eee0a4ee07c2964ef8c78a0fd 100644 --- a/windowpipsample/src/main/ets/entryability/EntryAbility.ets +++ b/windowpipsample/src/main/ets/entryability/EntryAbility.ets @@ -13,11 +13,12 @@ * limitations under the License. */ -import { Configuration, ConfigurationConstant, UIAbility } from '@kit.AbilityKit'; -import { display, window } from '@kit.ArkUI'; +import { UIAbility } from '@kit.AbilityKit'; +import { window } from '@kit.ArkUI'; import { BusinessError } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; -import { WindowUtil } from 'windowpiplibrary'; +import { WindowPipController } from 'windowpiplibrary'; + const TAG: string = '[EntryAbility]'; @@ -25,17 +26,7 @@ export default class EntryAbility extends UIAbility { onCreate(): void { hilog.info(0x0000, TAG, '%{public}s', 'Ability onCreate'); - AppStorage.setOrCreate('systemColorMode', this.context.config.colorMode); - this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); - } - - onConfigurationUpdate(newConfig: Configuration): void { - let newColorMode: ConfigurationConstant.ColorMode = - newConfig.colorMode || ConfigurationConstant.ColorMode.COLOR_MODE_DARK; - let currentColorMode = AppStorage.get('systemColorMode'); - if (newColorMode !== currentColorMode) { - AppStorage.setOrCreate('systemColorMode', newColorMode); - } + WindowPipController.updatedColorMode(this.context); } onDestroy(): void { @@ -43,8 +34,6 @@ export default class EntryAbility extends UIAbility { } onWindowStageCreate(windowStage: window.WindowStage): void { - WindowUtil.requestFullScreen(windowStage) - WindowUtil.registerBreakPoint(windowStage) // Main window is created, set main page for this ability hilog.info(0x0000, TAG, '%{public}s', 'Ability onWindowStageCreate'); windowStage.loadContent('pages/Index', (error: BusinessError) => { @@ -53,6 +42,7 @@ export default class EntryAbility extends UIAbility { `Failed to load the content. code: ${error.code}, message: ${error.message}`); return; } + WindowPipController.initWindowConfig(windowStage); hilog.info(0x0000, TAG, '%{public}s', 'Succeeded in loading the content.'); }); } diff --git a/windowpipsample/src/main/ets/pages/Index.ets b/windowpipsample/src/main/ets/pages/Index.ets index 6e6da7a60b0eb40dfbd48823260519a0b5a8bef8..559777bfec862034b2febba5b02b636829dcba44 100644 --- a/windowpipsample/src/main/ets/pages/Index.ets +++ b/windowpipsample/src/main/ets/pages/Index.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { WindowPipPage } from 'windowpiplibrary'; +import { WindowPipComponent } from 'windowpiplibrary'; @Entry @@ -21,7 +21,7 @@ import { WindowPipPage } from 'windowpiplibrary'; struct WindowPip { build() { Stack() { - WindowPipPage() + WindowPipComponent() } } } \ No newline at end of file diff --git a/windowpipsample/src/main/module.json5 b/windowpipsample/src/main/module.json5 index 88610f26d828e2e2178352766c77120608405bce..837b5249c1ad8a9d25d1f7395fcfcce8374d3f41 100644 --- a/windowpipsample/src/main/module.json5 +++ b/windowpipsample/src/main/module.json5 @@ -9,7 +9,7 @@ "tablet", "2in1" ], - "deliveryWithInstall": true, + "deliveryWithInstall": false, "installationFree": false, "pages": "$profile:main_pages", "abilities": [ diff --git a/windowpipsample/src/main/resources/base/element/color.json b/windowpipsample/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/windowpipsample/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/windowpipsample/src/main/resources/base/element/string.json b/windowpipsample/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..9847ef6fc3fd1845119d6936583fc75c08ef277d --- /dev/null +++ b/windowpipsample/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "WindowPiP" + } + ] +} \ No newline at end of file diff --git a/windowpiplibrary/src/main/resources/base/media/background.png b/windowpipsample/src/main/resources/base/media/background.png similarity index 100% rename from windowpiplibrary/src/main/resources/base/media/background.png rename to windowpipsample/src/main/resources/base/media/background.png diff --git a/windowpiplibrary/src/main/resources/base/media/foreground.png b/windowpipsample/src/main/resources/base/media/foreground.png similarity index 100% rename from windowpiplibrary/src/main/resources/base/media/foreground.png rename to windowpipsample/src/main/resources/base/media/foreground.png diff --git a/windowpiplibrary/src/main/resources/base/media/layered_image.json b/windowpipsample/src/main/resources/base/media/layered_image.json similarity index 100% rename from windowpiplibrary/src/main/resources/base/media/layered_image.json rename to windowpipsample/src/main/resources/base/media/layered_image.json diff --git a/windowpiplibrary/src/main/resources/base/media/startIcon.png b/windowpipsample/src/main/resources/base/media/startIcon.png similarity index 100% rename from windowpiplibrary/src/main/resources/base/media/startIcon.png rename to windowpipsample/src/main/resources/base/media/startIcon.png diff --git a/windowpipsample/src/main/resources/en_US/element/string.json b/windowpipsample/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..9847ef6fc3fd1845119d6936583fc75c08ef277d --- /dev/null +++ b/windowpipsample/src/main/resources/en_US/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "WindowPiP" + } + ] +} \ No newline at end of file diff --git a/windowpipsample/src/main/resources/zh_CN/element/string.json b/windowpipsample/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..0a7a5230585632efca293d650adc749092a0edb6 --- /dev/null +++ b/windowpipsample/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "WindowPiP" + } + ] +} \ No newline at end of file