diff --git a/AppScope/app.json5 b/AppScope/app.json5
index 83474faa86f70f58c8d2474835d9f19e51c85101..d1d2c5a73821a1cd135177cf6065c922f9d4df0c 100644
--- a/AppScope/app.json5
+++ b/AppScope/app.json5
@@ -15,12 +15,11 @@
{
"app": {
- "bundleName": "net.openvally.videoplay",
+ "bundleName": "com.example.avplayer_basic_control",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
- "icon": "$media:app_icon",
- "label": "$string:app_name",
- "distributedNotificationEnabled": true
+ "icon": "$media:layered_image",
+ "label": "$string:app_name"
}
}
diff --git a/AppScope/resources/base/element/string.json b/AppScope/resources/base/element/string.json
index 890b5c1cef25ffee69bf80276ba3a0e3a560cbc3..e1ab609a842ddb871d7bc6d573ce77479bd7c9e9 100644
--- a/AppScope/resources/base/element/string.json
+++ b/AppScope/resources/base/element/string.json
@@ -2,7 +2,7 @@
"string": [
{
"name": "app_name",
- "value": "VideoPlay"
+ "value": "avplayer_basic_control"
}
]
}
diff --git a/AppScope/resources/base/media/app_icon.png b/AppScope/resources/base/media/app_icon.png
index ce307a8827bd75456441ceb57d530e4c8d45d36c..a39445dc87828b76fed6d2ec470dd455c45319e3 100644
Binary files a/AppScope/resources/base/media/app_icon.png and b/AppScope/resources/base/media/app_icon.png differ
diff --git a/README.md b/README.md
index 0b7de8605b514a2d0716f560e68977dd1d5a9e27..a105d314b8209b7abaa22d1d4a5d7e9b6a60e0d0 100644
--- a/README.md
+++ b/README.md
@@ -2,26 +2,17 @@
## 项目简介
-本示例主要展示了如何基于AVPlayer系统播放器实现播放本地视频相关功能,指导开发者实现以下开发场景:
-
-- 视频加载、播放、暂停、退出
-- 跳转播放
-- 静音播放
-- 循环播放
-- 窗口缩放模式设置
-- 倍速设置
-- 音量设置
-- 字幕挂载
+本示例主要展示了如何基于AVPlayer系统播放器实现播放本地视频相关功能,指导开发者实现视频加载、播放、暂停、退出;跳转播放;静音播放;循环播放;窗口缩放模式设置;倍速设置;音量设置;字幕挂载等开发场景。
## 效果预览
-| 播放 | 暂停 | 倍速弹窗 |
-|--------------------------------------------|------------------------------------------|----------------------------------------------------|
-|  |  |  |
+| 播放 | 暂停 | 倍速弹窗 |
+|-----------------------------------------------------------------|------------------------------------------|----------------------------------------------------|
+|
|
|
|
| 静音设置 | 音量设置 | 窗口缩放模式设置 |
|------------------------------------------------------|-------------------------------------------------|----------------------------------------------------|
-|  |  |  |
+|
|
|
|
## 使用说明
@@ -35,7 +26,7 @@
8. 点击窗口缩放模式按钮,可以选择拉伸至与窗口等大、缩放至最短边填满窗口;
9. 长按屏幕,控制视频2.0倍速播放;
10. 上下滑动屏幕,可以设置视频播放音量;
-11. 视频下方显示字幕;
+11. 视频下方显示字幕,并可以点击语言切换按钮切换字幕;
12. 视频自动循环播放;
13. 点击左上角退出箭头,退出应用。
@@ -44,13 +35,13 @@
```
├──entry/src/main/ets // 代码区
│ ├──common
-│ │ │──constants
+│ │ ├──constants
│ │ │ └──CommonConstants.ets // 公共常量
│ │ └──utils
│ │ ├──GlobalContext.ets // 公共工具类
│ │ └──TimeUtils.ts // 视频时间帮助类
-│ ├──components
-│ │ ├──ExitVideo.ets // 退出应用组件
+│ ├──views
+│ │ ├──languageDialog.ets // 弹幕语言切换弹窗
│ │ ├──ScaleDialog.ets // 窗口缩放模式设置弹窗
│ │ ├──SetVolumn.ets // 设置音量组件
│ │ ├──SpeedDialog.ets // 播放倍速弹窗
@@ -63,12 +54,13 @@
│ │ └──VideoData.ets // 视频数据类
│ └──pages
│ └──Index.ets // 首页视频界面
-└────entry/src/main/resources // 应用资源目录
+└──entry/src/main/resources // 应用资源目录
```
## 具体实现
-+ 视频倍速切换、暂停、播放、切换视频、视频跳转的功能接口都封装在AvPlayerController.ets,源码参考:[AvPlayerController.ets](entry/src/main/ets/controller/AvPlayerController.ets);
++
+视频倍速切换、暂停、播放、切换视频、视频跳转的功能接口都封装在AvPlayerController.ets,源码参考:[AvPlayerController.ets](entry/src/main/ets/controller/AvPlayerController.ets);
+ 使用media.createAVPlayer()来获取AVPlayer对象;
+ 倍速切换:选择不同倍速时调用avPlayer.setSpeed(speed: PlaybackSpeed);
+ 暂停、播放:点击暂停、播放按钮时调用avPlayer.pause()、avPlayer.play();
diff --git a/entry/src/main/ets/components/ExitVideo.ets b/entry/src/main/ets/components/ExitVideo.ets
deleted file mode 100644
index 927dce1a29b0e232c8e4c3f1311fd60adb3d0e6d..0000000000000000000000000000000000000000
--- a/entry/src/main/ets/components/ExitVideo.ets
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2025 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 { common } from '@kit.AbilityKit';
-import { GlobalContext } from '../common/utils/GlobalContext';
-
-@Component
-export struct ExitVideo {
- @StorageLink('videoName') videoName: Resource = $r('app.string.video_res_1');
-
- build() {
- Row() {
- // Exit
- Column() {
- Image($r('app.media.ic_video_back'))
- .id('Exit')
- .width($r('app.float.size_15'))
- }
- .width($r('app.float.size_40'))
- .height($r('app.float.size_40'))
- .borderRadius($r('app.float.size_20'))
- .justifyContent(FlexAlign.Center)
- .backgroundColor($r('app.color.back_button'))
- .onClick(() => {
- (GlobalContext.getContext().getObject('context') as (common.UIAbilityContext)).terminateSelf();
- })
-
- Text(this.videoName)
- .fontColor(Color.White)
- .fontWeight(FontWeight.Medium)
- .fontSize($r('app.float.size_24'))
- .margin({ left: $r('app.float.size_16') })
- }
- .margin({ top: $r('app.float.size_20'), left: $r('app.float.size_25') })
- }
-}
\ No newline at end of file
diff --git a/entry/src/main/ets/controller/AvPlayerController.ets b/entry/src/main/ets/controller/AvPlayerController.ets
index d8c27ce7ea64f8c992f1623745240a192a51fc45..585bfbd8099556ab64451471baa8219951eb7f5d 100644
--- a/entry/src/main/ets/controller/AvPlayerController.ets
+++ b/entry/src/main/ets/controller/AvPlayerController.ets
@@ -49,7 +49,7 @@ export class AvPlayerController {
// [Start create_instance]
// Create an AVPlayer instance
- public async initAVPlayer(source: VideoData, surfaceId: string) {
+ public async initAVPlayer(source: VideoData, surfaceId: string, avPlayer?: media.AVPlayer) {
if (!this.context) {
hilog.info(CommonConstants.LOG_DOMAIN, TAG, `initPlayer failed context not set`);
return
@@ -75,7 +75,7 @@ export class AvPlayerController {
try {
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'initPlayer videoPlay avPlayerDemo');
// Creates the avPlayer instance object.
- this.avPlayer = await media.createAVPlayer();
+ this.avPlayer = avPlayer ? avPlayer : await media.createAVPlayer()
// Creates a callback function for state machine changes.
this.setAVPlayerCallback();
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'initPlayer videoPlay setAVPlayerCallback');
@@ -122,7 +122,7 @@ export class AvPlayerController {
this.avPlayer.addSubtitleFromFd(fileDescriptorSub.fd, fileDescriptorSub.offset, fileDescriptorSub.length);
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'initPlayer videoPlay addSubtitleFromFd');
}
- // [Start AddCaption]
+ // [End AddCaption]
} catch (err) {
hilog.error(CommonConstants.LOG_DOMAIN, TAG,
`initPlayer initPlayer, code is ${err.code}, message is ${err.message}`);
@@ -153,7 +153,7 @@ export class AvPlayerController {
this.currentTime = time;
AppStorage.setOrCreate('CurrentTime', time);
hilog.info(CommonConstants.LOG_DOMAIN, TAG,
- `setAVPlayerCallback timeUpdate success,and new time is = ${this.currentTime}`);
+ `setAVPlayerCallback timeUpdate success, and new time is = ${this.currentTime}`);
});
// The error callback function is triggered when an error occurs during avPlayer operations,
@@ -166,21 +166,7 @@ export class AvPlayerController {
`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
this.avPlayer.reset(); // resets the resources and triggers the idle state
})
- // [Start RegisterCaptionCallBack]
- this.avPlayer.on('subtitleUpdate', (info: media.SubtitleInfo) => {
- if (!!info) {
- let text = (!info.text) ? '' : info.text;
- let startTime = (!info.startTime) ? 0 : info.startTime;
- let duration = (!info.duration) ? 0 : info.duration;
- this.currentCaption = text; //update current caption content
- hilog.info(CommonConstants.LOG_DOMAIN, TAG,
- `subtitleUpdate info: text:${text},startTime:${startTime},duration:${duration}`);
- } else {
- this.currentCaption = '';
- hilog.error(CommonConstants.LOG_DOMAIN, TAG, 'subtitleUpdate info is null');
- }
- });
- // [End RegisterCaptionCallBack]
+ this.subtitleUpdateFunction();
this.setStateChangeCallback();
}
@@ -199,8 +185,8 @@ export class AvPlayerController {
}
switch (state) {
// DocsDot
+ // [StartExclude state]
case 'idle': // This state machine is triggered after the reset interface is successfully invoked.
- this.avPlayer.release();
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'setAVPlayerCallback AVPlayer state idle called.');
break;
case 'initialized': // This status is reported after the playback source is set on the AVPlayer.
@@ -211,12 +197,14 @@ export class AvPlayerController {
`setAVPlayerCallback this.avPlayer.surfaceId = ${this.avPlayer.surfaceId}`);
this.avPlayer.prepare();
break;
- // DocsDot
+ // [EndExclude state]
+ // DocsDot
case 'prepared': // This state machine is reported after the prepare interface is successfully invoked.
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'setAVPlayerCallback AVPlayer state prepared called.');
this.isReady = true;
this.avPlayer.loop = true
// DocsDot
+ // [StartExclude prepared]
this.durationTime = this.avPlayer.duration;
this.currentTime = this.avPlayer.currentTime;
this.avPlayer.audioInterruptMode = audio.InterruptMode.SHARE_MODE;
@@ -240,9 +228,11 @@ export class AvPlayerController {
}
this.setVideoSpeed();
+ // [EndExclude prepared]
// DocsDot
break;
- // DocsDot
+ // DocsDot
+ // [StartExclude other_state]
case 'playing': // After the play interface is successfully invoked, the state machine is reported.
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'setAVPlayerCallback AVPlayer state playing called.');
this.isPlaying = true;
@@ -274,6 +264,7 @@ export class AvPlayerController {
default:
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'setAVPlayerCallback AVPlayer state unknown called.');
break;
+ // [EndExclude other_state]
// DocsDot
}
});
@@ -296,16 +287,16 @@ export class AvPlayerController {
private setVideoSpeed() {
switch (this.speedSelect) {
case CASE_ZERO:
- this.videoSpeedOne();
+ this.videoSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X);
break;
case CASE_ONE:
- this.videoSpeedOnePointTwentyFive();
+ this.videoSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_25_X);
break;
case CASE_TWO:
- this.videoSpeedOnePointSeventyFive();
+ this.videoSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_75_X);
break;
case CASE_THREE:
- this.videoSpeedTwo();
+ this.videoSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X);
break;
default:
break;
@@ -331,7 +322,7 @@ export class AvPlayerController {
this.isPlaying = false;
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'videoPause');
} catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG,
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
`videoPause failed, code is ${err.code}, message is ${err.message}`);
}
}
@@ -345,7 +336,7 @@ export class AvPlayerController {
this.isPlaying = false;
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'videoPause');
} catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG,
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
`videoPause failed, code is ${err.code}, message is ${err.message}`);
}
}
@@ -364,7 +355,7 @@ export class AvPlayerController {
await this.avPlayer!.setMediaMuted(media.MediaType.MEDIA_TYPE_AUD, isMuted)
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'videoMuted');
} catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG,
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
`videoMuted failed, code is ${err.code}, message is ${err.message}`);
}
}
@@ -373,61 +364,18 @@ export class AvPlayerController {
// [End video_muted_fun]
// [Start video_speed_fun]
-
- // [Start video_speed_1.0X_fun]
- videoSpeedOne(): void {
+ videoSpeed(speed: number): void {
if (this.avPlayer) {
try {
- this.avPlayer.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X);
- hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'videoSpeed_1_00');
+ this.avPlayer.setSpeed(speed);
+ hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'videoSpeed');
} catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG,
- `videoSpeed_1_00 failed, code is ${err.code}, message is ${err.message}`);
- }
- }
- }
-
- // [End video_speed_1.0X_fun]
-
- videoSpeedOnePointTwentyFive(): void {
- if (this.avPlayer) {
- try {
- this.avPlayer.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_25_X);
- hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'videoSpeed_1_25');
- } catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG,
- `videoSpeed_1_25 failed, code is ${err.code}, message is ${err.message}`);
- }
- }
- }
-
- videoSpeedOnePointSeventyFive(): void {
- if (this.avPlayer) {
- try {
- this.avPlayer.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_75_X);
- hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'videoSpeed_1_75');
- } catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG,
- `videoSpeed_1_75 failed, code is ${err.code}, message is ${err.message}`);
- }
- }
- }
-
- // [Start video_speed_2.0X_fun]
- videoSpeedTwo(): void {
- if (this.avPlayer) {
- try {
- this.avPlayer.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X);
- hilog.info(CommonConstants.LOG_DOMAIN, TAG, `videoSpeed_2_0`);
- } catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG,
- `videoSpeed_2_0 failed, code is ${err.code}, message is ${err.message}`);
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
+ `videoSpeed failed, code is ${err.code}, message is ${err.message}`);
}
}
}
- // [End video_speed_2.0X_fun]
-
// [End video_speed_fun]
videoSeek(seekTime: number): void {
@@ -436,7 +384,8 @@ export class AvPlayerController {
this.avPlayer.seek(seekTime, media.SeekMode.SEEK_CLOSEST);
hilog.info(CommonConstants.LOG_DOMAIN, TAG, `videoSeek== ${seekTime}`);
} catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG, `videoSeek failed, code is ${err.code}, message is ${err.message}`);
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
+ `videoSeek failed, code is ${err.code}, message is ${err.message}`);
}
}
}
@@ -448,7 +397,7 @@ export class AvPlayerController {
try {
await this.avPlayer.reset();
} catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG, `videoReset failed, code is ${err.code}, message is ${err.message}`);
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG, `videoReset failed, code is ${err.code}, message is ${err.message}`);
}
}
@@ -458,7 +407,7 @@ export class AvPlayerController {
return;
}
this.avPlayer.release((err) => {
- if (err == null) {
+ if (err === null) {
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'videoRelease release success');
} else {
hilog.error(CommonConstants.LOG_DOMAIN, TAG,
@@ -485,7 +434,7 @@ export class AvPlayerController {
this.avPlayer.videoScaleType = media.VideoScaleType.VIDEO_SCALE_TYPE_FIT
hilog.info(CommonConstants.LOG_DOMAIN, TAG, `videoScaleType_0`);
} catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG,
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
`videoScaleType_0 failed, code is ${err.code}, message is ${err.message}`);
}
}
@@ -497,11 +446,55 @@ export class AvPlayerController {
this.avPlayer.videoScaleType = media.VideoScaleType.VIDEO_SCALE_TYPE_FIT_CROP
hilog.info(CommonConstants.LOG_DOMAIN, TAG, `videoScaleType_1`);
} catch (err) {
- hilog.info(CommonConstants.LOG_DOMAIN, TAG,
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
`videoScaleType_1 failed, code is ${err.code}, message is ${err.message}`);
}
}
}
// [End window_scale_fun]
+ subtitleUpdateFunction(): void {
+ try {
+ if (this.avPlayer) {
+ // [Start RegisterCaptionCallBack]
+ this.avPlayer.on('subtitleUpdate', (info: media.SubtitleInfo) => {
+ if (info) {
+ let text = (!info.text) ? '' : info.text;
+ let startTime = (!info.startTime) ? 0 : info.startTime;
+ let duration = (!info.duration) ? 0 : info.duration;
+ this.currentCaption = text; //update current caption content
+ hilog.info(CommonConstants.LOG_DOMAIN, TAG,
+ `subtitleUpdate info: text:${text}, startTime:${startTime}, duration:${duration}`);
+ } else {
+ this.currentCaption = '';
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG, 'subtitleUpdate info is null');
+ }
+ });
+ // [End RegisterCaptionCallBack]
+ }
+ } catch (err) {
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
+ `subtitleUpdateFunction failed, code is ${err.code}, message is ${err.message}`);
+ }
+ }
+
+ // [Start languageSwitch]
+ async languageChange(languageSelect: number = 0): Promise {
+ if (this.avPlayer) {
+ try {
+ if (this.curSource && this.curSource.caption) {
+ this.curSource.caption = languageSelect === 0 ? 'captions.srt' : 'en_captions.srt'
+ this.curSource.seekTime = this.avPlayer.currentTime;
+ await this.avPlayer.reset();
+ this.initAVPlayer(this.curSource, this.surfaceID, this.avPlayer);
+ hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'language change');
+ }
+ } catch (err) {
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
+ `languageChange failed, code is ${err.code}, message is ${err.message}`);
+ }
+ }
+ }
+
+ // [End languageSwitch]
}
\ 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 7546edc89e0c327533ac83f104165147cb60f946..9d939aec0e89269e2237344f3169a51914e37155 100644
--- a/entry/src/main/ets/entryability/EntryAbility.ets
+++ b/entry/src/main/ets/entryability/EntryAbility.ets
@@ -23,8 +23,6 @@ import { CommonConstants } from '../common/constants/CommonConstants';
const TAG = '[EntryAbility]';
export default class EntryAbility extends UIAbility {
-
-
onCreate(want: Want) {
GlobalContext.getContext().setObject('abilityWant', want)
GlobalContext.getContext().setObject('context', this.context)
@@ -44,29 +42,36 @@ export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
hilog.info(CommonConstants.LOG_DOMAIN, TAG, '%{public}s', 'Ability onWindowStageCreate');
- windowStage.getMainWindow().then((win: window.Window) => {
- win.setWindowKeepScreenOn(true);
- win.setWindowSystemBarProperties({
- statusBarColor: '#000000',
- statusBarContentColor: '#FFFFFF'
- });
- win.setWindowLayoutFullScreen(true);
- win.on('windowSizeChange', (newSize: window.Size) => {
- let eventWHData: emitter.EventData = {
- data: {
- 'width': newSize.width,
- 'height': newSize.height
- }
- };
- emitter.emit(CommonConstants.innerEventWH, eventWHData);
+ try {
+ windowStage.getMainWindow().then((win: window.Window) => {
+ win.setWindowKeepScreenOn(true);
+ win.setWindowSystemBarProperties({
+ statusBarColor: '#000000',
+ statusBarContentColor: '#FFFFFF'
+ });
+ win.setWindowLayoutFullScreen(true);
+ win.on('windowSizeChange', (newSize: window.Size) => {
+ let eventWHData: emitter.EventData = {
+ data: {
+ 'width': newSize.width,
+ 'height': newSize.height
+ }
+ };
+ emitter.emit(CommonConstants.innerEventWH, eventWHData);
+ });
});
- });
+ } catch (err) {
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
+ `getMainWindow failed, code is ${err.code}, message is ${err.message}`);
+ }
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
- hilog.error(CommonConstants.LOG_DOMAIN, TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG, 'Failed to load the content. Cause: %{public}s',
+ JSON.stringify(err) ?? '');
return;
}
- hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
+ hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'Succeeded in loading the content. Data: %{public}s',
+ JSON.stringify(data) ?? '');
});
}
diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets
index 2a15a9c978c914fc065c0b5230ae64d18b6d469d..eb581110dfbb861f8b94718ebcbb5635aa1d36ac 100644
--- a/entry/src/main/ets/pages/Index.ets
+++ b/entry/src/main/ets/pages/Index.ets
@@ -17,10 +17,10 @@ import { connection } from '@kit.NetworkKit';
import { display } from '@kit.ArkUI';
import { emitter } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
+import { media } from '@kit.MediaKit';
import { AvPlayerController } from '../controller/AvPlayerController';
-import { VideoOperate } from '../components/VideoOperate';
-import { ExitVideo } from '../components/ExitVideo';
-import { SetVolume } from '../components/SetVolume'
+import { VideoOperate } from '../views/VideoOperate';
+import { SetVolume } from '../views/SetVolume'
import { timeConvert } from '../common/utils/TimeUtils';
import { GlobalContext } from '../common/utils/GlobalContext';
import { VideoDataType, CommonConstants } from '../common/constants/CommonConstants';
@@ -34,6 +34,8 @@ const SET_TIME_OUT = 8000; // Interval: 8s
const SET_INTERVAL = 100;
const SET_VOLUME_TIME_OUT = 5000 // VolumeTimer: 5s
const TAG = '[Index]';
+const CASE_ZERO = 0;
+const CASE_THREE = 3;
@Entry
@Component
@@ -43,13 +45,15 @@ struct Index {
@State isClickScreen: boolean = false;
@State flag: boolean = true; // Pause Playback
@State XComponentFlag: boolean = false;
- @State speedSelect: number = 0;
- @State videoListSelect: number = 0;
+ @State speedList: Resource[] =
+ [$r('app.string.video_speed_1_0X'), $r('app.string.video_speed_1_25X'), $r('app.string.video_speed_1_75X'),
+ $r('app.string.video_speed_2_0X')];
+ @State @Watch('onSpeedSelectUpdate') speedSelect: number = 0;
@State durationTime: number = 0;
@State currentTime: number = 0;
@State surfaceW: number = 0;
@State surfaceH: number = 0;
- @State volume: number = 5;
+ @State @Watch('onVolumeUpdate') volume: number = 5;
@State volumeVisible: boolean = false
@State show: boolean = false; // Indicates whether the videoPanel component is displayed.
@State percent: number = 0;
@@ -92,8 +96,13 @@ struct Index {
}
aboutToAppear() {
- this.windowWidth = display.getDefaultDisplaySync().width;
- this.windowHeight = display.getDefaultDisplaySync().height;
+ try {
+ this.windowWidth = display.getDefaultDisplaySync().width;
+ this.windowHeight = display.getDefaultDisplaySync().height;
+ } catch (err) {
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
+ `getDefaultDisplaySync failed, code is ${err.code}, message is ${err.message}`);
+ }
this.surfaceW = (GlobalContext.getContext().getObject('windowWidth') as number) * SURFACE_WIDTH;
this.surfaceH = this.surfaceW / SURFACE_HEIGHT;
this.flag = true;
@@ -142,7 +151,7 @@ struct Index {
this.setVideoWH();
}
});
- if (this.flag == false) {
+ if (this.flag === false) {
this.clearTimer();
}
}
@@ -157,19 +166,39 @@ struct Index {
}
}
+ onSpeedSelectUpdate() {
+ AppStorage.setOrCreate('speedName', this.speedList[this.speedSelect]);
+ AppStorage.setOrCreate('speedIndex', this.speedSelect);
+ }
+
+ onVolumeUpdate() {
+ AppStorage.setOrCreate('isMuted', this.volume <= 0.0);
+ this.avPlayerController.videoMuted(this.volume <= 0.0);
+ }
+
async isInternet(): Promise {
- if (connection.getAllNetsSync().length <= 0) {
- this.toast();
- return false
+ try {
+ if (connection.getAllNetsSync().length <= 0) {
+ this.toast();
+ return false
+ }
+ } catch (err) {
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
+ `getAllNetsSync failed, code is ${err.code}, message is ${err.message}`);
}
return true;
}
async toast() {
- this.getUIContext().getPromptAction().showToast({
- message: $r('app.string.video_warn'),
- duration: 2000,
- });
+ try {
+ this.getUIContext().getPromptAction().showToast({
+ message: $r('app.string.video_warn'),
+ duration: 2000,
+ });
+ } catch (err) {
+ hilog.error(CommonConstants.LOG_DOMAIN, TAG,
+ `showToast failed, code is ${err.code}, message is ${err.message}`);
+ }
}
@Builder
@@ -201,8 +230,9 @@ struct Index {
SetVolume({ volume: this.volume, volumeVisible: this.volumeVisible })
Column() {
+ // [Start currentCaptionText]
Stack({ alignContent: Alignment.Center }) {
- Text(this.avPlayerController.currentCaption || '')
+ Text(this.avPlayerController.currentCaption)
.fontColor(Color.White)
.fontSize($r('app.float.size_20'))
.fontFamily('Sans')
@@ -211,6 +241,8 @@ struct Index {
.position({ x: $r('app.float.size_zero'), y: $r('app.float.size_210') })
.zIndex(1)
+ // [End currentCaptionText]
+
this.CoverXComponent()
}
// [Start pan_gesture]
@@ -223,8 +255,6 @@ struct Index {
let curVolume = this.volume - this.getUIContext().vp2px(event.offsetY) / this.windowHeight;
curVolume = curVolume >= 15.0 ? 15.0 : curVolume;
curVolume = curVolume <= 0.0 ? 0.0 : curVolume;
- AppStorage.setOrCreate('isMuted', curVolume <= 0.0);
- this.avPlayerController.videoMuted(curVolume <= 0.0);
this.volume = curVolume;
hilog.info(CommonConstants.LOG_DOMAIN, TAG, 'AVPlayManage', 'AVPlayer', `this volumn is: ` + this.volume);
})
@@ -260,12 +290,6 @@ struct Index {
.visibility(this.isSwiping ? Visibility.Visible : Visibility.Hidden)
Column() {
- Row() {
- ExitVideo()
- }
- .width('100%')
- .justifyContent(FlexAlign.Start)
-
Blank()
Column() {
// Progress bar
@@ -282,12 +306,12 @@ struct Index {
.justifyContent(FlexAlign.Center)
}
.onTouch((event: TouchEvent) => {
- if (event.type == TouchType.Down) {
+ if (event.type === TouchType.Down) {
this.isClickScreen = true;
this.clearTimer();
- } else if (event.type == TouchType.Up) {
+ } else if (event.type === TouchType.Up) {
this.setTimer();
- } else if (event.type == TouchType.Move) {
+ } else if (event.type === TouchType.Move) {
this.isClickScreen = true;
this.clearTimer();
}
@@ -308,14 +332,12 @@ struct Index {
.gesture(
LongPressGesture({ repeat: true })
.onAction(() => {
- this.avPlayerController.videoSpeedTwo();
- AppStorage.setOrCreate('speedName', $r('app.string.video_speed_2_0X'));
- AppStorage.setOrCreate('speedIndex', 3);
+ this.speedSelect = CASE_THREE
+ this.avPlayerController.videoSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X);
})
.onActionEnd(() => {
- this.avPlayerController.videoSpeedOne();
- AppStorage.setOrCreate('speedName', $r('app.string.video_speed_1_0X'));
- AppStorage.setOrCreate('speedIndex', 0);
+ this.speedSelect = CASE_ZERO
+ this.avPlayerController.videoSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X);
})
)
// [End long_press_gesture]
diff --git a/entry/src/main/ets/views/LanguageDialog.ets b/entry/src/main/ets/views/LanguageDialog.ets
new file mode 100644
index 0000000000000000000000000000000000000000..9fe6e4a1a385389e381724296401bf2b662e057e
--- /dev/null
+++ b/entry/src/main/ets/views/LanguageDialog.ets
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2025 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 { AvPlayerController } from '../controller/AvPlayerController';
+
+// Index of the playback rate list.
+const ONE = 1;
+
+/**
+ * Set language dialog
+ */
+@CustomDialog
+export struct LanguageDialog {
+ @State languageList: Resource[] =
+ [$r('app.string.Chinese'), $r('app.string.English')];
+ @Link @Watch('onLanguageSelectUpdate') languageSelect: number; // Index of the current selection
+ @StorageLink('avPlayerController') avPlayerController: AvPlayerController = new AvPlayerController();
+ private controller: CustomDialogController;
+
+ onLanguageSelectUpdate() {
+ AppStorage.setOrCreate('currentLanguageType', this.languageSelect);
+ }
+
+ build() {
+ Column() {
+ Text($r('app.string.language_switch'))
+ .fontSize($r('app.float.size_20'))
+ .fontWeight(FontWeight.Bold)
+ .width('90%')
+ .fontColor(Color.Black)
+ .textAlign(TextAlign.Center)
+ .margin({ top: $r('app.float.size_20'), bottom: $r('app.float.size_12') })
+
+ // [Start video_language_dialog]
+ List() {
+ ForEach(this.languageList, (item: Resource, index) => {
+ ListItem() {
+ Column() {
+ Row() {
+ Text(item)
+ // DocsDot
+ // [StartExclude text_style2]
+ .fontSize($r('app.float.size_16'))
+ .fontColor(Color.Black)
+ .fontWeight(FontWeight.Medium)
+ .textAlign(TextAlign.Center)
+ // [EndExclude text_style2]
+ // DocsDot
+ Blank()
+ Image(this.languageSelect === index ? $r('app.media.ic_radio_selected') :
+ $r('app.media.ic_radio'))
+ // DocsDot
+ // [StartExclude text_style3]
+ .width($r('app.float.size_24'))
+ .height($r('app.float.size_24'))
+ .objectFit(ImageFit.Contain)
+ // [EndExclude text_style3]
+ // DocsDot
+ }
+ // DocsDot
+ // [StartExclude text_style4]
+ .width('100%')
+
+ if (index != this.languageList.length - ONE) {
+ Divider()
+ .vertical(false)
+ .strokeWidth(1)
+ .margin({ top: $r('app.float.size_10') })
+ .color($r('app.color.speed_dialog'))
+ .width('100%')
+ }
+ // [EndExclude text_style4]
+ // DocsDot
+ }
+ .width('90%')
+ }
+ .width('100%')
+ .height($r('app.float.size_48'))
+ .onClick(() => {
+ this.languageSelect = index;
+ this.avPlayerController.languageChange(this.languageSelect);
+ this.controller.close();
+ })
+ }, (item: Resource, index) => index + '_' + JSON.stringify(item))
+ }
+
+ // [End video_language_dialog]
+ .width('100%')
+ .height('192vp')
+ .margin({
+ top: $r('app.float.size_12')
+ })
+
+ Row() {
+ Text($r('app.string.dialog_cancel'))
+ .fontSize($r('app.float.size_16'))
+ .fontColor('#0A59F7')
+ .fontWeight(FontWeight.Medium)
+ .layoutWeight(1)
+ .textAlign(TextAlign.Center)
+ .onClick(() => {
+ this.controller.close();
+ })
+ }
+ .alignItems(VerticalAlign.Center)
+ .height($r('app.float.size_50'))
+ .padding({ bottom: $r('app.float.size_5') })
+ .width('100%')
+
+ }
+ .alignItems(HorizontalAlign.Center)
+ .width('100%')
+ .margin({ left: $r('app.float.size_16'), right: $r('app.float.size_16') })
+ .borderRadius($r('app.float.size_24'))
+ .backgroundColor(Color.White)
+
+ }
+}
\ No newline at end of file
diff --git a/entry/src/main/ets/components/ScaleDialog.ets b/entry/src/main/ets/views/ScaleDialog.ets
similarity index 82%
rename from entry/src/main/ets/components/ScaleDialog.ets
rename to entry/src/main/ets/views/ScaleDialog.ets
index 0aacaa42dc004c939a4dfe492ddff032972d969a..91ff6a7230e9f7f24ac5fc63aab875a7d1ffced4 100644
--- a/entry/src/main/ets/components/ScaleDialog.ets
+++ b/entry/src/main/ets/views/ScaleDialog.ets
@@ -19,7 +19,6 @@ import { AvPlayerController } from '../controller/AvPlayerController';
const ZERO = 0;
const ONE = 1;
-// [Start window_scale_dialog]
/**
* Window scale dialog
*/
@@ -27,42 +26,52 @@ const ONE = 1;
export struct ScaleDialog {
@State scaleList: Resource[] =
[$r('app.string.video_scale_fit'), $r('app.string.video_scale_fit_crop')];
- @Link windowScaleSelect: number; // Index of the current selection
+ @Link @Watch('onWindowScaleSelectUpdate') windowScaleSelect: number; // Index of the current selection
@StorageLink('avPlayerController') avPlayerController: AvPlayerController = new AvPlayerController();
private controller: CustomDialogController;
+ onWindowScaleSelectUpdate() {
+ AppStorage.setOrCreate('videoScaleType', this.windowScaleSelect);
+ }
+
build() {
Column() {
- Text($r('app.string.dialog_play_scale'))// DocsDot
+ Text($r('app.string.dialog_play_scale'))
.fontSize($r('app.float.size_20'))
.fontWeight(FontWeight.Bold)
.width('90%')
.fontColor(Color.Black)
.textAlign(TextAlign.Center)
.margin({ top: $r('app.float.size_20'), bottom: $r('app.float.size_12') })
- // DocsDot
+ // [Start window_scale_dialog]
List() {
ForEach(this.scaleList, (item: Resource, index) => {
ListItem() {
Column() {
Row() {
- Text(item)// DocsDot
+ Text(item)
+ // DocsDot
+ // [StartExclude text_style2]
.fontSize($r('app.float.size_16'))
.fontColor(Color.Black)
.fontWeight(FontWeight.Medium)
.textAlign(TextAlign.Center)
+ // [EndExclude text_style2]
// DocsDot
Blank()
- Image(this.windowScaleSelect == index ? $r('app.media.ic_radio_selected') :
- $r('app.media.ic_radio'))// DocsDot
+ Image(this.windowScaleSelect === index ? $r('app.media.ic_radio_selected') :
+ $r('app.media.ic_radio'))
+ // DocsDot
+ // [StartExclude text_style3]
.width($r('app.float.size_24'))
.height($r('app.float.size_24'))
.objectFit(ImageFit.Contain)
+ // [EndExclude text_style3]
// DocsDot
}
// DocsDot
+ // [StartExclude text_style4]
.width('100%')
-
if (index != this.scaleList.length - ONE) {
Divider()
.vertical(false)
@@ -71,6 +80,7 @@ export struct ScaleDialog {
.color($r('app.color.speed_dialog'))
.width('100%')
}
+ // [EndExclude text_style4]
// DocsDot
}
.width('90%')
@@ -79,7 +89,6 @@ export struct ScaleDialog {
.height($r('app.float.size_48'))
.onClick(() => {
this.windowScaleSelect = index;
- AppStorage.setOrCreate('videoScaleType', this.windowScaleSelect);
switch (this.windowScaleSelect) {
case ZERO:
this.avPlayerController.videoScaleFit();
@@ -94,7 +103,7 @@ export struct ScaleDialog {
})
})
}
- // DocsDot
+ // [End window_scale_dialog]
.width('100%')
.height('192vp')
.margin({
@@ -116,18 +125,12 @@ export struct ScaleDialog {
.height($r('app.float.size_50'))
.padding({ bottom: $r('app.float.size_5') })
.width('100%')
-
- // DocsDot
}
- // DocsDot
.alignItems(HorizontalAlign.Center)
.width('100%')
.margin({ left: $r('app.float.size_16'), right: $r('app.float.size_16') })
.borderRadius($r('app.float.size_24'))
.backgroundColor(Color.White)
- // DocsDot
}
-}
-
-// [End window_scale_dialog]
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/entry/src/main/ets/components/SetVolume.ets b/entry/src/main/ets/views/SetVolume.ets
similarity index 100%
rename from entry/src/main/ets/components/SetVolume.ets
rename to entry/src/main/ets/views/SetVolume.ets
diff --git a/entry/src/main/ets/components/SpeedDialog.ets b/entry/src/main/ets/views/SpeedDialog.ets
similarity index 75%
rename from entry/src/main/ets/components/SpeedDialog.ets
rename to entry/src/main/ets/views/SpeedDialog.ets
index 98734eddd3fc11564f29c08a7293965bb00fb9b2..a97c3d59793efb76238b06aa9c2b8ce0ae141861 100644
--- a/entry/src/main/ets/components/SpeedDialog.ets
+++ b/entry/src/main/ets/views/SpeedDialog.ets
@@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+import { media } from '@kit.MediaKit';
import { AvPlayerController } from '../controller/AvPlayerController';
// Index of the playback rate list.
@@ -21,7 +21,6 @@ const ONE = 1;
const TWO = 2;
const THREE = 3;
-// [Start video_speed_dialog]
/**
* Set speed dialog
*/
@@ -30,41 +29,53 @@ export struct SpeedDialog {
@State speedList: Resource[] =
[$r('app.string.video_speed_1_0X'), $r('app.string.video_speed_1_25X'), $r('app.string.video_speed_1_75X'),
$r('app.string.video_speed_2_0X')];
- @Link speedSelect: number; // Index of the current selection
+ @Link @Watch('onSpeedSelectUpdate') speedSelect: number; // Index of the current selection
@StorageLink('avPlayerController') avPlayerController: AvPlayerController = new AvPlayerController();
private controller: CustomDialogController;
+ onSpeedSelectUpdate() {
+ AppStorage.setOrCreate('speedName', this.speedList[this.speedSelect]);
+ AppStorage.setOrCreate('speedIndex', this.speedSelect);
+ }
+
build() {
Column() {
- Text($r('app.string.dialog_play_speed'))// DocsDot
+ Text($r('app.string.dialog_play_speed'))
.fontSize($r('app.float.size_20'))
.fontWeight(FontWeight.Bold)
.width('90%')
.fontColor(Color.Black)
.textAlign(TextAlign.Center)
.margin({ top: $r('app.float.size_20'), bottom: $r('app.float.size_12') })
- // DocsDot
List() {
+ // [Start video_speed_dialog]
ForEach(this.speedList, (item: Resource, index) => {
ListItem() {
Column() {
Row() {
- Text(item)// DocsDot
+ Text(item)
+ // DocsDot
+ // [StartExclude text_style2]
.fontSize($r('app.float.size_16'))
.fontColor(Color.Black)
.fontWeight(FontWeight.Medium)
.textAlign(TextAlign.Center)
+ // [EndExclude text_style2]
// DocsDot
Blank()
- Image(this.speedSelect == index ? $r('app.media.ic_radio_selected') :
- $r('app.media.ic_radio'))// DocsDot
+ Image(this.speedSelect === index ? $r('app.media.ic_radio_selected') :
+ $r('app.media.ic_radio'))
+ // DocsDot
+ // [StartExclude text_style3]
.width($r('app.float.size_24'))
.height($r('app.float.size_24'))
.objectFit(ImageFit.Contain)
+ // [EndExclude text_style3]
// DocsDot
}
// DocsDot
+ // [StartExclude text_style4]
.width('100%')
if (index != this.speedList.length - ONE) {
@@ -75,6 +86,7 @@ export struct SpeedDialog {
.color($r('app.color.speed_dialog'))
.width('100%')
}
+ // [EndExclude text_style4]
// DocsDot
}
.width('90%')
@@ -83,20 +95,18 @@ export struct SpeedDialog {
.height($r('app.float.size_48'))
.onClick(() => {
this.speedSelect = index;
- AppStorage.setOrCreate('speedName', this.speedList[this.speedSelect]);
- AppStorage.setOrCreate('speedIndex', this.speedSelect);
switch (this.speedSelect) {
case ZERO:
- this.avPlayerController.videoSpeedOne();
+ this.avPlayerController.videoSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X);
break;
case ONE:
- this.avPlayerController.videoSpeedOnePointTwentyFive();
+ this.avPlayerController.videoSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_25_X);
break;
case TWO:
- this.avPlayerController.videoSpeedOnePointSeventyFive();
+ this.avPlayerController.videoSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_75_X);
break;
case THREE:
- this.avPlayerController.videoSpeedTwo();
+ this.avPlayerController.videoSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X);
break;
default:
break;
@@ -105,7 +115,7 @@ export struct SpeedDialog {
})
}, (item: Resource, index) => index + '_' + JSON.stringify(item))
}
- // DocsDot
+ // [End video_speed_dialog]
.width('100%')
.height('192vp')
.margin({
@@ -127,18 +137,12 @@ export struct SpeedDialog {
.height($r('app.float.size_50'))
.padding({ bottom: $r('app.float.size_5') })
.width('100%')
-
- // DocsDot
}
- // DocsDot
.alignItems(HorizontalAlign.Center)
.width('100%')
.margin({ left: $r('app.float.size_16'), right: $r('app.float.size_16') })
.borderRadius($r('app.float.size_24'))
.backgroundColor(Color.White)
- // DocsDot
}
-}
-
-// [End video_speed_dialog]
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/entry/src/main/ets/components/VideoOperate.ets b/entry/src/main/ets/views/VideoOperate.ets
similarity index 37%
rename from entry/src/main/ets/components/VideoOperate.ets
rename to entry/src/main/ets/views/VideoOperate.ets
index d5bb6a67681fad1fcda8a65563c0bf5e34eaa41b..715b82198bb968ae0366c0379d6be591b70775c4 100644
--- a/entry/src/main/ets/components/VideoOperate.ets
+++ b/entry/src/main/ets/views/VideoOperate.ets
@@ -16,13 +16,15 @@
import { media } from '@kit.MediaKit';
import { timeConvert } from '../common/utils/TimeUtils';
import { AvPlayerController } from '../controller/AvPlayerController';
-import { SpeedDialog } from '../components/SpeedDialog';
-import { ScaleDialog } from '../components/ScaleDialog';
+import { SpeedDialog } from './SpeedDialog';
+import { ScaleDialog } from './ScaleDialog';
+import { LanguageDialog } from './LanguageDialog';
@Component
export struct VideoOperate {
@State speedSelect: number = 0; // Speed Magnification Selection
- @State windowScaleSelect: number = 0;
+ @State windowScaleSelect: number = 0
+ @State languageSelect: number = 0
@Link currentTime: number;
@Link durationTime: number;
@Link isSwiping: boolean;
@@ -34,6 +36,7 @@ export struct VideoOperate {
@StorageLink('speedName') speedName: Resource = $r('app.string.video_speed_1_0X');
@StorageLink('isMuted') isMuted: boolean = false;
@StorageLink('videoScaleType') videoScaleType: number = media.VideoScaleType.VIDEO_SCALE_TYPE_FIT;
+ @StorageLink('currentLanguageType') currentLanguageType: number = 0;
private dialogController: CustomDialogController = new CustomDialogController({
builder: SpeedDialog({ speedSelect: $speedSelect }),
alignment: DialogAlignment.Center,
@@ -44,133 +47,167 @@ export struct VideoOperate {
alignment: DialogAlignment.Center,
offset: { dx: $r('app.float.size_zero'), dy: $r('app.float.size_down_20') }
});
+ private languageDialogController: CustomDialogController = new CustomDialogController({
+ builder: LanguageDialog({ languageSelect: $languageSelect }),
+ alignment: DialogAlignment.Center,
+ offset: { dx: $r('app.float.size_zero'), dy: $r('app.float.size_down_20') }
+ });
build() {
- Row() {
- Row() {
- Image(this.flag ? $r('app.media.ic_video_play') : $r('app.media.ic_video_pause'))// Play/Pause
- .id('play')
- .width($r('app.float.size_30'))
- .height($r('app.float.size_30'))
- .onClick(() => {
- this.flag ? this.avPlayerController.videoPause() : this.avPlayerController.videoPlay();
- this.flag = !this.flag;
- })
-
- // Left side time
- Text(timeConvert(this.currentTime))
- .fontColor(Color.White)
- .textAlign(TextAlign.End)
- .fontWeight(FontWeight.Regular)
- .margin({ left: $r('app.float.size_5') })
- }
-
+ Column(){
Row() {
- // [Start progress_slider]
+ // [Start video_language_switch_button]
/**
- * Progress slider
+ * Video Language switch
*/
- Slider({
- value: this.currentTime,
- min: 0,
- max: this.durationTime,
- style: SliderStyle.OutSet
+ Button() {
+ Image($r('app.media.ic_video_translate'))
+ .width($r('app.float.size_25'))
+ .height($r('app.float.size_25'))
+ }
+ .type(ButtonType.Normal)
+ .width($r('app.float.size_25'))
+ .height($r('app.float.size_25'))
+ .backgroundColor('rgba(0, 0, 0, 0)')
+ .margin({ left: $r('app.float.size_5') })
+ .fontColor(Color.White)
+ .onClick(() => {
+ this.languageSelect = this.currentLanguageType;
+ this.languageDialogController.open();
})
- .id('Slider')
- .blockColor(Color.White)
- .trackColor(Color.Gray)
- .selectedColor($r('app.color.slider_selected'))
- .showTips(false)
- .onChange((value: number, mode: SliderChangeMode) => {
- if (mode == SliderChangeMode.Begin) {
- this.isSwiping = true;
- this.avPlayerController.videoPause();
- }
- this.avPlayerController.videoSeek(value);
- this.currentTime = value;
- if (mode == SliderChangeMode.End) {
- this.isSwiping = false;
- this.flag = true;
- this.avPlayerController.videoPlay();
- }
- })
- // [End progress_slider]
+
+ // [End video_language_switch_button]
}
- .layoutWeight(1)
+ .width('100%')
+ .padding({ left: $r('app.float.size_12'), right: $r('app.float.size_20') })
+ .justifyContent(FlexAlign.End)
+
Row() {
- // Right side time
- Text(timeConvert(this.durationTime))
- .fontColor(Color.White)
- .fontWeight(FontWeight.Regular)
+ Row() {
+ Image(this.flag ? $r('app.media.ic_video_play') : $r('app.media.ic_video_pause'))// Play/Pause
+ .id('play')
+ .width($r('app.float.size_30'))
+ .height($r('app.float.size_30'))
+ .onClick(() => {
+ this.flag ? this.avPlayerController.videoPause() : this.avPlayerController.videoPlay();
+ this.flag = !this.flag;
+ })
+
+ // Left side time
+ Text(timeConvert(this.currentTime))
+ .fontColor(Color.White)
+ .textAlign(TextAlign.End)
+ .fontWeight(FontWeight.Regular)
+ .margin({ left: $r('app.float.size_5') })
+ }
+
+ Row() {
+ // [Start progress_slider]
+ /**
+ * Progress slider
+ */
+ Slider({
+ value: this.currentTime,
+ min: 0,
+ max: this.durationTime,
+ style: SliderStyle.OutSet
+ })
+ .id('Slider')
+ .blockColor(Color.White)
+ .trackColor(Color.Gray)
+ .selectedColor($r('app.color.slider_selected'))
+ .showTips(false)
+ .onChange((value: number, mode: SliderChangeMode) => {
+ if (mode === SliderChangeMode.Begin) {
+ this.isSwiping = true;
+ this.avPlayerController.videoPause();
+ }
+ this.avPlayerController.videoSeek(value);
+ this.currentTime = value;
+ if (mode === SliderChangeMode.End) {
+ this.isSwiping = false;
+ this.flag = true;
+ this.avPlayerController.videoPlay();
+ }
+ })
+ // [End progress_slider]
+ }
+ .layoutWeight(1)
+ Row() {
+ // Right side time
+ Text(timeConvert(this.durationTime))
+ .fontColor(Color.White)
+ .fontWeight(FontWeight.Regular)
+
+ // [Start video_speed_button]
+ Button(this.speedName, { type: ButtonType.Normal })
+ .border({ width: $r('app.float.size_1'), color: Color.White })
+ .width($r('app.float.size_64'))
+ .height($r('app.float.size_30'))
+ .fontSize($r('app.float.size_15'))
+ .borderRadius($r('app.float.size_20'))
+ .fontColor(Color.White)
+ .backgroundColor('rgba(0, 0, 0, 0)')
+ .opacity($r('app.float.size_1'))
+ .padding({ left: $r('app.float.size_5'), right: $r('app.float.size_5') })
+ .margin({ left: $r('app.float.size_8') })
+ .id('Speed')
+ .onClick(() => {
+ this.speedSelect = this.speedIndex;
+ this.dialogController.open();
+ })
+ // [End video_speed_button]
- // [Start video_speed_button]
- Button(this.speedName, { type: ButtonType.Normal })
- .border({ width: $r('app.float.size_1'), color: Color.White })
- .width($r('app.float.size_64'))
+ // [Start video_muted_button]
+ /**
+ * Video Muted Button
+ */
+ Button() {
+ Image(this.isMuted ? $r('app.media.ic_video_speaker_slash') : $r('app.media.ic_video_speaker'))
+ .width($r('app.float.size_30'))
+ .height($r('app.float.size_30'))
+ }
+ .type(ButtonType.Normal)
+ .width($r('app.float.size_30'))
.height($r('app.float.size_30'))
- .fontSize($r('app.float.size_15'))
.borderRadius($r('app.float.size_20'))
- .fontColor(Color.White)
.backgroundColor('rgba(0, 0, 0, 0)')
- .opacity($r('app.float.size_1'))
- .padding({ left: $r('app.float.size_5'), right: $r('app.float.size_5') })
- .margin({ left: $r('app.float.size_8') })
- .id('Speed')
+ .margin({ left: $r('app.float.size_5') })
+ .fontColor(Color.White)
.onClick(() => {
- this.speedSelect = this.speedIndex;
- this.dialogController.open();
+ this.isMuted = !this.isMuted;
+ this.avPlayerController.videoMuted(this.isMuted)
})
- // [End video_speed_button]
- // [Start video_muted_button]
- /**
- * Video Muted Button
- */
- Button() {
- Image(this.isMuted ? $r('app.media.ic_video_speaker_slash') : $r('app.media.ic_video_speaker'))
- .width($r('app.float.size_30'))
- .height($r('app.float.size_30'))
- }
- .type(ButtonType.Normal)
- .width($r('app.float.size_30'))
- .height($r('app.float.size_30'))
- .borderRadius($r('app.float.size_20'))
- .backgroundColor('rgba(0, 0, 0, 0)')
- .margin({ left: $r('app.float.size_5') })
- .fontColor(Color.White)
- .onClick(() => {
- this.isMuted = !this.isMuted;
- this.avPlayerController.videoMuted(this.isMuted)
- })
+ // [End video_muted_button]
- // [End video_muted_button]
+ // [Start window_scale_button]
+ /**
+ * Window scale button
+ */
+ Button() {
+ Image($r('app.media.ic_video_window_scale'))
+ .width($r('app.float.size_25'))
+ .height($r('app.float.size_25'))
+ }
+ .type(ButtonType.Normal)
+ .width($r('app.float.size_25'))
+ .height($r('app.float.size_25'))
+ .backgroundColor('rgba(0, 0, 0, 0)')
+ .margin({ left: $r('app.float.size_5') })
+ .fontColor(Color.White)
+ .onClick(() => {
+ this.windowScaleSelect = this.videoScaleType;
+ this.scaleDialogController.open();
+ })
- // [Start window_scale_button]
- /**
- * Window scale button
- */
- Button() {
- Image($r('app.media.ic_video_window_scale'))
- .width($r('app.float.size_25'))
- .height($r('app.float.size_25'))
+ // [End window_scale_button]
}
- .type(ButtonType.Normal)
- .width($r('app.float.size_25'))
- .height($r('app.float.size_25'))
- .backgroundColor('rgba(0, 0, 0, 0)')
- .margin({ left: $r('app.float.size_5') })
- .fontColor(Color.White)
- .onClick(() => {
- this.windowScaleSelect = this.videoScaleType;
- this.scaleDialogController.open();
- })
-
- // [End window_scale_button]
}
+ .justifyContent(FlexAlign.Center)
+ .padding({ left: $r('app.float.size_12'), right: $r('app.float.size_20') })
+ .width('100%')
}
- .justifyContent(FlexAlign.Center)
- .padding({ left: $r('app.float.size_12'), right: $r('app.float.size_20') })
- .width('100%')
}
}
\ No newline at end of file
diff --git a/entry/src/main/module.json5 b/entry/src/main/module.json5
index 5caa9363487d06748da71f11e89c384e975a1267..847fceb6c68f30a164b4f35acad31e4ec1733554 100644
--- a/entry/src/main/module.json5
+++ b/entry/src/main/module.json5
@@ -20,8 +20,7 @@
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
- "phone",
- "tablet"
+ "phone"
],
"deliveryWithInstall": true,
"installationFree": false,
diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json
index da436699c0ec274e7b58a4adae50012a3678cfac..83059752bdd5f7c8799c8d9994c2d3cf04c36221 100644
--- a/entry/src/main/resources/base/element/string.json
+++ b/entry/src/main/resources/base/element/string.json
@@ -79,7 +79,18 @@
{
"name": "local_video",
"value": "Local video"
+ },
+ {
+ "name": "Chinese",
+ "value": "Chinese"
+ },
+ {
+ "name": "English",
+ "value": "English"
+ },
+ {
+ "name": "language_switch",
+ "value": "Language switch"
}
-
]
}
\ No newline at end of file
diff --git a/entry/src/main/resources/base/media/background.png b/entry/src/main/resources/base/media/background.png
new file mode 100644
index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f
Binary files /dev/null and b/entry/src/main/resources/base/media/background.png differ
diff --git a/entry/src/main/resources/base/media/foreground.png b/entry/src/main/resources/base/media/foreground.png
new file mode 100644
index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f
Binary files /dev/null and b/entry/src/main/resources/base/media/foreground.png differ
diff --git a/entry/src/main/resources/base/media/ic_video_translate.svg b/entry/src/main/resources/base/media/ic_video_translate.svg
new file mode 100644
index 0000000000000000000000000000000000000000..907ba2997bc6abcf55a3303a3e3a23d1bf42c4d8
--- /dev/null
+++ b/entry/src/main/resources/base/media/ic_video_translate.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/entry/src/main/resources/base/media/layered_image.json b/entry/src/main/resources/base/media/layered_image.json
new file mode 100644
index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a
--- /dev/null
+++ b/entry/src/main/resources/base/media/layered_image.json
@@ -0,0 +1,7 @@
+{
+ "layered-image":
+ {
+ "background" : "$media:background",
+ "foreground" : "$media:foreground"
+ }
+}
\ No newline at end of file
diff --git a/entry/src/main/resources/en_US/element/string.json b/entry/src/main/resources/en_US/element/string.json
index c8388e9f3be5541020683c46c9426a95cc915289..8d5ec0fa074d19cbf56be3471ba6f2eff251022c 100644
--- a/entry/src/main/resources/en_US/element/string.json
+++ b/entry/src/main/resources/en_US/element/string.json
@@ -10,7 +10,7 @@
},
{
"name": "entryAbility_label",
- "value": "AVPlayer Basic Control"
+ "value": "AVPlayerBasicControl"
},
{
"name": "video_res_1",
@@ -79,6 +79,18 @@
{
"name": "local_video",
"value": "Local video"
+ },
+ {
+ "name": "Chinese",
+ "value": "Chinese"
+ },
+ {
+ "name": "English",
+ "value": "English"
+ },
+ {
+ "name": "language_switch",
+ "value": "Language switch"
}
]
}
\ No newline at end of file
diff --git a/entry/src/main/resources/rawfile/captions.srt b/entry/src/main/resources/rawfile/captions.srt
index 845591e72e763e2784736471d7b26dc907c9199f..9a17e648059285d09261cd86c36e1dcfbcc18629 100644
--- a/entry/src/main/resources/rawfile/captions.srt
+++ b/entry/src/main/resources/rawfile/captions.srt
@@ -1,47 +1,47 @@
1
-00:00:01,000 --> 00:00:03,000
+00:00:00,000 --> 00:00:01,000
360°立体天气动态展示
2
-00:00:03,000 --> 00:00:06,000
+00:00:01,000 --> 00:00:02,000
实时同步窗外真实气象
3
-00:00:07,000 --> 00:00:10,000
+00:00:02,000 --> 00:00:03,000
雷暴预警闪电特效提示
4
-00:00:10,000 --> 00:00:12,000
+00:00:03,000 --> 00:00:04,000
晨曦极光自动色调变换
5
-00:00:12,000 --> 00:00:14,000
+00:00:04,000 --> 00:00:05,000
指尖轻触触发季节音效
6
-00:00:14,000 --> 00:00:17,000
+00:00:05,000 --> 00:00:06,000
这是第一段比较长的字幕测试内容
7
-00:00:17,000 --> 00:00:20,000
+00:00:06,000 --> 00:00:07,000
这是第二段比较长的字幕测试内容
8
-00:00:20,000 --> 00:00:23,000
+00:00:07,000 --> 00:00:08,000
这是第三段比较长的字幕测试内容
9
-00:00:23,000 --> 00:00:26,000
+00:00:08,000 --> 00:00:09,000
这是第四段比较长的字幕测试内容
10
-00:00:26,000 --> 00:00:29,000
+00:00:09,000 --> 00:00:10,000
这是第五段比较长的字幕测试内容
11
-00:00:29,000 --> 00:00:32,000
+00:00:10,000 --> 00:00:11,000
这是第六段比较长的字幕测试内容
12
-00:00:32,000 --> 00:00:35,000
+00:00:11,000 --> 00:00:12,000
这是第七段比较长的字幕测试内容
\ No newline at end of file
diff --git a/entry/src/main/resources/rawfile/en_captions.srt b/entry/src/main/resources/rawfile/en_captions.srt
new file mode 100644
index 0000000000000000000000000000000000000000..0de4e872eb7f99848907ed59113fca1a5a8d1ce4
--- /dev/null
+++ b/entry/src/main/resources/rawfile/en_captions.srt
@@ -0,0 +1,47 @@
+1
+00:00:00,000 --> 00:00:01,000
+360° dynamic display of three-dimensional weather
+
+2
+00:00:01,000 --> 00:00:02,000
+Synchronize the real-time meteorological conditions outside the window
+
+3
+00:00:02,000 --> 00:00:03,000
+Thunderstorm warning: lightning effect prompt
+
+4
+00:00:03,000 --> 00:00:04,000
+Dawn Aurora Automatic Color Tone Transition
+
+5
+00:00:04,000 --> 00:00:05,000
+A light touch on the fingertip triggers seasonal sound effects
+
+6
+00:00:05,000 --> 00:00:06,000
+This is the first relatively long subtitle test content
+
+7
+00:00:06,000 --> 00:00:07,000
+This is the second relatively long subtitle test content
+
+8
+00:00:07,000 --> 00:00:08,000
+This is the third relatively long subtitle test content
+
+9
+00:00:08,000 --> 00:00:09,000
+This is the fourth relatively long subtitle test content
+
+10
+00:00:09,000 --> 00:00:10,000
+This is the fifth relatively long subtitle test content
+
+11
+00:00:10,000 --> 00:00:11,000
+This is the sixth relatively long subtitle test content
+
+12
+00:00:11,000 --> 00:00:12,000
+This is the seventh relatively long subtitle test content
\ No newline at end of file
diff --git a/entry/src/main/resources/zh_CN/element/string.json b/entry/src/main/resources/zh_CN/element/string.json
index 5654ae5cc6021df3de4c4ec7e810ceb7ea870fe9..b074e3c1f8485a02902532389c4f119f719268b6 100644
--- a/entry/src/main/resources/zh_CN/element/string.json
+++ b/entry/src/main/resources/zh_CN/element/string.json
@@ -79,6 +79,18 @@
{
"name": "local_video",
"value": "本地视频"
+ },
+ {
+ "name": "Chinese",
+ "value": "中文"
+ },
+ {
+ "name": "English",
+ "value": "英文"
+ },
+ {
+ "name": "language_switch",
+ "value": "语言切换"
}
]
}
\ No newline at end of file
diff --git a/hvigor/hvigor-config.json5 b/hvigor/hvigor-config.json5
index f70ecd4112d94f9aa555adf898d53f18bf58f3e9..5bebc9755447385d82ce4138f54d991b1f85f348 100644
--- a/hvigor/hvigor-config.json5
+++ b/hvigor/hvigor-config.json5
@@ -1,5 +1,22 @@
{
- "modelVersion": "5.0.0",
+ "modelVersion": "5.0.5",
"dependencies": {
+ },
+ "execution": {
+ // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */
+ // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
+ // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
+ // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
+ // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
+ },
+ "logging": {
+ // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
+ },
+ "debugging": {
+ // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
+ },
+ "nodeOptions": {
+ // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/
+ // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/
}
-}
\ No newline at end of file
+}
diff --git a/hvigorfile.ts b/hvigorfile.ts
index 6478186902c0c1ad7c966a929c7d6b7d8ae7a9f3..47113e2e36ecefde41c136272a0bd6ff745cffe4 100644
--- a/hvigorfile.ts
+++ b/hvigorfile.ts
@@ -1,2 +1,6 @@
-// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
-export { appTasks } from '@ohos/hvigor-ohos-plugin';
\ No newline at end of file
+import { appTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins: [] /* Custom plugin to extend the functionality of Hvigor. */
+}
\ No newline at end of file
diff --git a/oh-package.json5 b/oh-package.json5
index 77a997818065cdc56973d6bb556dea03eccf28ba..2d9c74ff34f1383ec920815a40399dd0fe46a6c5 100644
--- a/oh-package.json5
+++ b/oh-package.json5
@@ -1,11 +1,8 @@
{
- "modelVersion": "5.0.0",
- "license": "ISC",
- "devDependencies": {
+ "modelVersion": "5.0.5",
+ "description": "Please describe the basic information.",
+ "dependencies": {
},
- "name": "myvideo",
- "description": "example description",
- "repository": {},
- "version": "1.0.0",
- "dependencies": {}
-}
\ No newline at end of file
+ "devDependencies": {
+ }
+}
diff --git a/screenshots/devices/pause.png b/screenshots/devices/pause.png
index e61bc6095867189a81b71fac950fcf951862cf6b..86813701956bc38e2c419b398fb3b7ee6a4d2703 100644
Binary files a/screenshots/devices/pause.png and b/screenshots/devices/pause.png differ
diff --git a/screenshots/devices/playing.png b/screenshots/devices/playing.png
index 481b5fe0e4d123851ce2a8ad50d6166d401d5ff8..ed81fd38eb1d70d89c46ab5949cb6404f596aa03 100644
Binary files a/screenshots/devices/playing.png and b/screenshots/devices/playing.png differ
diff --git a/screenshots/devices/scale_fit.png b/screenshots/devices/scale_fit.png
index 6769279939028f0c2e8772060f554605fc4f971f..67b8a911244de0e2344b2ac587dffe03466fa275 100644
Binary files a/screenshots/devices/scale_fit.png and b/screenshots/devices/scale_fit.png differ
diff --git a/screenshots/devices/set_media_muted.png b/screenshots/devices/set_media_muted.png
index 8f0db4592c578f47154f6d15d2e2e896fe2f20c0..a4a94bc62cbe343948dd686d73e937525a004821 100644
Binary files a/screenshots/devices/set_media_muted.png and b/screenshots/devices/set_media_muted.png differ
diff --git a/screenshots/devices/set_volume.png b/screenshots/devices/set_volume.png
index b84ee4d88688ed5ad531b0cdcfa306253a515bc0..c11e3f332a78c94df518552da031d975d406fa2b 100644
Binary files a/screenshots/devices/set_volume.png and b/screenshots/devices/set_volume.png differ
diff --git a/screenshots/devices/speed_dialog.png b/screenshots/devices/speed_dialog.png
index 7c5c1e4d45e5da6655f9e71be3e64411fbd3ca5b..9845b501bcd6b66f3013b14438666e66a085b6ac 100644
Binary files a/screenshots/devices/speed_dialog.png and b/screenshots/devices/speed_dialog.png differ