diff --git a/README.en.md b/README.en.md index 4b2c4e14fcfbc928ef651a8887ccde24b39a5f60..6e60f3bd274ce0eae3021c878ef0a33e9464b9a8 100644 --- a/README.en.md +++ b/README.en.md @@ -53,7 +53,10 @@ N/A ## Constraints -1. The sample app is supported only on Huawei phones running the standard system. -2. The HarmonyOS version must be HarmonyOS NEXT Developer Beta1 or later. -3. The DevEco Studio version must be DevEco Studio NEXT Developer Beta1 or later. -4. The HarmonyOS SDK version must be HarmonyOS NEXT Developer Beta1 or later. +1. The sample is only supported on Huawei phones with standard systems. + +2. The HarmonyOS version must be HarmonyOS 5.0.0 Release or later. + +3. The DevEco Studio version must be DevEco Studio 5.0.0 Release or later. + +4. The HarmonyOS SDK version must be HarmonyOS 5.0.0 Release SDK or later. diff --git a/README.md b/README.md index 2c9e87804fd6a68d0b9ce745f342668b1d1f9f32..2c3c79a3f52ca0ed0c2894e29f3a40d6db33aa5e 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,10 @@ ## 约束与限制 -1. 本示例仅支持标准系统上运行,支持设备:华为手机。 -2. HarmonyOS系统:HarmonyOS NEXT Developer Beta1及以上。 -3. DevEco Studio版本:DevEco Studio NEXT Developer Beta1及以上。 -4. HarmonyOS SDK版本:HarmonyOS NEXT Developer Beta1 SDK及以上。 \ No newline at end of file +1. 本示例仅支持标准系统上运行,支持设备:phone,tablet,2in1。 + +2. HarmonyOS系统:HarmonyOS 5.0.0 Release及以上。 + +3. DevEco Studio版本:DevEco Studio 5.0.0 Release及以上。 + +4. HarmonyOS SDK版本:HarmonyOS 5.0.0 Release SDK及以上。 \ No newline at end of file diff --git a/entry/build-profile.json5 b/entry/build-profile.json5 index b695582d3680556f4cce2ec518f65720a9413ca3..808380f3b726e2036a3d6cf5fb9b0fd9513a8215 100644 --- a/entry/build-profile.json5 +++ b/entry/build-profile.json5 @@ -20,9 +20,6 @@ "targets": [ { "name": "default" - }, - { - "name": "ohosTest", } ] } \ No newline at end of file diff --git a/entry/obfuscation-rules.txt b/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..a1dfa0bd175984dc49e641436aa67b1de1b8abeb --- /dev/null +++ b/entry/obfuscation-rules.txt @@ -0,0 +1,22 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/entry/src/main/ets/constants/Constants.ets b/entry/src/main/ets/constants/Constants.ets index 79be196281a3d2841e2739d8f8d39054c698af25..f7dc11847f84263f33862078bbb4d46c4f0a6acd 100644 --- a/entry/src/main/ets/constants/Constants.ets +++ b/entry/src/main/ets/constants/Constants.ets @@ -34,6 +34,11 @@ export class Constants { */ public static readonly NAV_DESTINATION_HEIGHT: string = '100%'; + /** + * The hundred percent of the components + */ + static readonly FULL_PERCENT: string = '100%'; + /** * Video1 button width. */ @@ -67,7 +72,7 @@ export class Constants { /** * Layout Element Spacing. */ - public static readonly SPACE: number = 20; + public static readonly SPACE: number = 24; /** * HomePage Element Spacing. @@ -80,14 +85,34 @@ export class Constants { public static readonly AVPLAYER_TYPE: number = 1; /** - * GridRow columns. + * GridRow columns sm. + */ + public static readonly GRID_COLUMNS_SM: number = 2; + + /** + * GridRow columns md. + */ + public static readonly GRID_COLUMNS_MD: number = 3; + + /** + * GridRow columns lg. */ - public static readonly GRID_ROW_COLUMNS: number = 2; + public static readonly GRID_COLUMNS_LG: number = 4; /** - * GridRow gutter x. + * GridRow gutter sm. */ - public static readonly GRID_ROW_X: number = 10; + public static readonly GRID_ROW_SM: number = 8; + + /** + * GridRow gutter md. + */ + public static readonly GRID_ROW_MD: number = 12; + + /** + * GridRow gutter lg. + */ + public static readonly GRID_ROW_lg: number = 16; /** * GridRow gutter y. @@ -138,4 +163,34 @@ export class Constants { * Destruction Status. */ public static readonly RELEASED_STATUS: string = 'released'; + + /** + * Breakpoint sm. + */ + static readonly BREAK_POINT_SM: string = 'sm'; + + /** + * Breakpoint md. + */ + static readonly BREAK_POINT_MD: string = 'md'; + + /** + * Breakpoint lg. + */ + static readonly BREAK_POINT_LG: string = 'lg'; + + /** + * ColumnsTemplate sm. + */ + static readonly COLUMNS_TEMPLATE_SM: string = '1fr 1fr'; + + /** + * ColumnsTemplate md. + */ + static readonly COLUMNS_TEMPLATE_MD: string = '1fr 1fr 1fr'; + + /** + * ColumnsTemplate lg. + */ + static readonly COLUMNS_TEMPLATE_LG: string = '1fr 1fr 1fr 1fr 1fr'; } \ No newline at end of file diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets index 26f7915ba58cb086f4cba8138761aa8ade2fc4f3..45a6302ce6af2d6ede1ba7b3dca3b27c4313a192 100644 --- a/entry/src/main/ets/entryability/EntryAbility.ets +++ b/entry/src/main/ets/entryability/EntryAbility.ets @@ -13,13 +13,46 @@ * limitations under the License. */ -import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { Configuration, ConfigurationConstant, UIAbility } from '@kit.AbilityKit'; +import { resourceManager } from '@kit.LocalizationKit'; +import { BusinessError } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; -import { window } from '@kit.ArkUI'; +import { display, window } from '@kit.ArkUI'; +import Logger from '../utils/Logger'; export default class EntryAbility extends UIAbility { - onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + private windowObj?: window.Window; + private curBp: string = ''; + + private updateBreakpoint(windowWidth: number): void { + let windowWidthVp = windowWidth / display.getDefaultDisplaySync().densityPixels; + let newBp: string = ''; + if (windowWidthVp < 600) { + newBp = 'sm'; + } else if (windowWidthVp < 840) { + newBp = 'md'; + } else { + newBp = 'lg'; + } + if (this.curBp !== newBp) { + this.curBp = newBp; + AppStorage.setOrCreate('currentBreakpoint', this.curBp); + } + } + + onCreate(): void { hilog.info(0x0000, 'testTag', '%{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); + } } onDestroy(): void { @@ -27,15 +60,40 @@ export default class EntryAbility extends UIAbility { } onWindowStageCreate(windowStage: window.WindowStage): void { + windowStage.getMainWindow().then((windowObj: window.Window) => { + let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; + let avoidArea = windowObj.getWindowAvoidArea(type); + let bottomRectHeight = avoidArea.bottomRect.height; + AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight); + type = window.AvoidAreaType.TYPE_SYSTEM; + avoidArea = windowObj.getWindowAvoidArea(type); + let topRectHeight = avoidArea.topRect.height; + AppStorage.setOrCreate('topRectHeight', topRectHeight); + this.windowObj = windowObj; + this.updateBreakpoint(windowObj.getWindowProperties().windowRect.width); + windowObj.on('windowSizeChange', (windowSize) => { + this.updateBreakpoint(windowSize.width); + }) + }); // Main window is created, set main page for this ability hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); - - windowStage.loadContent('pages/WindowPip', (err) => { + let context = this.context; + let resourceManager: resourceManager.ResourceManager = context.resourceManager; + AppStorage.setOrCreate('resourceManager', resourceManager); + windowStage.loadContent('pages/WindowPip', (err, data) => { if (err.code) { hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); return; } - hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); + let windowClass: window.Window = windowStage.getMainWindowSync(); + AppStorage.setOrCreate('windowClass', windowClass); + let isLayoutFullScreen = true; + windowClass.setWindowLayoutFullScreen(isLayoutFullScreen).then(() => { + Logger.info('Succeeded in setting the window layout to full-screen mode.'); + }).catch((err: BusinessError) => { + Logger.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err)); + }); }); } diff --git a/entry/src/main/ets/pages/AVPlayer.ets b/entry/src/main/ets/pages/AVPlayer.ets index 9745417fbc442eadf0d04b97d18749cd5fc64d97..93729199ec5d9a1f4149dd9e9a4e5bd022c857d8 100644 --- a/entry/src/main/ets/pages/AVPlayer.ets +++ b/entry/src/main/ets/pages/AVPlayer.ets @@ -46,12 +46,12 @@ export class AVPlayer { }); } - updatePlayStatus(status: boolean) { + updatePlayStatus(status: boolean): void { this.playStatus = status; } // Register the avplayer callback function. - setAVPlayerCallback() { + setAVPlayerCallback(): void { // Callback function for seek operation result. this.avPlayer?.on('seekDone', (seekDoneTime: number) => { Logger.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`); @@ -70,7 +70,7 @@ export class AVPlayer { } this.State = state; switch (state) { - // After the RESET API is successfully called, the state machine is triggered. + // After the RESET API is successfully called, the state machine is triggered. case Constants.idle_STATUS: Logger.info('AVPlayer state idle called.'); if (!this.jumpNext) { @@ -79,7 +79,7 @@ export class AVPlayer { } else { let context = getContext(this) as common.UIAbilityContext; let fileDescriptor: resourceManager.RawFileDescriptor; - fileDescriptor = await context.resourceManager.getRawFd('video.mp4'); + fileDescriptor = await context.resourceManager.getRawFd('video.mov'); this.avPlayer.fdSrc = fileDescriptor; } break; @@ -141,18 +141,18 @@ export class AVPlayer { * The following demo shows how to use the Resource Management API to obtain a media resource file packaged in HAP * and use the fdSrc attribute to play back. */ - async avPlayerFdSrc() { + async avPlayerFdSrc(): Promise { // Create an avPlayer instance object. 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.mp4'); + let fileDescriptor = await context.resourceManager.getRawFd('video.mov'); // Assign a value to fdSrc to trigger an initialized state machine report. this.avPlayer.fdSrc = fileDescriptor; } - async playNext() { + async playNext(): Promise { if (this.avPlayer === null) { return; } @@ -160,19 +160,20 @@ export class AVPlayer { this.avPlayer?.stop(); } - play() { - if ((this.State === Constants.PAUSED_STATUS || this.State === Constants.PREPARED_STATUS) && this.playStatus === true) { + play(): void { + if ((this.State === Constants.PAUSED_STATUS || this.State === Constants.PREPARED_STATUS) && + this.playStatus === true) { this.avPlayer?.play(); } } - pause() { + pause(): void { if (this.State === Constants.PLAYING_STATUS) { this.avPlayer?.pause(); } } - stopAvPlayer() { + stopAvPlayer(): void { if (!this.avPlayer) { return; } diff --git a/entry/src/main/ets/pages/VideoPlay.ets b/entry/src/main/ets/pages/VideoPlay.ets index 302da590213c0c0bb18d3adbc873d3e592a3f874..213fcd9298a0c7306aa940c5cbc42fb30c611254 100644 --- a/entry/src/main/ets/pages/VideoPlay.ets +++ b/entry/src/main/ets/pages/VideoPlay.ets @@ -13,7 +13,9 @@ * limitations under the License. */ -import { PiPWindow } from '@kit.ArkUI'; +import { ConfigurationConstant } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { PiPWindow, window } from '@kit.ArkUI'; import { JSON } from '@kit.ArkTS'; import { Constants } from '../constants/Constants'; import { AVPlayer } from './AVPlayer'; @@ -23,22 +25,50 @@ const TAG = Constants.NAV_DESTINATION_NAME; @Extend(Text) function textType() { - .padding({ left: $r('app.integer.other_padding') }) - .fontWeight(FontWeight.Bold) - .fontSize($r('app.integer.text_size')) - .alignSelf(ItemAlign.Start) + .fontColor($r('sys.color.font_primary')) + .fontSize($r('sys.float.Subtitle_M')) + .fontWeight(FontWeight.Medium) } @Extend(Text) function msgType() { - .padding({ left: $r('app.integer.other_padding') }) - .fontSize($r('app.integer.text_size')) - .fontColor($r('app.color.Message_color')) - .alignSelf(ItemAlign.Start) + .fontColor($r('sys.color.font_secondary')) + .fontSize($r('sys.float.Body_M')) + .fontWeight(FontWeight.Regular) +} + +@Extend(Row) +function twoTextRow() { + .height(22) + .width(Constants.FULL_PERCENT) + .justifyContent(FlexAlign.SpaceBetween) +} + +@Extend(Divider) +function twoTextDivider() { + .vertical(false) + .color($r('sys.color.comp_divider')) + .opacity(0.6) +} + +@Extend(Column) +function dataListColumn() { + .justifyContent(FlexAlign.SpaceBetween) + .backgroundColor($r('sys.color.comp_background_primary')) + .width(Constants.FULL_PERCENT) + .padding({ + right: $r('sys.float.corner_radius_level6'), + left: $r('sys.float.corner_radius_level6') + }) } @Component export struct PlayVideo { + @StorageProp('systemColorMode') @Watch('onColorModeChange') + currentMode: ConfigurationConstant.ColorMode = ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT; + @StorageLink('topRectHeight') topRectHeight: number = 0; + @StorageLink('bottomRectHeight') bottomRectHeight: number = 0; + @StorageLink('currentBreakpoint') curBp: string = Constants.BREAK_POINT_SM; @Consume('pageInfos') pageInfos: NavPathStack; @State curState: string = ''; @State curError: ResourceStr = ''; @@ -47,13 +77,17 @@ export struct PlayVideo { @State isLightBackground: boolean = false; @State hintMsgVisibility: boolean = false; @State pipTypeString: string = ''; - mXComponentController = new XComponentController(); - surfaceId = ''; - navigationId: string = ''; - player?: AVPlayer; - pipController?: PiPWindow.PiPController; - eventHub = getContext().eventHub; - private scrollerForScroll: Scroller = new Scroller() + private mXComponentController = new XComponentController(); + private surfaceId = ''; + private navigationId: string = ''; + private player?: AVPlayer; + private pipController: PiPWindow.PiPController | undefined = undefined; + private eventHub = getContext().eventHub; + private scrollerForScroll: Scroller = new Scroller(); + private defaultListData: Array = [1, 2, 3, 4, 5, 6]; + private pathStack: NavPathStack = new NavPathStack(); + // How to get the main window. + private mainWin: window.Window = AppStorage.get('windowClass') as window.Window; aboutToAppear(): void { this.eventHub.on('onStateChange', (fg: boolean) => { @@ -61,9 +95,55 @@ export struct PlayVideo { this.stopPip(); } }); + this.onColorModeChange(); + } + + aboutToDisappear(): void { + this.backColorModeChange(); + this.pipController?.off('stateChange'); + } + + backColorModeChange(): void { + let fontStatusColor = ''; + if (this.currentMode == ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT) { + // Currently in light mode, resource initialization logic. + fontStatusColor = '#000000'; + } else { + // The current mode is dark, resource initialization logic. + fontStatusColor = '#FFFFFF'; + } + this.setStatusStyle(fontStatusColor) } - async startPip() { + onColorModeChange(): void { + let fontStatusColor = ''; + if (this.currentMode == ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT) { + // Currently in light mode, resource initialization logic. + fontStatusColor = '#FFFFFF'; + } else { + // The current mode is dark, resource initialization logic. + fontStatusColor = '#FFFFFF'; + } + this.setStatusStyle(fontStatusColor) + } + + setStatusStyle(statusBarContentColor: string): void { + let SystemBarProperties: window.SystemBarProperties = { + statusBarContentColor: statusBarContentColor + }; + try { + let promise = this.mainWin.setWindowSystemBarProperties(SystemBarProperties); + promise.then(() => { + Logger.info('Succeeded in setting the system bar properties.'); + }).catch((err: BusinessError) => { + Logger.error(`Failed to set the system bar properties. Cause code: ${err.code}, message: ${err.message}`); + }); + } catch (exception) { + Logger.error(`Failed to set the system bar properties. Cause code: ${exception.code}, message: ${exception.message}`); + } + } + + async startPip(): Promise { if (!this.pipController) { await this.createPipController(); } @@ -74,7 +154,7 @@ export struct PlayVideo { await this.pipController.startPiP(); } - async stopPip() { + async stopPip(): Promise { if (!this.pipController) { Logger.info(`[${TAG}] pipController is not exist`); return; @@ -82,12 +162,14 @@ export struct PlayVideo { await this.pipController.stopPiP(); } - async createPipController() { + async createPipController(): Promise { this.pipController = await PiPWindow.create({ context: getContext(this), componentController: this.mXComponentController, navigationId: this.navigationId, - templateType: PiPWindow.PiPTemplateType.VIDEO_PLAY + 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, }); this.pipController.on('stateChange', (state: PiPWindow.PiPState, reason: string) => { this.onStateChange(state, reason); @@ -97,7 +179,7 @@ export struct PlayVideo { }); } - destroyPipController() { + destroyPipController(): void { if (!this.pipController) { return; } @@ -106,7 +188,7 @@ export struct PlayVideo { this.pipController = undefined; } - onStateChange(state: PiPWindow.PiPState, reason: string) { + onStateChange(state: PiPWindow.PiPState, reason: string): void { switch (state) { case PiPWindow.PiPState.ABOUT_TO_START: this.curState = 'ABOUT_TO_START'; @@ -140,7 +222,7 @@ export struct PlayVideo { Logger.info(`[${TAG}] onStateChange: ${this.curState}, reason: ${reason}`); } - onActionEvent(event: PiPWindow.PiPActionEventType, status: number | undefined) { + onActionEvent(event: PiPWindow.PiPActionEventType, status: number | undefined): void { switch (event) { case 'playbackStateChanged': if (status === 0) { @@ -158,98 +240,16 @@ export struct PlayVideo { Logger.info(`[${TAG}] onActionEvent: ${this.buttonAction} status:${status}}`); } - build() { - Stack() { - NavDestination() { - Column({ space: Constants.SPACE }) { - Stack() { - Text($r('app.string.current_video_pip_play')) - .fontColor($r('app.color.XComponent_text_color')) - .margin({ bottom: $r('app.integer.x_component_marg_bottom') }) - .visibility(this.hintMsgVisibility ? Visibility.Visible : Visibility.Hidden) - XComponent({ id: 'video', type: '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: $r('app.float.x_component_height') }) - .margin({ top: $r('app.integer.x_component_marg_top') }) - .backgroundColor(Color.Transparent) - .align(Alignment.Bottom) - .id('x_component') - } - .size({ width: Constants.X_COMPONENT_WIDTH, height: $r('app.float.x_component_height') }) - .alignContent(Alignment.Bottom) - .backgroundColor($r('app.color.XComponent_backgroundColor')) - - Scroll(this.scrollerForScroll) { - Column({ space: Constants.SPACE }) { - this.ControlPip() - this.AutoPip() - this.CallbackMessage() - } - .width(Constants.NAV_DESTINATION_WIDTH) - } - .layoutWeight(Constants.SCROLL_LAY_OUT_WEIGHT) - .scrollable(ScrollDirection.Vertical) - .scrollBar(BarState.Off) - .edgeEffect(EdgeEffect.Spring) - } - .width(Constants.NAV_DESTINATION_WIDTH) - .height(Constants.NAV_DESTINATION_HEIGHT) - } - .hideTitleBar(true) - .backgroundColor($r('app.color.Play_backgroundColor')) - .onBackPressed(() => { - // Eject the top-of-the-stack element of the routing stack. - const popDestinationInfo = this.pageInfos.pop(); - Logger.info('pop' + 'return value' + JSON.stringify(popDestinationInfo)); - return true; - }) - } - } - - @Builder - ControlPip() { - Row({ space: Constants.SPACE }) { - Button($r('app.string.start')) - .width($r('app.integer.control_button_width')) - .onClick(() => { - this.startPip(); - this.hintMsgVisibility = true; - }) - Button($r('app.string.stop')) - .width($r('app.integer.control_button_width')) - .onClick(() => { - this.stopPip(); - this.hintMsgVisibility = false; - }) - } - .size({ width: Constants.CONTROL_WIDTH, height: $r('app.integer.control_height') }) - .justifyContent(FlexAlign.SpaceAround) - .id('pip_control') - } - @Builder AutoPip() { Row() { Text($r('app.string.auto')) - .width($r('app.integer.auto_text_width')) - .fontSize($r('app.integer.text_size')) - .fontWeight(FontWeight.Bold) - .padding({ left: $r('app.integer.other_padding') }) + .textType() Toggle({ type: ToggleType.Switch, isOn: this.isAutoPull }) .width($r('app.integer.auto_button_width')) .height($r('app.integer.auto_button_height')) - .selectedColor($r('app.color.Toggle_selectedColor')) - .padding({ right: $r('app.float.toggle_padding') }) + .selectedColor($r('sys.color.brand')) .onChange(async (isOn: boolean) => { this.isAutoPull = isOn; if (!this.pipController) { @@ -259,64 +259,273 @@ export struct PlayVideo { this.hintMsgVisibility = true; }) } - .width(Constants.AUTO_PIP_WIDTH) + .width(Constants.FULL_PERCENT) .height($r('app.integer.auto_pip_height')) - .borderRadius($r('app.integer.auto_button_board_radius')) + .backgroundColor($r('sys.color.comp_background_primary')) + .borderRadius($r('sys.float.corner_radius_level8')) .justifyContent(FlexAlign.SpaceBetween) - .backgroundColor($r('app.color.start_window_background')) + .padding({ + left: $r('sys.float.corner_radius_level6'), + right: $r('sys.float.corner_radius_level6') + }) } @Builder CallbackMessage() { - Column({ space: Constants.SPACE }) { + Column() { Text($r('app.string.callback_message')) - .width(Constants.CONTROL_WIDTH) - .fontColor($r('app.color.Text_color')) - .padding({ left: $r('app.integer.other_padding') }) - Column() { - Text($r('app.string.current_status')) - .textType() - Text(this.curState) - .msgType() - } - .size({ - width: Constants.CONTROL_WIDTH, - height: $r('app.integer.control_height') - }) - .backgroundColor($r('app.color.Callback_message_backgroundColor')) - .borderRadius($r('app.integer.auto_button_board_radius')) - .justifyContent(FlexAlign.SpaceAround) - .id('current_state') + .fontSize($r('sys.float.Subtitle_L')) + .width(Constants.FULL_PERCENT) + .fontColor($r('sys.color.font_secondary')) + .padding({ + right: $r('sys.float.corner_radius_level6'), + bottom: $r('sys.float.corner_radius_level6'), + left: $r('sys.float.corner_radius_level6') + }) Column() { - Text($r('app.string.current_error')) - .textType() - Text(this.curError) - .msgType() + Column() { + Column() { + Row() { + Text($r('app.string.current_status')) + .textType() + Text(this.curState) + .msgType() + } + .twoTextRow() + } + .justifyContent(FlexAlign.Center) + .height(this.curBp === 'sm' ? 48 : 56) + + Divider() + .twoTextDivider() + } + .dataListColumn() + .borderRadius({ + topLeft: $r('sys.float.corner_radius_level8'), + topRight: $r('sys.float.corner_radius_level8') + }) + + Column() { + Column() { + Row() { + Text($r('app.string.current_error')) + .textType() + Text(this.curError) + .msgType() + } + .twoTextRow() + } + .justifyContent(FlexAlign.Center) + .height(this.curBp === 'sm' ? 48 : 56) + + Divider() + .twoTextDivider() + } + .dataListColumn() + + Column() { + Column() { + Row() { + Text($r('app.string.current_action')) + .textType() + Text(this.buttonAction) + .msgType() + } + .twoTextRow() + } + .justifyContent(FlexAlign.Center) + .height(this.curBp === 'sm' ? 48 : 56) + + Divider() + .twoTextDivider() + .visibility(Visibility.Hidden) + } + .dataListColumn() + .borderRadius({ + bottomLeft: $r('sys.float.corner_radius_level8'), + bottomRight: $r('sys.float.corner_radius_level8') + }) } - .size({ - width: Constants.CONTROL_WIDTH, - height: $r('app.integer.control_height') - }) - .backgroundColor($r('app.color.Callback_message_backgroundColor')) - .borderRadius($r('app.integer.auto_button_board_radius')) - .justifyContent(FlexAlign.SpaceAround) - .id('current_error') + } + } - Column() { - Text($r('app.string.current_action')) - .textType() - Text(this.buttonAction) - .msgType() + @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) => index + JSON.stringify(item)) + } + .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(this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT ? + $r('sys.color.icon_primary') : $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(this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT ? + $r('sys.color.icon_fourth') : $r('sys.color.comp_background_tertiary')) + .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(); + }) + + 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(this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT ? + $r('sys.color.icon_fourth') : $r('sys.color.comp_background_tertiary')) + .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; + } + }) + } + } + .backgroundColor($r('sys.color.background_primary')) + .size({ + width: Constants.X_COMPONENT_WIDTH, + height: this.curBp === 'sm' ? '30%' : this.curBp === 'md' ? '45%' : '40%' + }) + + Scroll(this.scrollerForScroll) { + Column({ space: Constants.SPACE }) { + this.AutoPip() + this.CallbackMessage() + } + .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') + }) + .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); + }) } - .size({ - width: Constants.CONTROL_WIDTH, - height: $r('app.integer.control_height') + .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; }) - .backgroundColor($r('app.color.Callback_message_backgroundColor')) - .borderRadius($r('app.integer.auto_button_board_radius')) - .justifyContent(FlexAlign.SpaceAround) - .id('current_action') } + .width(Constants.FULL_PERCENT) + .height(Constants.FULL_PERCENT) + .backgroundColor($r('sys.color.background_secondary')) } } \ No newline at end of file diff --git a/entry/src/main/ets/pages/WindowPip.ets b/entry/src/main/ets/pages/WindowPip.ets index 67048e28b65e46d7acbc216c0f03fb8beca59f89..c2f6a204dd7db513cfef86ff652f6aa1a4c75b35 100644 --- a/entry/src/main/ets/pages/WindowPip.ets +++ b/entry/src/main/ets/pages/WindowPip.ets @@ -13,6 +13,9 @@ * limitations under the License. */ +import { ConfigurationConstant } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { window } from '@kit.ArkUI'; import { Constants } from '../constants/Constants'; import { PlayVideo } from './VideoPlay'; import Logger from '../utils/Logger'; @@ -24,19 +27,27 @@ struct ImageWidthTitle { private titleResource?: Resource; build() { - Column({ space: Constants.HOME_SPACE }) { + Column() { Image($r('app.media.btn_ground')) .width(Constants.NAV_DESTINATION_HEIGHT) .height(this.imageHeight) - .borderRadius($r('app.integer.video_button_board_radius')) + .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('app.integer.text_size')) + .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); + // router.pushUrl({url:'pages/VideoPlay'}) this.pageInfos?.pushPath({ name: Constants.NAV_DESTINATION_NAME }, { launchMode: 3 }); }) .onAreaChange((oldArea: Area, newArea: Area) => { @@ -50,9 +61,55 @@ struct ImageWidthTitle { @Entry @Component struct WindowPip { + @StorageProp('systemColorMode') @Watch('onColorModeChange') + currentMode: ConfigurationConstant.ColorMode = ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT; + @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 = ''; private navigationId: string = 'navId'; + private videoList: Array = [ + $r('app.string.video1'), $r('app.string.video2'), $r('app.string.video3'), + $r('app.string.video4'), $r('app.string.video5'), $r('app.string.video6'), + $r('app.string.video7'), $r('app.string.video8'), $r('app.string.video9'), + $r('app.string.video10'), $r('app.string.video11'), $r('app.string.video12'), + $r('app.string.video13'), $r('app.string.video14'), $r('app.string.video15') + ]; + // How to get the main window. + private mainWin: window.Window = AppStorage.get('windowClass') as window.Window; + + aboutToAppear(): void { + this.onColorModeChange(); + } + + onColorModeChange(): void { + let fontStatusColor = ''; + if (this.currentMode == ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT) { + // Currently in light mode, resource initialization logic. + fontStatusColor = '#000000'; + } else { + // The current mode is dark, resource initialization logic. + fontStatusColor = '#FFFFFF'; + } + this.setStatusStyle(fontStatusColor) + } + + setStatusStyle(statusBarContentColor: string): void { + let SystemBarProperties: window.SystemBarProperties = { + statusBarContentColor: statusBarContentColor + }; + try { + let promise = this.mainWin.setWindowSystemBarProperties(SystemBarProperties); + promise.then(() => { + Logger.info('Succeeded in setting the system bar properties.'); + }).catch((err: BusinessError) => { + Logger.error(`Failed to set the system bar properties. Cause code: ${err.code}, message: ${err.message}`); + }); + } catch (exception) { + Logger.error(`Failed to set the system bar properties. Cause code: ${exception.code}, message: ${exception.message}`); + } + } @Builder PageMap(name: string) { @@ -63,54 +120,53 @@ struct WindowPip { build() { Navigation(this.pageInfos) { - Scroll() { - Column() { - ImageWidthTitle({ titleResource: $r('app.string.video1'), pageInfos: this.pageInfos }) - Blank() - .height($r('app.integer.scroll_height')) - GridRow({ - columns: Constants.GRID_ROW_COLUMNS, - gutter: { x: Constants.GRID_ROW_X, y: Constants.GRID_ROW_Y } - }) { - GridCol() { - ImageWidthTitle({ titleResource: $r('app.string.video2'), pageInfos: this.pageInfos }) - } - - GridCol() { - ImageWidthTitle({ titleResource: $r('app.string.video3'), pageInfos: this.pageInfos }) - } - - GridCol() { - ImageWidthTitle({ titleResource: $r('app.string.video4'), pageInfos: this.pageInfos }) - } - - GridCol() { - ImageWidthTitle({ titleResource: $r('app.string.video5'), pageInfos: this.pageInfos }) - } - - GridCol() { - ImageWidthTitle({ titleResource: $r('app.string.video6'), pageInfos: this.pageInfos }) - } + Column() { + Row() { + Text($r('app.string.pip_effect')) + .fontSize($r('sys.float.Title_L')) + .fontWeight(FontWeight.Bold) + .fontColor($r('sys.color.font_primary')) + } + .width('100%') + .height(40) + .margin({ + top: 84, + bottom: $r('sys.float.padding_level12') + }) - GridCol() { - ImageWidthTitle({ titleResource: $r('app.string.video7'), pageInfos: this.pageInfos }) + Grid() { + ForEach(this.videoList, (item: Resource, index: number) => { + GridItem() { + ImageWidthTitle({ titleResource: item, pageInfos: this.pageInfos }) } - } - .width(Constants.NAV_DESTINATION_WIDTH) + .padding({ + bottom: this.videoList.length - 1 === index ? $r('sys.float.padding_level8') : + $r('sys.float.padding_level0') + }) + }, (item: Resource, index: number) => index + JSON.stringify(item)) } - .justifyContent(FlexAlign.Start) - .padding({ left: Constants.COLUMNS_PADDING, right: Constants.COLUMNS_PADDING }) - .height(Constants.NAV_DESTINATION_HEIGHT) + .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) + .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) } - .scrollable(ScrollDirection.Vertical) - .scrollBar(BarState.Off) - .edgeEffect(EdgeEffect.Spring) + .width(Constants.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'), + left: this.curBp === 'lg' ? $r('sys.float.padding_level8') : $r('sys.float.padding_level6') + }) } - .title($r('app.string.pip_demo')) - .titleMode(NavigationTitleMode.Mini) - .hideBackButton(true) - .mode(NavigationMode.Auto) + .title($r('app.string.pip_effect')) + .titleMode(NavigationTitleMode.Full) + .hideTitleBar(true) .navDestination(this.PageMap) + .mode(NavigationMode.Stack) + .hideBackButton(true) + .backgroundColor($r('sys.color.background_secondary')) .size({ width: Constants.NAV_DESTINATION_WIDTH, height: Constants.NAV_DESTINATION_HEIGHT }) .id(this.navigationId) } diff --git a/entry/src/main/resources/base/element/color.json b/entry/src/main/resources/base/element/color.json index 95fc9b84bcd42de85c4c6fdec9998a7493b4d054..6b377d2fbcd40b68cd54ebf7cb60633009227814 100644 --- a/entry/src/main/resources/base/element/color.json +++ b/entry/src/main/resources/base/element/color.json @@ -35,6 +35,10 @@ { "name": "XComponent_text_color", "value": "#686868" + }, + { + "name": "video_background_dark", + "value": "#1a1a1a" } ] } \ No newline at end of file diff --git a/entry/src/main/resources/base/element/float.json b/entry/src/main/resources/base/element/float.json index 4a49ef7f00033bdd443ccaf1eb54c21dd2b1ee4c..e72ba25d2877163c71a4321c53201979147a4039 100644 --- a/entry/src/main/resources/base/element/float.json +++ b/entry/src/main/resources/base/element/float.json @@ -1,9 +1,5 @@ { "float": [ - { - "name": "x_component_height", - "value": "800px" - }, { "name": "toggle_padding", "value": "10.75" diff --git a/entry/src/main/resources/base/element/integer.json b/entry/src/main/resources/base/element/integer.json index b43b81dd5194b523a36f7c847883bcdbb49e4467..dbbc12173e666abc37b411cad892ee42c6bf34c1 100644 --- a/entry/src/main/resources/base/element/integer.json +++ b/entry/src/main/resources/base/element/integer.json @@ -50,11 +50,11 @@ }, { "name": "auto_button_height", - "value": 27 + "value": 20 }, { "name": "auto_button_width", - "value": 60 + "value": 36 }, { "name": "video_button_height", diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json index 524d7ae334bc7e7ba6e922fb570c636026e5b2de..7cb600d0bcb699ef9185baa412255560e1eac303 100644 --- a/entry/src/main/resources/base/element/string.json +++ b/entry/src/main/resources/base/element/string.json @@ -41,8 +41,40 @@ "value": "Video7" }, { - "name": "pip_demo", - "value": "WindowPiP" + "name": "video8", + "value": "Video8" + }, + { + "name": "video9", + "value": "Video9" + }, + { + "name": "video10", + "value": "Video10" + }, + { + "name": "video11", + "value": "Video11" + }, + { + "name": "video12", + "value": "Video12" + }, + { + "name": "video13", + "value": "Video13" + }, + { + "name": "video14", + "value": "Video14" + }, + { + "name": "video15", + "value": "Video15" + }, + { + "name": "pip_effect", + "value": "PiP Effect" }, { "name": "start", @@ -54,7 +86,7 @@ }, { "name": "auto", - "value": "Auto" + "value": "Automatically Start PiP" }, { "name": "current_status", diff --git a/entry/src/main/resources/base/media/btn_ground.PNG b/entry/src/main/resources/base/media/btn_ground.PNG index 25ce3c2994f68bee7a5fa3ba26f57f9faa707267..3bfbbe3b811d2468f6834492c707fe256d5498d1 100644 Binary files a/entry/src/main/resources/base/media/btn_ground.PNG and b/entry/src/main/resources/base/media/btn_ground.PNG differ diff --git a/entry/src/main/resources/en_US/element/string.json b/entry/src/main/resources/en_US/element/string.json index 524d7ae334bc7e7ba6e922fb570c636026e5b2de..7cb600d0bcb699ef9185baa412255560e1eac303 100644 --- a/entry/src/main/resources/en_US/element/string.json +++ b/entry/src/main/resources/en_US/element/string.json @@ -41,8 +41,40 @@ "value": "Video7" }, { - "name": "pip_demo", - "value": "WindowPiP" + "name": "video8", + "value": "Video8" + }, + { + "name": "video9", + "value": "Video9" + }, + { + "name": "video10", + "value": "Video10" + }, + { + "name": "video11", + "value": "Video11" + }, + { + "name": "video12", + "value": "Video12" + }, + { + "name": "video13", + "value": "Video13" + }, + { + "name": "video14", + "value": "Video14" + }, + { + "name": "video15", + "value": "Video15" + }, + { + "name": "pip_effect", + "value": "PiP Effect" }, { "name": "start", @@ -54,7 +86,7 @@ }, { "name": "auto", - "value": "Auto" + "value": "Automatically Start PiP" }, { "name": "current_status", diff --git a/entry/src/main/resources/rawfile/video.mov b/entry/src/main/resources/rawfile/video.mov new file mode 100644 index 0000000000000000000000000000000000000000..68c87f00df82a782c34695c9ee403995a16d5274 Binary files /dev/null and b/entry/src/main/resources/rawfile/video.mov differ diff --git a/entry/src/main/resources/rawfile/video.mp4 b/entry/src/main/resources/rawfile/video.mp4 deleted file mode 100644 index 43889ee3fc3d21ab6780366d536c5c4608a00cb4..0000000000000000000000000000000000000000 Binary files a/entry/src/main/resources/rawfile/video.mp4 and /dev/null differ diff --git a/entry/src/main/resources/zh_CN/element/string.json b/entry/src/main/resources/zh_CN/element/string.json index 3e368b8b09eadc9d8a6ff0c45ebb76528e846744..cf0a6343b5fce019684da8e4b1ae30d94bee0f3e 100644 --- a/entry/src/main/resources/zh_CN/element/string.json +++ b/entry/src/main/resources/zh_CN/element/string.json @@ -40,10 +40,41 @@ "name": "video7", "value": "视频7" }, - { - "name": "pip_demo", - "value": "画中画示例" + "name": "video8", + "value": "视频8" + }, + { + "name": "video9", + "value": "视频9" + }, + { + "name": "video10", + "value": "视频10" + }, + { + "name": "video11", + "value": "视频11" + }, + { + "name": "video12", + "value": "视频12" + }, + { + "name": "video13", + "value": "视频13" + }, + { + "name": "video14", + "value": "视频14" + }, + { + "name": "video15", + "value": "视频15" + }, + { + "name": "pip_effect", + "value": "实现画中画效果" }, { "name": "start",