diff --git a/Ability/PagesRouter/README.md b/Ability/PagesRouter/README.md index 545978236b792937f4aa064e1dcbfc3cd107a94c..bae83c10104c9a05be8527f4240be5c2ef7c8fb7 100644 --- a/Ability/PagesRouter/README.md +++ b/Ability/PagesRouter/README.md @@ -1,7 +1,9 @@ -# UIAbility内页面间的跳转(ArkTS) +# Ability内页面间的跳转(ArkTS) ## 介绍 -本篇Codelab基于Stage模型下的UIAbility开发,实现UIAbility内页面间的跳转和数据传递。最终效果图如图所示: +本篇Codelab基于Stage模型下的Ability开发,实现Ability内页面间的跳转和数据传递。 + +最终效果图如下: ![](figures/pageRouter.gif) @@ -13,13 +15,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -40,15 +42,17 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ └──constants -│ │ └──CommonConstants.ets // 公共常量类 +│ │ ├──constants +│ │ │ └──CommonConstants.ets // 公共常量类 +│ │ └──utils +│ │ └──Logger.ets // 日志类 │ ├──entryability -│ │ └──EntryAbility.ts // 程序入口类 +│ │ └──EntryAbility.ets // 程序入口类 │ └──pages │ ├──IndexPage.ets // 入口页面 │ └──SecondPage.ets // 跳转页 @@ -58,10 +62,11 @@ ## 页面跳转 -1. 在工程pages目录中,选中Index.ets,点击鼠标右键 \> Refactor \> Rename,改名为IndexPage.ets。改名后,修改工程entryability目录下EntryAbility.ts文件中windowStage.loadContent方法第一个参数为pages/IndexPage。 +1. 在工程pages目录中,选中Index.ets,点击鼠标右键 \> Refactor \> Rename,改名为IndexPage.ets。改名后,修改工程entryability目录下EntryAbility.ets文件中windowStage.loadContent方法第一个参数为pages/IndexPage。 ```typescript - onWindowStageCreate(windowStage: Window.WindowStage) { + // EntryAbility.ets + onWindowStageCreate(windowStage: Window.WindowStage): void { ... windowStage.loadContent('pages/IndexPage', (err, data) => { ... @@ -79,6 +84,7 @@ IndexPage页面有一个Text文本和Button按钮,点击按钮跳转到下一个页面,并传递数据。IndexPage.ets代码如下: ```typescript + // IndexPage.ets import router from '@ohos.router'; import CommonConstants from '../common/constants/CommonConstants'; @@ -101,8 +107,10 @@ params: { src: CommonConstants.SECOND_SRC_MSG } - }); - }) + }).catch((error: Error) => { + Logger.info(TAG, 'IndexPage push error' + JSON.stringify(error)); + }); + }) } ... } @@ -114,6 +122,7 @@ SecondPage页面有两个Text文本,其中一个文本展示从IndexPage页面传递过来的数据。SecondPage.ets代码如下: ```typescript + // SecondPage.ets import router from '@ohos.router'; import CommonConstants from '../common/constants/CommonConstants'; @@ -121,7 +130,7 @@ @Component struct Second { @State message: string = CommonConstants.SECOND_MESSAGE; - @State src: string = router.getParams()?.[CommonConstants.SECOND_SRC_PARAM]; + @State src: string = (router.getParams() as Record)[CommonConstants.SECOND_SRC_PARAM]; build() { Row() { @@ -142,6 +151,7 @@ 在SecondPage页面中,Button按钮添加onClick()事件。调用router.back()方法,实现返回上一页面的功能。 ```typescript +// SecondPage.ets Button($r('app.string.back')) ... .onClick(() => { @@ -152,6 +162,6 @@ Button($r('app.string.back')) 您已经完成了本次Codelab的学习,并了解到以下知识点: -1. 使用页面路由实现UIAbility内页面间的跳转。 +1. 使用页面路由实现应用内页面跳转。 ![](figures/summarize.gif) \ No newline at end of file diff --git a/Ability/PagesRouter/entry/src/main/ets/common/utils/Logger.ets b/Ability/PagesRouter/entry/src/main/ets/common/utils/Logger.ets index e10590ed49971df816ee2703aab860d022a9271b..2663be0e9ca448a777381cb04a176399ce4a1e4b 100644 --- a/Ability/PagesRouter/entry/src/main/ets/common/utils/Logger.ets +++ b/Ability/PagesRouter/entry/src/main/ets/common/utils/Logger.ets @@ -28,27 +28,27 @@ export class Logger { this.domain = 0xFF00; } - debug(...args: any[]) { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]) { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]) { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]) { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } - fatal(...args: any[]) { + fatal(...args: string[]): void { hilog.fatal(this.domain, this.prefix, this.format, args); } - isLoggable(level: number) { + isLoggable(level: number): void { hilog.isLoggable(this.domain, this.prefix, level); } } diff --git a/Ability/PagesRouter/entry/src/main/ets/entryability/EntryAbility.ets b/Ability/PagesRouter/entry/src/main/ets/entryability/EntryAbility.ets index 9a0462cbbebebc9703661c4849ef6134524559ec..c8d050e2c59b7952929d2855ddfe2a10a0f246fc 100644 --- a/Ability/PagesRouter/entry/src/main/ets/entryability/EntryAbility.ets +++ b/Ability/PagesRouter/entry/src/main/ets/entryability/EntryAbility.ets @@ -15,16 +15,19 @@ import UIAbility from '@ohos.app.ability.UIAbility' import Logger from '../common/utils/Logger'; +import Want from '@ohos.app.ability.Want'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; +import window from '@ohos.window'; const TAG = '[EntryAbility]'; export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { Logger.info(TAG, 'onCreate'); - globalThis.abilityWant = want; + AppStorage.SetOrCreate('abilityWant', want); } - onWindowStageCreate(windowStage) { + onWindowStageCreate(windowStage: window.WindowStage): void { // Main window is created, set main page for this ability Logger.info(TAG, 'onWindowStageCreate'); windowStage.loadContent('pages/IndexPage', (err, data) => { diff --git a/Ability/PagesRouter/entry/src/main/ets/pages/IndexPage.ets b/Ability/PagesRouter/entry/src/main/ets/pages/IndexPage.ets index b3594ed3653ea49dcff26ef9fbac7a177e49d0cf..9db7f87c812a762c575bbe952cd4ab7a4d7f4341 100644 --- a/Ability/PagesRouter/entry/src/main/ets/pages/IndexPage.ets +++ b/Ability/PagesRouter/entry/src/main/ets/pages/IndexPage.ets @@ -45,7 +45,7 @@ struct IndexPage { params: { src: CommonConstants.SECOND_SRC_MSG } - }).catch((error) => { + }).catch((error: Error) => { Logger.info(TAG, 'IndexPage push error' + JSON.stringify(error)); }); }) diff --git a/Ability/PagesRouter/entry/src/main/ets/pages/SecondPage.ets b/Ability/PagesRouter/entry/src/main/ets/pages/SecondPage.ets index ebfd09210e3cd5c56c335d0f8a6361224b4c8536..9ba02dd57197a9a78e7ae11962eed9342735b637 100644 --- a/Ability/PagesRouter/entry/src/main/ets/pages/SecondPage.ets +++ b/Ability/PagesRouter/entry/src/main/ets/pages/SecondPage.ets @@ -23,7 +23,7 @@ import CommonConstants from '../common/constants/CommonConstants'; @Component struct SecondPage { @State message: string = CommonConstants.SECOND_MESSAGE; - @State src: string = router.getParams()?.[CommonConstants.SECOND_SRC_PARAM]; + @State src: string = (router.getParams() as Record)[CommonConstants.SECOND_SRC_PARAM]; build() { Row() { diff --git a/Ability/PagesRouter/hvigor/hvigor-config.json5 b/Ability/PagesRouter/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/Ability/PagesRouter/hvigor/hvigor-config.json5 +++ b/Ability/PagesRouter/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/Ability/StageAbility/README.md b/Ability/StageAbility/README.md index 5da418522ae8f731af14e4a6dfce2d782edc5978..98d5062f7b7d675ccbf81726641e05224619c912 100644 --- a/Ability/StageAbility/README.md +++ b/Ability/StageAbility/README.md @@ -17,6 +17,7 @@ - [UIAbility组件概述](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/application-models/uiability-overview.md):UIAbility组件是一种包含UI界面的应用组件,主要用于和用户交互。UIAbility组件是系统调度的基本单元,为应用提供绘制界面的窗口。一个应用可以包含一个或多个UIAbility组件。 - [UIAbilityContext](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-inner-application-uiAbilityContext.md):UIAbilityContext是[UIAbility](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-app-ability-uiAbility.md)的上下文环境,继承自[Context](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-inner-application-context.md),提供UIAbility的相关配置信息以及操作UIAbility和ServiceExtensionAbility的方法。 - [页面路由](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-router.md):提供通过不同的url访问不同的页面,包括跳转到应用内的指定页面、用应用内的某个页面替换当前页面、返回上一页面或指定的页面等。 + - [Text](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-text.md):文本组件,用于呈现一段文本信息。 - [Button](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-button.md):按钮组件,可快速创建不同样式的按钮。 @@ -24,13 +25,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -53,30 +54,31 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──device/src/main/ets // device模块的代码区 │ ├──pages -│ │ ├──Index.ets // SecondAbility的Index页面 +│ │ ├──Index.ets // SecondAbility的Index页面 │ │ └──Second.ets // SecondAbility的Second页面 -│ └──secondability -│ └──SecondAbility.ts // 程序入口类 +│ ├──secondability +│ │ └──SecondAbility.ets // 程序入口类 ├──device/src/main/resources // device模块的资源文件目录 ├──entry/src/main/ets // entry模块的代码区 │ ├──common │ │ ├──constants │ │ │ ├──CommonConstants.ets // 公共常量类 -│ │ │ └──StyleConstants.ets // 样式常量类 -│ │ └──utils -│ │ └──Logger.ets // 日志打印类 +│ │ │ └──StyleConstants.ets // 样式常量类 +│ │ ├──utils +│ │ │ ├──GlobalContext.ets // 全局变量控制类 +│ │ │ └──Logger.ets // 日志打印类 │ ├──entryability │ │ └──EntryAbility.ts // 程序入口类 │ ├──model │ │ └──ButtonClickMethod.ets // 按钮点击后调用的方法类 -│ └──pages -│ ├──Index.ets // EntryAbility的Index页面 -│ └──Second.ets // EntryAbility的Second页面 +│ ├──pages +│ │ ├──Index.ets // EntryAbility的Index页面 +│ │ └──Second.ets // EntryAbility的Second页面 └──entry/src/main/resources // entry模块的资源文件目录 ``` @@ -183,8 +185,9 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 struct Second { ... // 获取Index页面传递过来的自定义参数 - @State src: string = router?.getParams()?.['src'] ?? '-'; - @State count: number = router?.getParams()?.['count'] ?? 0; + params = router?.getParams(); + @State src: string = this.params == undefined ? '-' : (this.params as Record)['src'] as string; + @State count: number = this.params == undefined ? 0 : (this.params as Record)['count'] as number; build() { Column() { @@ -222,7 +225,7 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 1. 在本章节中,实现跳转到指定UIAbility的首页,我们需要新建一个模块。在“Project”窗口,右键点击“entry 文件夹”,选择“New \> Module \> Empty Ability \> Next”,在“Module name”中给新建的模块命名为“device”,点击“Next”,在“Ability name”中给新建模块的Ability命名为“SecondAbility”,点击“Finish”。可以看到文件目录结构如下: - ![](figures/zh-cn_image_0000001407656688.png) + ![](figures/zh-cn_image_0000001682837654.png) 2. 构建SecondAbility的首页。在“Project”窗口,点击“device \> src \> main \> ets \> pages”,打开“Index.ets”文件,可以看到SecondAbility的Index页面由一个Image组件、两个Text组件、一个Button组件组成。“Index.ets”文件的示例代码如下: @@ -258,7 +261,7 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 ```typescript // 获取UIAbilityContext - let context = getContext(this); + let context = getContext(this) as common.UIAbilityContext; ``` >![](public_sys-resources/icon-note.gif) **说明:** 如果需要使用UIAbilityContext中的方法,需要在对应的页面获取相应的UIAbilityContext。 @@ -266,8 +269,8 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 ```typescript // 导航到SecondAbility的Index Page - toSecondAbilityIndex(context) { - let want = { + toSecondAbilityIndex(context: common.UIAbilityContext) { + let want: Want = { 'deviceId': '', 'bundleName': CommonConstants.BUNDLE_NAME, 'abilityName': CommonConstants.SECOND_ABILITY_NAME, @@ -279,8 +282,8 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 }; context.startAbility(want).then(() => { Logger.info(CommonConstants.TAG, `start second ability index page succeed with ${JSON.stringify(want)}`); - }).catch((error) => { - Logger.error(CommonConstants.TAG, `start second ability index page failedwith ${error.code}`); + }).catch((error: Error) => { + Logger.error(CommonConstants.TAG, `start second ability index page failedwith ${error}`); }); } ``` @@ -292,8 +295,9 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 @Component struct Index { // 获取从EntryAbility的Index页面传递过来的自定义参数 - @State src: string = globalThis?.secondAbilityWant?.parameters?.src ?? '-'; - @State count: number = globalThis?.secondAbilityWant?.parameters?.count ?? 0; + secondAbilityWant?: Want = GlobalContext.getContext().getObject('secondAbilityWant'); + @State src: string = this.secondAbilityWant?.parameters?.src as string ?? '-'; + @State count: number = this.secondAbilityWant?.parameters?.count as number ?? 0; build() { Column() { @@ -320,11 +324,11 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 ```typescript // 停止SecondAbility自身 - terminateSecondAbility(context) { + terminateSecondAbility(context: common.UIAbilityContext) { context.terminateSelf().then(() => { Logger.info(CommonConstants.TAG, 'terminate second ability self succeed'); - }).catch((error) => { - Logger.error(CommonConstants.TAG, `terminate second ability self failed with ${error.code}`); + }).catch((error: Error) => { + Logger.error(CommonConstants.TAG, `terminate second ability self failed with ${error}`); }); } ``` @@ -350,8 +354,9 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 @Component struct Second { // 用来接收parameters参数传过来的值 - @State src: string = globalThis?.secondAbilityWant?.parameters?.src ?? '-'; - @State count: number = globalThis?.secondAbilityWant?.parameters?.count ?? 0; + secondAbilityWant?: Want = GlobalContext.getContext().getObject('secondAbilityWant'); + @State src: string = this.secondAbilityWant?.parameters?.src as string ?? '-'; + @State count: number = this.secondAbilityWant?.parameters?.count as number ?? 0; build() { Column() { @@ -379,8 +384,8 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 ```typescript // 导航到SecondAbility的Second Page - toSecondAbilitySecond(context, callback) { - let want = { + toSecondAbilitySecond(context: common.UIAbilityContext, callback: (abilityResult: common.AbilityResult) => void) { + let want: Want = { 'deviceId': '', 'bundleName': CommonConstants.BUNDLE_NAME, 'abilityName': CommonConstants.SECOND_ABILITY_NAME, @@ -396,20 +401,20 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 context.startAbilityForResult(want).then((result) => { callback(result); Logger.info(CommonConstants.TAG, `start second ability second page succeed with ${JSON.stringify(want)}`); - }).catch((error) => { - Logger.error(CommonConstants.TAG, `start second ability second page failed with ${error.code}`); + }).catch((error: Error) => { + Logger.error(CommonConstants.TAG, `start second ability second page failed with ${error}`); }); } ``` - - 在“Project”窗口,点击“device \> src \> main \> ets \> SecondAbility”,打开“SecondAbility.ts”文件,在onWindowStageCreate的生命周期回调函数中获取拉起方的意图,展示SecondAbility的指定页面到界面。示例代码如下: + - 在“Project”窗口,点击“device \> src \> main \> ets \> SecondAbility”,打开“SecondAbility.ets”文件,在onWindowStageCreate的生命周期回调函数中获取拉起方的意图,展示SecondAbility的指定页面到界面。示例代码如下: ```typescript onWindowStageCreate(windowStage: Window.WindowStage) { ... - - let url = globalThis?.secondAbilityWant?.parameters?.url ? - globalThis.secondAbilityWant.parameters.url : 'pages/Index'; + let parameters: Record = (GlobalContext.getContext().getObject('secondAbilityWant') as Want)?.parameters as Record; + let url = parameters?.url ? + parameters.url as string : 'pages/Index'; windowStage.loadContent(url, (err, data) => { ... }); @@ -420,8 +425,8 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 ```typescript // 停止SecondAbility自身并返回结果 - terminateSecondAbilityForResult(context) { - let abilityResult = { + terminateSecondAbilityForResult(context: common.UIAbilityContext) { + let abilityResult: common.AbilityResult = { resultCode: CommonConstants.RESULT_CODE, want: { 'deviceId': '', @@ -439,9 +444,9 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 context.terminateSelfWithResult(abilityResult).then(() => { Logger.info(CommonConstants.TAG, `terminate second ability self with result succeed with ${JSON.stringify(abilityResult)}`); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.TAG, `terminate second ability self with - result failed with ${error.code}`); + result failed with ${error}`); }); } ``` @@ -456,4 +461,4 @@ entry模块中,EntryAbility内页面的跳转可以通过页面路由router来 4. 跳转到指定UIAbility的首页。 5. 跳转到指定UIAbility的指定页面(非首页)。 -![](figures/zh-cn_image_0000001458177569.gif) +![](figures/zh-cn_image_0000001458177569.gif) \ No newline at end of file diff --git a/Ability/StageAbility/device/src/main/ets/pages/Index.ets b/Ability/StageAbility/device/src/main/ets/pages/Index.ets index eadcfe18cd3dd81fd3089e16a9d6be8dc030e67e..c119195fe6a06510456e050c0a9c9b7801b88ccd 100644 --- a/Ability/StageAbility/device/src/main/ets/pages/Index.ets +++ b/Ability/StageAbility/device/src/main/ets/pages/Index.ets @@ -15,11 +15,14 @@ import ButtonClickMethod from '../../../../../entry/src/main/ets/model/ButtonClickMethod'; import StyleConstants from '../../../../../entry/src/main/ets/common/constants/StyleConstants'; +import common from '@ohos.app.ability.common'; +import Want from '@ohos.app.ability.Want'; +import { GlobalContext } from '../../../../../entry/src/main/ets/common/utils/GlobalContext' /** * Get context. */ -let context = getContext(this); +let context = getContext(this) as common.UIAbilityContext; /** * The Index Page of SecondAbility. @@ -27,8 +30,9 @@ let context = getContext(this); @Entry @Component struct Index { - @State src: string = globalThis?.secondAbilityWant?.parameters?.src ?? '-'; - @State count: number = globalThis?.secondAbilityWant?.parameters?.count ?? 0; + secondAbilityWant?: Want = GlobalContext.getContext().getObject('secondAbilityWant') + @State src: string = this.secondAbilityWant?.parameters?.src as string ?? '-'; + @State count: number = this.secondAbilityWant?.parameters?.count as number ?? 0; build() { Column() { diff --git a/Ability/StageAbility/device/src/main/ets/pages/Second.ets b/Ability/StageAbility/device/src/main/ets/pages/Second.ets index 1865fdc7b5cdbf4b84bdf3703a59352076340aa0..b5a30ee9cd6d5e32b89bf916c919f62a8e965bf4 100644 --- a/Ability/StageAbility/device/src/main/ets/pages/Second.ets +++ b/Ability/StageAbility/device/src/main/ets/pages/Second.ets @@ -15,11 +15,14 @@ import ButtonClickMethod from '../../../../../entry/src/main/ets/model/ButtonClickMethod'; import StyleConstants from '../../../../../entry/src/main/ets/common/constants/StyleConstants'; +import Want from '@ohos.app.ability.Want'; +import { GlobalContext } from '../../../../../entry/src/main/ets/common/utils/GlobalContext'; +import common from '@ohos.app.ability.common'; /** * Get context. */ -let context = getContext(this); +let context = getContext(this) as common.UIAbilityContext; /** * The Second Page of SecondAbility. @@ -27,8 +30,9 @@ let context = getContext(this); @Entry @Component struct Second { - @State src: string = globalThis?.secondAbilityWant?.parameters?.src ?? '-'; - @State count: number = globalThis?.secondAbilityWant?.parameters?.count ?? 0; + secondAbilityWant?: Want = GlobalContext.getContext().getObject('secondAbilityWant') + @State src: string = this.secondAbilityWant?.parameters?.src as string ?? '-'; + @State count: number = this.secondAbilityWant?.parameters?.count as number ?? 0; build() { Column() { diff --git a/Ability/StageAbility/device/src/main/ets/secondability/SecondAbility.ts b/Ability/StageAbility/device/src/main/ets/secondability/SecondAbility.ets similarity index 78% rename from Ability/StageAbility/device/src/main/ets/secondability/SecondAbility.ts rename to Ability/StageAbility/device/src/main/ets/secondability/SecondAbility.ets index 6beeeb054e435c2bd8ce6008d748048ea422c3f5..b1d37e2838f953a14e5283893d2f48d6fbb65881 100644 --- a/Ability/StageAbility/device/src/main/ets/secondability/SecondAbility.ts +++ b/Ability/StageAbility/device/src/main/ets/secondability/SecondAbility.ets @@ -1,14 +1,17 @@ import hilog from '@ohos.hilog'; import Ability from '@ohos.app.ability.UIAbility'; import Window from '@ohos.window'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; +import Want from '@ohos.app.ability.Want'; +import { GlobalContext } from '../../../../../entry/src/main/ets/common/utils/GlobalContext'; export default class SecondAbility extends Ability { - onCreate(want, launchParam) { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); - globalThis.secondAbilityWant = want; + GlobalContext.getContext().setObject("secondAbilityWant", want) } onDestroy() { @@ -20,9 +23,9 @@ export default class SecondAbility extends Ability { // Main window is created, set main page for this ability hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); - - let url = globalThis?.secondAbilityWant?.parameters?.url ? - globalThis.secondAbilityWant.parameters.url : 'pages/Index'; + let parameters: Record = (GlobalContext.getContext().getObject('secondAbilityWant') as Want)?.parameters as Record + let url = parameters?.url ? + parameters.url as string : 'pages/Index'; windowStage.loadContent(url, (err, data) => { if (err.code) { hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.ERROR); diff --git a/Ability/StageAbility/device/src/main/module.json5 b/Ability/StageAbility/device/src/main/module.json5 index ee666e1e51354e319462195c17626f12737bfd5c..713be423d21eb04c72fce9c1bd97ce42abcbc83e 100644 --- a/Ability/StageAbility/device/src/main/module.json5 +++ b/Ability/StageAbility/device/src/main/module.json5 @@ -19,7 +19,7 @@ "abilities": [ { "name": "SecondAbility", - "srcEntry": "./ets/secondability/SecondAbility.ts", + "srcEntry": "./ets/secondability/SecondAbility.ets", "description": "$string:SecondAbility_desc", "icon": "$media:icon", "label": "$string:SecondAbility_label", diff --git a/Ability/StageAbility/entry/src/main/ets/common/utils/GlobalContext.ets b/Ability/StageAbility/entry/src/main/ets/common/utils/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..677db0cb7cce13a483f076991499a50d7fcdae94 --- /dev/null +++ b/Ability/StageAbility/entry/src/main/ets/common/utils/GlobalContext.ets @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { } + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/Ability/StageAbility/entry/src/main/ets/common/utils/Logger.ets b/Ability/StageAbility/entry/src/main/ets/common/utils/Logger.ets index df4a9dd38d30a8016af547d7e2f936bc79d9bf18..7d81f6b35e1c71d779eb68b6b76bf42031e5ee3f 100644 --- a/Ability/StageAbility/entry/src/main/ets/common/utils/Logger.ets +++ b/Ability/StageAbility/entry/src/main/ets/common/utils/Logger.ets @@ -35,7 +35,7 @@ class Logger { * * @param args Indicates the log parameters. */ - debug(...args: any[]) { + debug(...args: string[]) { hilog.debug(this.domain, this.prefix, this.format, args); } @@ -44,7 +44,7 @@ class Logger { * * @param args Indicates the log parameters. */ - info(...args: any[]) { + info(...args: string[]) { hilog.info(this.domain, this.prefix, this.format, args); } @@ -53,7 +53,7 @@ class Logger { * * @param args Indicates the log parameters. */ - warn(...args: any[]) { + warn(...args: string[]) { hilog.warn(this.domain, this.prefix, this.format, args); } @@ -62,7 +62,7 @@ class Logger { * * @param args Indicates the log parameters. */ - error(...args: any[]) { + error(...args: string[]) { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Ability/StageAbility/entry/src/main/ets/model/ButtonClickMethod.ets b/Ability/StageAbility/entry/src/main/ets/model/ButtonClickMethod.ets index 50ee6b1e228990cd8a2a591dc5cd3a233e3ea7d1..e9e5bcf6239ae847f357adeda86b3d6f24555b44 100644 --- a/Ability/StageAbility/entry/src/main/ets/model/ButtonClickMethod.ets +++ b/Ability/StageAbility/entry/src/main/ets/model/ButtonClickMethod.ets @@ -16,6 +16,8 @@ import router from '@ohos.router'; import Logger from '../common/utils/Logger'; import CommonConstants from '../common/constants/CommonConstants'; +import Want from '@ohos.app.ability.Want'; +import common from '@ohos.app.ability.common'; /** * Get the context. @@ -46,8 +48,8 @@ class ButtonClickMethod { * * @param context Context of EntryAbility. */ - toSecondAbilityIndex(context) { - let want = { + toSecondAbilityIndex(context: common.UIAbilityContext) { + let want: Want = { 'deviceId': '', 'bundleName': CommonConstants.BUNDLE_NAME, 'abilityName': CommonConstants.SECOND_ABILITY_NAME, @@ -59,8 +61,8 @@ class ButtonClickMethod { }; context.startAbility(want).then(() => { Logger.info(CommonConstants.TAG, `start second ability index page succeed with ${JSON.stringify(want)}`); - }).catch((error) => { - Logger.error(CommonConstants.TAG, `start second ability index page failedwith ${error.code}`); + }).catch((error: Error) => { + Logger.error(CommonConstants.TAG, `start second ability index page failedwith ${error}`); }); } @@ -70,8 +72,8 @@ class ButtonClickMethod { * @param context Context of EntryAbility. * @param callback Execute the result callback function. */ - toSecondAbilitySecond(context, callback) { - let want = { + toSecondAbilitySecond(context: common.UIAbilityContext, callback: (abilityResult: common.AbilityResult) => void) { + let want: Want = { 'deviceId': '', 'bundleName': CommonConstants.BUNDLE_NAME, 'abilityName': CommonConstants.SECOND_ABILITY_NAME, @@ -91,8 +93,8 @@ class ButtonClickMethod { context.startAbilityForResult(want).then((result) => { callback(result); Logger.info(CommonConstants.TAG, `start second ability second page succeed with ${JSON.stringify(want)}`); - }).catch((error) => { - Logger.error(CommonConstants.TAG, `start second ability second page failed with ${error.code}`); + }).catch((error: Error) => { + Logger.error(CommonConstants.TAG, `start second ability second page failed with ${error}`); }); } @@ -101,11 +103,11 @@ class ButtonClickMethod { * * @param context Context of SecondAbility. */ - terminateSecondAbility(context) { + terminateSecondAbility(context: common.UIAbilityContext) { context.terminateSelf().then(() => { Logger.info(CommonConstants.TAG, 'terminate second ability self succeed'); - }).catch((error) => { - Logger.error(CommonConstants.TAG, `terminate second ability self failed with ${error.code}`); + }).catch((error: Error) => { + Logger.error(CommonConstants.TAG, `terminate second ability self failed with ${error}`); }); } @@ -114,8 +116,8 @@ class ButtonClickMethod { * * @param context Context of SecondAbility. */ - terminateSecondAbilityForResult(context) { - let abilityResult = { + terminateSecondAbilityForResult(context: common.UIAbilityContext) { + let abilityResult: common.AbilityResult = { resultCode: CommonConstants.RESULT_CODE, want: { 'deviceId': '', @@ -132,8 +134,8 @@ class ButtonClickMethod { // Stop SecondAbility itself and return abilityResult to the startAbilityForResult interface caller context.terminateSelfWithResult(abilityResult).then(() => { Logger.info(CommonConstants.TAG, `terminate second ability self succeed with ${JSON.stringify(abilityResult)}`); - }).catch((error) => { - Logger.error(CommonConstants.TAG, `terminate second ability self failed with ${error.code}`); + }).catch((error: Error) => { + Logger.error(CommonConstants.TAG, `terminate second ability self failed with ${error}`); }); } } diff --git a/Ability/StageAbility/entry/src/main/ets/pages/Index.ets b/Ability/StageAbility/entry/src/main/ets/pages/Index.ets index 4c8c17c4f7541e7c454a1b7aa93e036d99d6f8eb..4cc8e15ab488cbc0b5a1554cd20f3e75265dfab5 100644 --- a/Ability/StageAbility/entry/src/main/ets/pages/Index.ets +++ b/Ability/StageAbility/entry/src/main/ets/pages/Index.ets @@ -16,11 +16,12 @@ import ButtonClickMethod from '../model/ButtonClickMethod'; import StyleConstants from '../common/constants/StyleConstants'; import CommonConstants from '../common/constants/CommonConstants'; +import common from '@ohos.app.ability.common'; /** * Get context. */ -let context = getContext(this); +let context = getContext(this) as common.UIAbilityContext; /** * The Index Page of EntryAbility. @@ -95,8 +96,8 @@ struct Index { ButtonClickMethod.toSecondAbilitySecond(context, (abilityResult) => { // Obtain abilityResult passed on when SecondAbility is destroyed. if (abilityResult.resultCode === CommonConstants.RESULT_CODE) { - let src: string = abilityResult?.want?.parameters?.src ?? '-'; - let count: number = abilityResult?.want?.parameters?.count ?? 0; + let src: string = abilityResult?.want?.parameters?.src as string ?? '-'; + let count: number = abilityResult?.want?.parameters?.count as number ?? 0; this.text = `${src}:${count}`; this.bottomMargin = StyleConstants.BUTTON_MARGIN_BOTTOM; } diff --git a/Ability/StageAbility/entry/src/main/ets/pages/Second.ets b/Ability/StageAbility/entry/src/main/ets/pages/Second.ets index a55c64802f773a97c4b20797f492724aad28fcb8..1f6e64ba9d0e6e8d8a9b4dc4d8b17a2d8f3503a3 100644 --- a/Ability/StageAbility/entry/src/main/ets/pages/Second.ets +++ b/Ability/StageAbility/entry/src/main/ets/pages/Second.ets @@ -22,8 +22,9 @@ import StyleConstants from '../common/constants/StyleConstants'; @Entry @Component struct Second { - @State src: string = router?.getParams()?.['src'] ?? '-'; - @State count: number = router?.getParams()?.['count'] ?? 0; + params = router?.getParams() + @State src: string = this.params == undefined ? '-' : (this.params as Record)['src'] as string + @State count: number = this.params == undefined ? 0 : (this.params as Record)['count'] as number build() { Column() { diff --git a/Ability/StageAbility/figures/zh-cn_image_0000001407656688.png b/Ability/StageAbility/figures/zh-cn_image_0000001407656688.png deleted file mode 100644 index 03de03177313a16bf214144d1210480391bbeeff..0000000000000000000000000000000000000000 Binary files a/Ability/StageAbility/figures/zh-cn_image_0000001407656688.png and /dev/null differ diff --git a/Ability/StageAbility/figures/zh-cn_image_0000001682837654.png b/Ability/StageAbility/figures/zh-cn_image_0000001682837654.png new file mode 100644 index 0000000000000000000000000000000000000000..7955263d5fd85b6beec7643c04324be2bb1aa7a7 Binary files /dev/null and b/Ability/StageAbility/figures/zh-cn_image_0000001682837654.png differ diff --git a/Ability/StageAbility/hvigor/hvigor-config.json5 b/Ability/StageAbility/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/Ability/StageAbility/hvigor/hvigor-config.json5 +++ b/Ability/StageAbility/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/Ability/StageAbilityDemo/README.md b/Ability/StageAbilityDemo/README.md index ba3133b0c27cdf4368ea43050e39276982ef9271..a06406c78458acd517a947d706f99e24f847e909 100644 --- a/Ability/StageAbilityDemo/README.md +++ b/Ability/StageAbilityDemo/README.md @@ -1,13 +1,14 @@ # Stage模型下Ability的创建和使用(ArkTS) ## 介绍 -本篇Codelab基于Stage模型,对Ability的创建和使用进行讲解。首先在课程中我们将带领大家使用DevEco Studio创建一个Stage模型Ability,并使用AbilityContext启动另一个Ability,然后借助通信接口Want,在Ability之间传递参数,最后我们使用HiLog打印Ability的生命周期。效果图如下: +本篇Codelab基于Stage模型,对Ability的创建和使用进行讲解。首先在课程中我们将带领大家使用DevEco Studio创建一个Stage模型Ability,并使用UIAbilityContext启动另一个Ability,然后借助Want,在Ability之间传递参数,最后我们使用HiLog打印Ability的生命周期。效果如图所示: ![](figures/gif1.gif) ### 相关概念 - [UIAbility](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-app-ability-uiAbility.md):UIAbility组件是系统调度的基本单元,为应用提供绘制界面的窗口;一个UIAbility组件中可以通过多个页面来实现一个功能模块。每一个UIAbility组件实例,都对应于一个最近任务列表中的任务。 + - [UIAbilityContext](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-inner-application-uiAbilityContext.md):UIAbilityContext是UIAbility的上下文环境,继承自Context,提供UIAbility的相关配置信息以及操作UIAbility和ServiceExtensionAbility的方法,如启动UIAbility,停止当前UIAbilityContext所属的UIAbility,启动、停止、连接、断开连接ServiceExtensionAbility等。 - [Want](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-app-ability-want.md):Want是对象间信息传递的载体, 可以用于应用组件间的信息传递。 Want的使用场景之一是作为startAbility的参数, 其包含了指定的启动目标, 以及启动时需携带的相关数据。 - [HiLog](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-hilog.md):HiLog日志系统,让应用可以按照指定类型、指定级别、指定格式字符串输出日志内容,帮助开发者了解应用的运行状态,更好地调试程序。 @@ -16,13 +17,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -43,7 +44,7 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 │ ├──common // 公共资源目录 @@ -69,14 +70,17 @@ - 创建完Ability后,需要我们为Ability设置page页面,选中pages目录,单击鼠标右键,选择New \> Page,在对话框中修改名字后,即可创建相关的Page页面。示例代码如下: ```typescript + // DetailsPage.ets ... @Entry @Component struct DetailsPage { - private goodsDetails: GoodsData; + private goodsDetails: GoodsData = new GoodsData(); aboutToAppear() { - this.goodsDetails = viewModel.loadDetails(position); + if (position !== undefined) { + this.goodsDetails = viewModel.loadDetails(position); + } } build() { @@ -108,28 +112,29 @@ ``` -- 使用windowStage.loadContent为指定Ability设置相关的Page页面,由于配置流程一样,我们在这里只展示为DetailsAbility配置页面的核心代码: +- 使用windowStage.loadContent为指定Ability设置相关的Page页面,由于配置流程一样,我们在这里只展示为DetailsAbility配置页面的核心代码: - ```typescript - ... - export default class DetailsAbility extends Ability { - ... - onWindowStageCreate(windowStage) { - ... - windowStage.loadContent('pages/DetailsPage', (err, data) => { - if (err.code) { - hilog.error(DETAIL_ABILITY_DOMAIN, TAG, 'Failed. Cause: %{public}s', JSON.stringify(err) ?? ''); - return; - } - hilog.info(DETAIL_ABILITY_DOMAIN, TAG, 'Succeeded. Data: %{public}s', JSON.stringify(data) ?? ''); - }); + ```typescript + // DetailsAbility.ts + ... + export default class DetailsAbility extends UIAbility { + ... + onWindowStageCreate(windowStage: window.WindowStage): void { + ... + windowStage.loadContent('pages/DetailsPage', (err, data) => { + if (err.code) { + hilog.error(DETAIL_ABILITY_DOMAIN, TAG, 'Failed. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; } - ... - }; - ``` + hilog.info(DETAIL_ABILITY_DOMAIN, TAG, 'Succeeded. Data: %{public}s', JSON.stringify(data) ?? ''); + }); + } + ... + }; + ``` -界面效果: +效果如图所示: ![](figures/Screenshot_20221121111346864.png) @@ -142,6 +147,7 @@ UIAbilityContext是UIAbility的上下文环境,继承自Context,提供UIAbil 在购物应用中,我们点击首页商品列表中的某一项商品,即可跳转到商品的详情页面。此处使用到UIAbilityContext模块的启动Ability的能力。关于[获取UIAbilityContext的方法](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-inner-application-uiAbilityContext.md),推荐使用getContext(this)方式来获取UIAbilityContext。 ```typescript +// HomePage.ets ... build() { Column() { @@ -161,10 +167,11 @@ UIAbilityContext是UIAbility的上下文环境,继承自Context,提供UIAbil MenusComponent({ menus: this.menus }) // 商品列表组件 GoodsComponent({ goodsList: this.goodsList, startPage: (index) => { - let handler = getContext(this) as AppContext.AbilityContext; + let handler = getContext(this) as AppContext.UIAbilityContext; viewModel.startDetailsAbility(handler, index); } }) - }.width(PERCENTAGE_100) + } + .width(PERCENTAGE_100) } .height(PERCENTAGE_100) .backgroundImage($rawfile('index/index_background.png'), ImageRepeat.NoRepeat) @@ -176,11 +183,12 @@ UIAbilityContext是UIAbility的上下文环境,继承自Context,提供UIAbil startDetailsAbility方法调用了UIAbilityContext模块启动Ability的能力。 ```typescript +// HomeViewModel.ets ... - public startDetailsAbility(context, index: number): void { - const want = { - bundleName: 'com.example.StageAbilityDemo', - abilityName: 'DetailsAbility', + public startDetailsAbility(context: common.UIAbilityContext, index: number): void { + const want: Want = { + bundleName: getContext(context).applicationInfo.name, + abilityName: DETAILS_ABILITY_NAME, parameters: { position: index } @@ -202,20 +210,22 @@ startDetailsAbility方法调用了UIAbilityContext模块启动Ability的能力 在DetailsAbility中通过AppStorage来存储detailWant对象。 ```typescript +// DetailsAbility.ts ... -export default class DetailsAbility extends Ability { - onCreate(want, launchParam) { - let index: number = want?.parameters?.position; - AppStorage.SetOrCreate(KEY, index); - hilog.info(DETAIL_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onCreate'); - } - ... +export default class DetailsAbility extends UIAbility { + onCreate(want, launchParam): void { + let index: number = want?.parameters?.position; + AppStorage.SetOrCreate(KEY, index); + hilog.info(DETAIL_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onCreate'); + } + ... }; ``` 在对应的DetailsPage页面,使用AppStorage来获取detailWant对象,解析detailWant对象中的商品信息参数,调用loadDetails方法来展示商品详情。 ```typescript +// DetailsPage.ets ... let viewModel: DetailsViewModel = new DetailsViewModel(); const KEY: string = 'GoodsPosition'; @@ -224,16 +234,18 @@ let position = AppStorage.Get(KEY); @Entry @Component struct DetailsPage { - private goodsDetails: GoodsData; + private goodsDetails: GoodsData = new GoodsData(); aboutToAppear() { - this.goodsDetails = viewModel.loadDetails(position); + if (position !== undefined) { + this.goodsDetails = viewModel.loadDetails(position); + } } ... } ``` -最终实现效果如下: +效果如图所示: ![](figures/gif2.gif) @@ -253,14 +265,15 @@ HiLog提供了debug、info、warn、error以及fatal接口,在购物应用中 下面我们在EntryAbility中演示如何使用hilog对象打印Ability的生命周期函数 onBackground,代码如下: ```typescript +// EntryAbility.ts ... -export default class EntryAbility extends Ability { - ... - onBackground() { - // Ability has back to background - hilog.isLoggable(ENTRY_ABILITY_DOMAIN, TAG, hilog.LogLevel.INFO); - hilog.info(ENTRY_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onBackground'); - } +export default class EntryAbility extends UIAbility { + ... + onBackground(): void { + // Ability has back to background + hilog.isLoggable(ENTRY_ABILITY_DOMAIN, TAG, hilog.LogLevel.INFO); + hilog.info(ENTRY_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onBackground'); + } } ``` @@ -276,7 +289,3 @@ export default class EntryAbility extends Ability { 4. Ability相关生命周期函数的调用。 ![](figures/finished.gif) - - - - diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/DetailsAbility/DetailsAbility.ts b/Ability/StageAbilityDemo/entry/src/main/ets/DetailsAbility/DetailsAbility.ts index a6b5319bb8fbdc411a1fc206fc7584e3bc36bb5b..96cab921608aea0faec827547edf9a560c35d017 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/DetailsAbility/DetailsAbility.ts +++ b/Ability/StageAbilityDemo/entry/src/main/ets/DetailsAbility/DetailsAbility.ts @@ -15,23 +15,24 @@ import hilog from '@ohos.hilog'; import UIAbility from '@ohos.app.ability.UIAbility'; +import window from '@ohos.window'; const TAG: string = 'DetailsAbility'; const KEY: string = 'GoodsPosition'; const DETAIL_ABILITY_DOMAIN = 0x00002; export default class DetailsAbility extends UIAbility { - onCreate(want, launchParam) { + onCreate(want, launchParam): void { let index: number = want?.parameters?.position; AppStorage.SetOrCreate(KEY, index); hilog.info(DETAIL_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onCreate'); } - onDestroy() { + onDestroy(): void | Promise { hilog.info(DETAIL_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onDestroy'); } - onWindowStageCreate(windowStage) { + onWindowStageCreate(windowStage: window.WindowStage): void { // Main window is created, set main page for this ability hilog.info(0x0000, TAG, '%{public}s', 'Ability onWindowStageCreate'); @@ -44,17 +45,17 @@ export default class DetailsAbility extends UIAbility { }); } - onWindowStageDestroy() { + onWindowStageDestroy(): void { // Main window is destroyed, release UI related resources hilog.info(DETAIL_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onWindowStageDestroy'); } - onForeground() { + onForeground(): void { // Ability has brought to foreground hilog.info(DETAIL_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onForeground'); } - onBackground() { + onBackground(): void { // Ability has back to background hilog.info(DETAIL_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onBackground'); } diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/Constants.ets b/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/Constants.ets index 615d403b6e1141b6401ac17b8b109b3f7bf1dfb2..9b2fe58ef1ea68924c9f06a3d73dae57d67d2353 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/Constants.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/Constants.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -57,194 +57,179 @@ export const Text_Margin = 18; /** * The style of CardComponent. */ -export const CardStyle = { +export class CardStyle { /** * The horizontal margin of CardComponent. */ - CARD_MARGIN_HORIZONTAL: 16, + static readonly CARD_MARGIN_HORIZONTAL: number = 16; /** * The top margin of CardComponent. */ - CARD_MARGIN_TOP: 24, + static readonly CARD_MARGIN_TOP: number = 24; /** * The vertical padding of CardComponent. */ - CARD_PADDING_VERTICAL: 25, + static readonly CARD_PADDING_VERTICAL: number = 25; /** * The horizontal padding of CardComponent. */ - CARD_PADDING_HORIZONTAL: 16, + static readonly CARD_PADDING_HORIZONTAL: number = 16; /** * The border radius of CardComponent. */ - CARD_RADIUS: 18, + static readonly CARD_RADIUS: number = 18; }; /** * The style of BalanceComponent. */ -export const BalanceStyle = { +export class BalanceStyle { /** * The layout weight of BalanceComponent. */ - LAYOUT_WEIGHT: 1, + static readonly LAYOUT_WEIGHT: number = 1; }; /** * The style of ToolBarComponent. */ -export const ToolBarStyle = { +export class ToolBarStyle { /** * The bottom margin. */ - MARGIN_BOTTOM: 10, + static readonly MARGIN_BOTTOM: number = 10; /** * The size of image. */ - IMAGE_SIZE: 24, + static readonly IMAGE_SIZE: number = 24; /** * The weight of layout. */ - LAYOUT_WEIGHT: '25%', + static readonly LAYOUT_WEIGHT: string = '25%'; /** * The height of divider. */ - DIVIDER_HEIGHT: 0.5, + static readonly DIVIDER_HEIGHT: number = 0.5; /** * The opacity of divider. */ - DIVIDER_OPACITY: 0.05 + static readonly DIVIDER_OPACITY: number = 0.05; }; /** * The style of NavPage. */ -export const NavPageStyle = { +export class NavPageStyle { /** * The height of Tabs. */ - BAR_HEIGHT: 0, + static readonly BAR_HEIGHT: number = 0; /** * The default position of Tabs. */ - POSITION_INITIAL: 0, + static readonly POSITION_INITIAL: number = 0; }; /** * The style of HomePage. */ -export const HomePageStyle = { +export class HomePageStyle { /** * The vertical padding. */ - PADDING_VERTICAL: 8, + static readonly PADDING_VERTICAL: number = 8; /** * The horizontal padding. */ - PADDING_HORIZONTAL: 16, + static readonly PADDING_HORIZONTAL: number = 16; /** * The height of blank. */ - BLANK_HEIGHT: 15, + static readonly BLANK_HEIGHT: number = 15; }; /** * The style of DetailsPage. */ -export const DetailsPageStyle = { +export class DetailsPageStyle { /** * The size of top image. */ - TOP_IMAGE_SIZE: 32, + static readonly TOP_IMAGE_SIZE: number = 32; /** * The margin of top. */ - MARGIN_TOP_LAYOUT: 16, + static readonly MARGIN_TOP_LAYOUT: number = 16; /** * The top margin of title. */ - TITLE_MARGIN_TOP: 4, + static readonly TITLE_MARGIN_TOP: number = 4; /** * The bottom margin of title. */ - TITLE_MARGIN_BOTTOM: 20, + static readonly TITLE_MARGIN_BOTTOM: number = 20; /** * The height of divider. */ - DIVIDER_HEIGHT: 0.25, + static readonly DIVIDER_HEIGHT: number = 0.25; /** * The left margin of divider. */ - DIVIDER_MARGIN_LEFT: '12%', + static readonly DIVIDER_MARGIN_LEFT: string = '12%'; /** * The top margin of divider. */ - DIVIDER_MARGIN_TOP: 10, + static readonly DIVIDER_MARGIN_TOP: number = 10; /** * The bottom margin of divider. */ - DIVIDER_MARGIN_BOTTOM: 18, + static readonly DIVIDER_MARGIN_BOTTOM: number = 18; /** * The top margin of comment list. */ - COMMENT_LIST_MARGIN_TOP: 10, + static readonly COMMENT_LIST_MARGIN_TOP: number = 10; /** * The height of top layout. */ - TOP_LAYOUT_HEIGHT: '45%', + static readonly TOP_LAYOUT_HEIGHT: string = '45%'; /** * The height of scroll layout. */ - SCROLL_LAYOUT_WEIGHT: '93%', + static readonly SCROLL_LAYOUT_WEIGHT: string = '93%'; /** * The weight of tool bar layout. */ - TOOLBAR_WEIGHT: '7%', + static readonly TOOLBAR_WEIGHT: string = '7%'; /** * The image size for more action. */ - IMAGE_SIZE_MORE: 14 + static readonly IMAGE_SIZE_MORE: number = 14; }; /** * ability name. */ -export const DETAILS_ABILITY_NAME = 'DetailsAbility' - - - - - - - - - - - - - - - +export const DETAILS_ABILITY_NAME = 'DetailsAbility'; \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/DetailsConstants.ets b/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/DetailsConstants.ets index 2ea238ed5490bccb6e2446eb93b8937b130cd55e..e0993323ee8bd17ae1c558b0f945768344f35d03 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/DetailsConstants.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/DetailsConstants.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,364 +16,354 @@ /** * The constant of GoodsTitleComponent. */ -export const GoodsTitle = { +export class GoodsTitle { /** * The max lines of title text. */ - MAX_LINE: 2, + static readonly MAX_LINE: number = 2; /** * The line height of title text. */ - LINE_HEIGHT: 32, + static readonly LINE_HEIGHT: number = 32; }; /** * The constant of PanelComponent. */ -export const ActionPanel = { +export class ActionPanel { /** * The image height of PanelComponent. */ - IMAGE_HEIGHT: 18, + static readonly IMAGE_HEIGHT: number = 18; /** * The blank width of PanelComponent. */ - BLANK_WIDTH: 4, + static readonly BLANK_WIDTH: number = 4; }; /** * The constant of AddressComponent. */ -export const AddressPicker = { +export class AddressPicker { /** * The size of image to show loaction. */ - IMAGE_SIZE_LOCATION: 18, + static readonly IMAGE_SIZE_LOCATION: number = 18; /** * The image size for more operations. */ - IMAGE_SIZE_MORE: 14, + static readonly IMAGE_SIZE_MORE: number = 14; /** * The max lines. */ - MAX_LINES: 1, + static readonly MAX_LINES: number = 1; /** * The layout weight of left. */ - LAYOUT_WEIGHT_LEFT: '12%', + static readonly LAYOUT_WEIGHT_LEFT: string = '12%'; /** * The layout weight of center. */ - LAYOUT_WEIGHT_CENTER: '80%', + static readonly LAYOUT_WEIGHT_CENTER: string = '80%'; /** * The layout weight of right. */ - LAYOUT_WEIGHT_RIGHT: '8%', + static readonly LAYOUT_WEIGHT_RIGHT: string = '8%'; /** * The margin of right image. */ - MARGIN_RIGHT_IMAGE: '2%', + static readonly MARGIN_RIGHT_IMAGE: string = '2%'; }; /** * The constant of CommentsComponent. */ -export const CommentList = { +export class CommentList { /** * The space of List. */ - SPACE: 5, + static readonly SPACE: number = 5; /** * The image size of head portrait. */ - IMAGE_SIZE_HEAD_PORTRAIT: 45, + static readonly IMAGE_SIZE_HEAD_PORTRAIT: number = 45; /** * The margin of head portrait. */ - MARGIN_HEAD_PORTRAIT: 16, + static readonly MARGIN_HEAD_PORTRAIT: number = 16; /** * The line height of phone number text. */ - LINE_HEIGHT_PHONE: 32, + static readonly LINE_HEIGHT_PHONE: number = 32; /** * The blank height of phone number text. */ - BLANK_HEIGHT_PHONE: 6, + static readonly BLANK_HEIGHT_PHONE: number = 6; /** * The width of blank. */ - MARK_BLANK_WIDTH: 15, + static readonly MARK_BLANK_WIDTH: number = 15; /** * The width of image. */ - IMAGE_MARK_WIDTH: 20, + static readonly IMAGE_MARK_WIDTH: number = 20; /** * The max lines. */ - COMMENT_MAX_LINES: 1, + static readonly COMMENT_MAX_LINES: number = 1; /** * The line height. */ - COMMENT_LINE_HEIGHT: 26, + static readonly COMMENT_LINE_HEIGHT: number = 26; /** * The margin of text. */ - MARGIN_TEXT: 5, + static readonly MARGIN_TEXT: number = 5; /** * The height of List. */ - HEIGHT: '40%', + static readonly HEIGHT: string = '40%'; }; /** * The constant of CommentsHeaderComponent. */ -export const CommentHeader = { +export class CommentHeader { /** * The layout weight. */ - LAYOUT_WEIGHT: '50%', + static readonly LAYOUT_WEIGHT: string = '50%'; /** * The arrow text. */ - ARROW: ' >', + static readonly ARROW: string = ' >'; /** * The line height. */ - LINE_HEIGHT: 20, + static readonly LINE_HEIGHT: number = 20; }; /** * The constant of BottomBarComponent. */ -export const BottomBar = { +export class BottomBar { /** * The height of divider. */ - DIVIDER_HEIGHT: 0.5, + static readonly DIVIDER_HEIGHT: number = 0.5; /** * The line height of text. */ - TEXT_LINE_HEIGHT: 20, + static readonly TEXT_LINE_HEIGHT: number = 20; /** * The width of container. */ - CONTAINER_SIZE_WIDTH: 195, + static readonly CONTAINER_SIZE_WIDTH: number = 195; /** * The height of container. */ - CONTAINER_SIZE_HEIGHT: 40, + static readonly CONTAINER_SIZE_HEIGHT: number = 40; /** * The padding of right. */ - BAR_PADDING_RIGHT: 12, + static readonly BAR_PADDING_RIGHT: number = 12; /** * The padding of top. */ - BAR_PADDING_TOP: 9, + static readonly BAR_PADDING_TOP: number = 9; /** * The padding of bottom. */ - BAR_PADDING_BOTTOM: 7, + static readonly BAR_PADDING_BOTTOM: number = 7; /** * The width of text. */ - TEXT_WIDTH: '50%', + static readonly TEXT_WIDTH: string = '50%'; }; /** * The constant of PickerComponent. */ -export const GoodsPicker = { +export class GoodsPicker { /** * The line height of GoodsPicker text. */ - LINE_HEIGHT_TEXT_SELECTED: 25, + static readonly LINE_HEIGHT_TEXT_SELECTED: number = 25; /** * The max lines. */ - MAX_LINES: 2, + static readonly MAX_LINES: number = 2; /** * The lines height of description text. */ - LINE_HEIGHT_DESCRIPTION: 25, + static readonly LINE_HEIGHT_DESCRIPTION: number = 25; /** * The left margin of description text. */ - MARGIN_LEFT_DESCRIPTION: 15, + static readonly MARGIN_LEFT_DESCRIPTION: number = 15; /** * The left weight of layout. */ - LAYOUT_WEIGHT_LEFT: '10%', + static readonly LAYOUT_WEIGHT_LEFT: string = '10%'; /** * The center weight of layout. */ - LAYOUT_WEIGHT_CENTER: '80%', + static readonly LAYOUT_WEIGHT_CENTER: string = '80%'; /** * The right weight of layout. */ - LAYOUT_WEIGHT_RIGHT: '10%', + static readonly LAYOUT_WEIGHT_RIGHT: string = '10%'; }; /** * The constant of PreviewerComponent. */ -export const GoodsPreviewer = { +export class GoodsPreviewer { /** * The bottom padding of image. */ - PADDING_IMAGE_BOTTOM: 40, + static readonly PADDING_IMAGE_BOTTOM: number = 40; /** * The top padding of image. */ - PADDING_IMAGE_TOP: 20, + static readonly PADDING_IMAGE_TOP: number = 20; /** * The text of indicator. */ - INDICATOR_TEXT: '1/4', + static readonly INDICATOR_TEXT: string = '1/4'; /** * The right margin of indicator. */ - INDICATOR_MARGIN_RIGHT: 24, + static readonly INDICATOR_MARGIN_RIGHT: number = 24; /** * The bottom margin of indicator. */ - INDICATOR_MARGIN_BOTTOM: 17, + static readonly INDICATOR_MARGIN_BOTTOM: number = 17; /** * The horizontal padding of indicator. */ - INDICATOR_PADDING_HORIZONTAL: 10, + static readonly INDICATOR_PADDING_HORIZONTAL: number = 0; /** * The top padding of indicator. */ - INDICATOR_PADDING_TOP: 3, + static readonly INDICATOR_PADDING_TOP: number = 3; /** * The bottom padding of indicator. */ - INDICATOR_PADDING_BOTTOM: 2, + static readonly INDICATOR_PADDING_BOTTOM: number = 2; /** * The border radius. */ - BORDER_RADIUS: 9, + static readonly BORDER_RADIUS: number = 9; /** * The location text. */ - LOCATION: "86%", + static readonly LOCATION: string = "86%"; /** * The zIndex of layout. */ - INDEX: 2, + static readonly INDEX: number = 2; }; /** * The constant of ServiceItemComponent. */ -export const GoodsServiceItem = { +export class GoodsServiceItem { /** * The max lines of text. */ - MAX_LINES: 1, + static readonly MAX_LINES: number = 1; /** * The size of service image. */ - IMAGE_SIZE_SERVICE: 18, + static readonly IMAGE_SIZE_SERVICE: number = 18; /** * The size of more action image. */ - IMAGE_SIZE_MORE: 14, + static readonly IMAGE_SIZE_MORE: number = 14; /** * The layout weight of left. */ - LAYOUT_WEIGHT_LEFT: '12%', + static readonly LAYOUT_WEIGHT_LEFT: string = '12%'; /** * The layout weight of center. */ - LAYOUT_WEIGHT_CENTER: '80%', + static readonly LAYOUT_WEIGHT_CENTER: string = '80%'; /** * The layout weight of right. */ - LAYOUT_WEIGHT_RIGHT: '8%', + static readonly LAYOUT_WEIGHT_RIGHT: string = '8%'; /** * The right margin of image. */ - MARGIN_RIGHT_IMAGE: '2%', + static readonly MARGIN_RIGHT_IMAGE: string = '2%'; }; /** * The constant of ServicesComponent. */ -export const GoodsService = { +export class GoodsService { /** * The space of List. */ - SPACE: 20, + static readonly SPACE: number = 20; /** * The height of List. */ - LIST_HEIGHT: 94, -}; - - - - - - - - - - + static readonly LIST_HEIGHT: number = 94; +}; \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/HomeConstants.ets b/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/HomeConstants.ets index da3668783816ce84f66e67359fdfdc9c1a5aaef9..c805d05bb301d1412e1575f3c2bfbef10f3b4433 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/HomeConstants.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/common/constants/HomeConstants.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,283 +16,271 @@ /** * The constant of BannerComponent. */ -export const Banner = { +export class Banner { /** * The size of indicator. */ - INDICATOR_SIZE: 12, + static readonly INDICATOR_SIZE: number = 12; /** * The width of banner. */ - WIDTH: '93%', + static readonly WIDTH: string = '93%'; /** * The space of column. */ - SPACE: 5, + static readonly SPACE: number = 5; /** * The cache count of Swiper. */ - CACHE_COUNT: 2, + static readonly CACHE_COUNT: number = 2; /** * The default index of Swiper. */ - POSITION: 1, + static readonly POSITION: number = 1; /** * The interval time of Swiper. */ - TIME: 4000, + static readonly TIME: number = 4000; /** * The duration of Swiper. */ - DURATION: 1000, + static readonly DURATION: number = 1000; /** * The item space of Swiper. */ - ITEM_SPACE: 0 + static readonly ITEM_SPACE: number = 0; }; /** * The constant of GoodsComponent. */ -export const GoodsList = { +export class GoodsList { /** * The padding of grid. */ - GRID_PADDING: 12, + static readonly GRID_PADDING: number = 12; /** * The columnsGap of grid. */ - SPACE: 8, + static readonly SPACE: number = 8; /** * The layout direction of grid. */ - HORIZONTAL: 0, + static readonly HORIZONTAL: number = 0; /** * The columns template of grid. */ - GRID_STYLE: '1fr 1fr', + static readonly GRID_STYLE: string = '1fr 1fr'; }; /** * The constant of GoodsItemComponent. */ -export const GoodsListItem = { +export class GoodsListItem { /** * The container height of goods name. */ - CONTAINER_GOODS_NAME_HEIGHT: 40, + static readonly CONTAINER_GOODS_NAME_HEIGHT: number = 40; /** * The max line of goods name. */ - MAX_LINE_GOODS_NAME: 2, + static readonly MAX_LINE_GOODS_NAME: number = 2; /** * The margin of goods discounts. */ - MARGIN_DISCOUNTS: 5, + static readonly MARGIN_DISCOUNTS: number = 5; /** * The size of goods image. */ - GOODS_IMAGE_SIZE: 130, + static readonly GOODS_IMAGE_SIZE: number = 130; /** * The top margin of goods image. */ - GOODS_IMAGE_MARGIN_TOP: 10, + static readonly GOODS_IMAGE_MARGIN_TOP: number = 10; /** * The border radius of goods label. */ - BORDER_RADIUS_LABEL: 5, + static readonly BORDER_RADIUS_LABEL: number = 5; /** * The verical padding of goods label. */ - PADDING_LABEL_VERTICAL: 8, + static readonly PADDING_LABEL_VERTICAL: number = 8; /** * The horizontal padding of goods label. */ - PADDING_LABEL_HORIZONTAL: 2, + static readonly PADDING_LABEL_HORIZONTAL: number = 2; /** * The top margin of goods label container. */ - CONTAINER_LABEL_MARGIN_TOP: 6, + static readonly CONTAINER_LABEL_MARGIN_TOP: number = 6; /** * The bottom margin of goods label container. */ - CONTAINER_LABEL_MARGIN_BOTTOM: 12, + static readonly CONTAINER_LABEL_MARGIN_BOTTOM: number = 12; /** * The top margin of text container. */ - TEXT_LAYER_MARGIN_TOP: 20, + static readonly TEXT_LAYER_MARGIN_TOP: number = 20; /** * The width of text container. */ - TEXT_LAYER_WIDTH: "98%", + static readonly TEXT_LAYER_WIDTH: string = "98%"; /** * The horizontal padding of item. */ - ITEM_PADDING_HORIZONTAL: 10, + static readonly ITEM_PADDING_HORIZONTAL: number = 10; /** * The width of border. */ - BORDER_WIDTH: 1, + static readonly BORDER_WIDTH: number = 1; /** * The value of border radius. */ - BORDER_RADIUS: 10, + static readonly BORDER_RADIUS: number = 10; }; /** * The constant of TabsComponent. */ -export const GoodsTabs = { +export class GoodsTabs { /** * The height of GoodsTabs. */ - BAR_HEIGHT: 50, + static readonly BAR_HEIGHT: number = 50; /** * The default index of GoodsTabs. */ - TABVIEW_POSITION_INDEX_PAGE: 0, + static readonly TABVIEW_POSITION_INDEX_PAGE: number = 0; /** * The width of image. */ - IMAGE_SIZE_WIDTH: 12, + static readonly IMAGE_SIZE_WIDTH: number = 12; /** * The height of image. */ - IMAGE_SIZE_HEIGHT: 16, + static readonly IMAGE_SIZE_HEIGHT: number = 16; /** * The width of tab. */ - TAB_WIDTH: '90%', + static readonly TAB_WIDTH: string = '90%'; /** * The animation duration of Tabs. */ - TIME: 400, + static readonly TIME: number = 400; /** * The blank width of Tabs setting. */ - SETTING_BLANK_WIDTH: 4, + static readonly SETTING_BLANK_WIDTH: number = 4; /** * The layout weight of Tabs setting. */ - SETTING_LAYOUT: '10%', + static readonly SETTING_LAYOUT: string = '10%'; /** * The padding of right. */ - PADDING_RIGHT: '9%', + static readonly PADDING_RIGHT: string = '9%'; }; /** * The constant of MenusComponent. */ -export const Menus = { +export class Menus { /** * The vertical padding of container. */ - CONTAINER_PADDING_VERTICAL: 12, + static readonly CONTAINER_PADDING_VERTICAL: number = 12; /** * The vertical padding of item. */ - ITEM_PADDING_VERTICAL: 16, + static readonly ITEM_PADDING_VERTICAL: number = 16; /** * The weight of layout. */ - LAYOUT_WEIGHT: '25%', + static readonly LAYOUT_WEIGHT: string = '25%'; }; /** * The constant of SearchComponent. */ -export const SearchBar = { +export class SearchBar { /** * The width of layout. */ - WEIGHT: '90%', + static readonly WEIGHT: string = '90%'; /** * The size of image. */ - IMAGE_SIZE: 20, + static readonly IMAGE_SIZE: number = 20; /** * The height of SearchBar. */ - BAR_HEIGHT: 40, + static readonly BAR_HEIGHT: number = 40; /** * The right margin of input. */ - TEXT_INPUT_MARGIN_RIGHT: 20, + static readonly TEXT_INPUT_MARGIN_RIGHT: number = 20; /** * The left padding of container. */ - CONTAINER_PADDING_LEFT: 10, + static readonly CONTAINER_PADDING_LEFT: number = 10; /** * The border radius. */ - BORDER_RADIUS: 36, + static readonly BORDER_RADIUS: number = 36; }; /** * The constant of TopBarComponent. */ -export const TopBar = { +export class TopBar { /** * The size of image. */ - IMAGE_SIZE: 30, + static readonly IMAGE_SIZE: number = 30; /** * The height of BalanceComponent. */ - HEIGHT: '4%', -}; - - - - - - - - - - - - + static readonly HEIGHT: string = '4%'; +}; \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/entryability/EntryAbility.ts b/Ability/StageAbilityDemo/entry/src/main/ets/entryability/EntryAbility.ts index f91818dbe4ee30e0f76d15cfaed05241cb59168a..c7b7e10dad3ae3c7bb457573c77b8ce93f6d49c0 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/entryability/EntryAbility.ts +++ b/Ability/StageAbilityDemo/entry/src/main/ets/entryability/EntryAbility.ts @@ -15,25 +15,27 @@ import hilog from '@ohos.hilog'; import UIAbility from '@ohos.app.ability.UIAbility'; -import Window from '@ohos.window'; +import window from '@ohos.window'; +import Want from '@ohos.app.ability.Want'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; const TAG: string = 'EntryAbility'; const ENTRY_ABILITY_DOMAIN = 0x00001; export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { hilog.isLoggable(ENTRY_ABILITY_DOMAIN, TAG, hilog.LogLevel.INFO); hilog.info(ENTRY_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onCreate'); hilog.info(ENTRY_ABILITY_DOMAIN, TAG, '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); hilog.info(ENTRY_ABILITY_DOMAIN, TAG, '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); } - onDestroy() { + onDestroy(): void | Promise { hilog.isLoggable(ENTRY_ABILITY_DOMAIN, TAG, hilog.LogLevel.INFO); hilog.info(ENTRY_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onDestroy'); } - onWindowStageCreate(windowStage: Window.WindowStage) { + onWindowStageCreate(windowStage: window.WindowStage): void { // Main window is created, set main page for this ability hilog.isLoggable(ENTRY_ABILITY_DOMAIN, TAG, hilog.LogLevel.INFO); hilog.info(ENTRY_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onWindowStageCreate'); @@ -49,19 +51,19 @@ export default class EntryAbility extends UIAbility { }); } - onWindowStageDestroy() { + onWindowStageDestroy(): void { // Main window is destroyed, release UI related resources hilog.isLoggable(ENTRY_ABILITY_DOMAIN, TAG, hilog.LogLevel.INFO); hilog.info(ENTRY_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onWindowStageDestroy'); } - onForeground() { + onForeground(): void { // Ability has brought to foreground hilog.isLoggable(ENTRY_ABILITY_DOMAIN, TAG, hilog.LogLevel.INFO); hilog.info(ENTRY_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onForeground'); } - onBackground() { + onBackground(): void { // Ability has back to background hilog.isLoggable(ENTRY_ABILITY_DOMAIN, TAG, hilog.LogLevel.INFO); hilog.info(ENTRY_ABILITY_DOMAIN, TAG, '%{public}s', 'Ability onBackground'); diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/model/DataModel.ets b/Ability/StageAbilityDemo/entry/src/main/ets/model/DataModel.ets index f76b4562981bcbd6793a99af8dc6388bb6215783..c71437296c89374be8ad897f785e46e2a54ec541 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/model/DataModel.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/model/DataModel.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,11 +13,11 @@ * limitations under the License. */ -import BannerData from '../common/bean/BannerData'; -import MenuData from '../common/bean/MenuData'; -import GoodsData from '../common/bean/GoodsData'; -import ToolBarData from '../common/bean/ToolBarData'; -import GoodsServiceData from '../common/bean/GoodsServiceData'; +import BannerData from '../viewmodel/BannerData'; +import MenuData from '../viewmodel/MenuData'; +import GoodsData from '../viewmodel/GoodsData'; +import ToolBarData from '../viewmodel/ToolBarData'; +import GoodsServiceData from '../viewmodel/GoodsServiceData'; /* * The DataModel file instead of network data. @@ -38,6 +38,9 @@ export default class DataModel { }, { imgSrc: $rawfile('index/banner2.png') + }, + { + imgSrc: $rawfile('index/banner3.png') } ]; public static readonly HOME_MENU: MenuData[] = [ @@ -129,5 +132,4 @@ export default class DataModel { description: $r('app.string.goods_service_3_desc') } ]; -} - +} \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/pages/DetailsPage.ets b/Ability/StageAbilityDemo/entry/src/main/ets/pages/DetailsPage.ets index b88088c9f44f708bb60f5f5505ed39a72dac0234..98967d2e5124d2155d2d45ddd38237e3d91dedbc 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/pages/DetailsPage.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/pages/DetailsPage.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -27,7 +27,7 @@ import ServicesComponent from '../view/details/ServicesComponent'; import BalanceComponent from '../view/BalanceComponent'; import CardComponent from '../view/CardComponent'; import PreviewerComponent from '../view/details/PreviewerComponent'; -import GoodsData from '../common/bean/GoodsData'; +import GoodsData from '../viewmodel/GoodsData'; import DetailsViewModel from '../viewmodel/DetailsViewModel'; let viewModel: DetailsViewModel = new DetailsViewModel(); @@ -42,10 +42,12 @@ let position = AppStorage.Get(KEY); @Entry @Component struct DetailsPage { - private goodsDetails: GoodsData; + private goodsDetails: GoodsData = new GoodsData(); aboutToAppear() { - this.goodsDetails = viewModel.loadDetails(position); + if (position !== undefined) { + this.goodsDetails = viewModel.loadDetails(position); + } } onBackPress() { @@ -93,7 +95,7 @@ struct DetailsPage { } @Builder TopBarLayout() { - BalanceComponent({ left: this.BackLayout(), right: this.ShareLayout() }) + BalanceComponent({ left: this.BackLayout, right: this.ShareLayout }) .width(PERCENTAGE_100) .padding(DetailsPageStyle.MARGIN_TOP_LAYOUT) } diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/pages/NavPage.ets b/Ability/StageAbilityDemo/entry/src/main/ets/pages/NavPage.ets index 2e06cec96ab563fbbd2a9b6ee79dafc1367d4747..8244720eb32a75558e6d2d36e17642e1c9271348 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/pages/NavPage.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/pages/NavPage.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,7 +15,7 @@ import HomePage from '../view/home/HomePage'; import NavViewModel from '../viewmodel/NavViewModel'; -import ToolBarData from '../common/bean/ToolBarData'; +import ToolBarData from '../viewmodel/ToolBarData'; import ToolBarComponent from '../view/ToolBarComponent'; import { AppFontSize, NavPageStyle, PERCENTAGE_100 } from '../common/constants/Constants'; @@ -47,7 +47,7 @@ struct NavPage { build() { Navigation() { Tabs({ barPosition: BarPosition.Start, controller: this.controller }) { - ForEach(this.toolBarConfigs, (item: ToolBarData, index) => { + ForEach(this.toolBarConfigs, (item: ToolBarData, index?: number) => { TabContent() { if (index === HOME) { HomePage() @@ -55,7 +55,7 @@ struct NavPage { this.HolderPage(item?.text) } } - }, item => JSON.stringify(item)) + }, (item: ToolBarData) => JSON.stringify(item)) }.setTabStyle() } .toolBar(this.ToolBarBuilder()) @@ -82,4 +82,4 @@ struct NavPage { .textAlign(TextAlign.Center) }.justifyContent(FlexAlign.Center) } -} +} \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/BalanceComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/BalanceComponent.ets index 58c48b228227d615189ea2acdd0865a037b7d846..3c820df573b30bcf32ff4ef52b679f82f6af5cb2 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/BalanceComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/BalanceComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,13 +17,13 @@ import { BalanceStyle } from '../common/constants/Constants'; /* * BalanceComponent - * right: The right component align start. + * right: The right component align start. * left: The left component align end. */ @Component export default struct BalanceComponent { - @BuilderParam right: any; - @BuilderParam left: any; + @BuilderParam right: () => void = () => {}; + @BuilderParam left: () => void = () => {}; build() { Row() { @@ -38,7 +38,6 @@ export default struct BalanceComponent { } .layoutWeight(BalanceStyle.LAYOUT_WEIGHT) .justifyContent(FlexAlign.End) - } } } \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/CardComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/CardComponent.ets index 9c17fd2e3d3652c4ec59c61b5a77884771f69b23..6fb4f461ba71d47e00fdc7506d271f99da9749c2 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/CardComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/CardComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -20,11 +20,20 @@ import { CardStyle } from '../common/constants/Constants'; */ @Component export default struct CardComponent { - @BuilderParam children: () => void; - paddingValue: Padding | Length; - marginValue: Margin | Length; - colorValue: ResourceColor; - radiusValue: Length; + @BuilderParam children: () => void = () => {}; + paddingValue: Padding | Length = { + top: CardStyle.CARD_PADDING_VERTICAL, + bottom: CardStyle.CARD_PADDING_VERTICAL, + left: CardStyle.CARD_PADDING_HORIZONTAL, + right: CardStyle.CARD_PADDING_HORIZONTAL + }; + marginValue: Margin | Length = { + top: CardStyle.CARD_MARGIN_TOP, + left: CardStyle.CARD_MARGIN_HORIZONTAL, + right: CardStyle.CARD_MARGIN_HORIZONTAL + }; + colorValue: ResourceColor = $r('app.color.background1'); + radiusValue: Length = CardStyle.CARD_RADIUS; build() { Column() { diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/ToolBarComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/ToolBarComponent.ets index 193ed9489383a380675ab92c66b727c689b89196..5fe6f01c9a7b4d5a58e94908fae72b4c6b3e45c9 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/ToolBarComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/ToolBarComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,15 +13,15 @@ * limitations under the License. */ -import ToolBarData from '../common/bean/ToolBarData'; +import ToolBarData from '../viewmodel/ToolBarData'; import { AppFontSize, AppFontWeight, PERCENTAGE_100, ToolBarStyle } from '../common/constants/Constants'; import { NavPageStyle } from '../common/constants/Constants'; @Component export default struct ToolBarComponent { @State navCurrentPosition: number = NavPageStyle.POSITION_INITIAL; - toolBarConfigs: ToolBarData[]; - controller: TabsController; + toolBarConfigs: ToolBarData[] = []; + controller: TabsController = new TabsController(); build() { Column() { @@ -30,7 +30,7 @@ export default struct ToolBarComponent { .height(ToolBarStyle.DIVIDER_HEIGHT) .opacity(ToolBarStyle.DIVIDER_OPACITY) Row() { - ForEach(this.toolBarConfigs, (item, index) => { + ForEach(this.toolBarConfigs, (item: ToolBarData, index?: number) => { Column() { Image(this.navCurrentPosition === index ? item?.icon_after : item?.icon) .height(ToolBarStyle.IMAGE_SIZE) @@ -47,9 +47,8 @@ export default struct ToolBarComponent { this.navCurrentPosition = item.num this.controller.changeIndex(this.navCurrentPosition) }) - }, item => JSON.stringify(item)) + }, (item: ToolBarData) => JSON.stringify(item)) } } } -} - +} \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/AddressComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/AddressComponent.ets index f757188e021f043323b334edca0b75ec091c5068..77a822b78ea0bb1d97476a14058ceee253960d06 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/AddressComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/AddressComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/BottomBarComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/BottomBarComponent.ets index d7067809d1fb908cf4850af5c8ac99dea0b5829d..ae375e4e350c735f2b8058130eaf2b03c90a7967 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/BottomBarComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/BottomBarComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -26,7 +26,7 @@ import { BottomBar } from '../../common/constants/DetailsConstants'; @Component export default struct BottomBarComponent { - private barHeight: Length; + private barHeight: Length = '100%'; build() { Column() { diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/CommentsComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/CommentsComponent.ets index 225d006a70a0f9afc326967bdc16adc6eabfc7b7..51aabd5ada658eab9e343863780c72fb1a9ec6fb 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/CommentsComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/CommentsComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/CommentsHeaderComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/CommentsHeaderComponent.ets index 8b83dcdf6a6d4ad586671d6c7c70108a7b0cdf05..5b0d682730ec218304d883cb2fcf69bb011352f4 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/CommentsHeaderComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/CommentsHeaderComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/GoodsTitleComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/GoodsTitleComponent.ets index 4c3559f7c1f5c56dcc6a0341f919ec4d25b0d5e2..f4169e2488f9401535ed0fc1c78c69a0b0449731 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/GoodsTitleComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/GoodsTitleComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -18,7 +18,7 @@ import { GoodsTitle } from '../../common/constants/DetailsConstants'; @Component export default struct GoodsTitleComponent { - private title: Resource + private title: Resource = $r('app.string.goods_list_item_1'); build() { Column() { diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PanelComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PanelComponent.ets index 9d78c22eff2d84d4f55e2a2b15770a590521db7c..55c8836aa8b46d8e57892e78cc23d6f281025b84 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PanelComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PanelComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PickerComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PickerComponent.ets index 2e695fbfeda5bb3e84168eb21bc2f08412e873d4..6964b74b664cea92f78880f318c30bc421cfccf6 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PickerComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PickerComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -18,8 +18,8 @@ import { GoodsPicker } from '../../common/constants/DetailsConstants'; @Component export default struct PickerComponent { - private goodsDescription: string | Resource - @BuilderParam actionMoreBuilder: () => void; + private goodsDescription: string | Resource = '' + @BuilderParam actionMoreBuilder: () => void = () => {}; build() { Row() { diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PreviewerComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PreviewerComponent.ets index 6b7c20336efa6775eb0c5929340a3777736a6666..05612c79a5194c228c0c839ababbfc3292207679 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PreviewerComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PreviewerComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -18,7 +18,7 @@ import { GoodsPreviewer } from '../../common/constants/DetailsConstants'; @Component export default struct PreviewerComponent { - goodsImg: string | Resource; + goodsImg: string | Resource = ''; build() { Column() { diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PriceComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PriceComponent.ets index 9c8184c078489a34dddc2af4ba3e381d64418dda..9c23c04e930127c6a08bb8d2d1fc2440e132ad03 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PriceComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/PriceComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,7 +17,7 @@ import { AppFontSize, AppFontWeight, PERCENTAGE_100 } from '../../common/constan @Component export default struct PriceComponent { - private price: string + private price: string = ''; build() { Column() { diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/ServiceItemComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/ServiceItemComponent.ets index 9700882b649b727353f90519517bfdf38c3a9d04..371d356ae4db2cd4d1e4c089537005abbbfdba86 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/ServiceItemComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/ServiceItemComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -18,9 +18,9 @@ import { GoodsServiceItem } from '../../common/constants/DetailsConstants'; @Component export default struct ServiceItemComponent { - serviceName: string; - description: string; - isShowActionMore: boolean; + serviceName?: Resource | null; + description?: Resource; + isShowActionMore?: boolean = false; build() { Row() { diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/ServicesComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/ServicesComponent.ets index fc0386634e038110228c71d1bd2fea3f55a1d1f1..fcb0632030c7609be52fcef990ca0e7fe726db88 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/details/ServicesComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/details/ServicesComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,7 +15,7 @@ import ServiceItemComponent from './ServiceItemComponent'; import ServicesViewModel from '../../viewmodel/ServicesViewModel'; -import GoodsServiceData from '../../common/bean/GoodsServiceData'; +import GoodsServiceData from '../../viewmodel/GoodsServiceData'; import { PERCENTAGE_100 } from '../../common/constants/Constants'; import { GoodsService } from '../../common/constants/DetailsConstants'; @@ -30,7 +30,7 @@ export default struct ServicesComponent { build() { List({ space: GoodsService.SPACE }) { - ForEach(goodsServiceList, (item) => { + ForEach(goodsServiceList, (item: GoodsServiceData) => { ListItem() { ServiceItemComponent({ serviceName: item?.name, @@ -38,7 +38,7 @@ export default struct ServicesComponent { isShowActionMore: item?.name != null }) } - }, item => JSON.stringify(item)) + }, (item: GoodsServiceData) => JSON.stringify(item)) } .width(PERCENTAGE_100) diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/BannerComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/BannerComponent.ets index b256aed96de524915dfbd377c9b01851e98d736a..870f82f2df1b88c0ec78b7bd10eb720c37fcc66c 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/BannerComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/BannerComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,22 +13,22 @@ * limitations under the License. */ -import BannerData from '../../common/bean/BannerData'; +import BannerData from '../../viewmodel/BannerData'; import { Banner } from '../../common/constants/HomeConstants'; import { PERCENTAGE_100, PERCENTAGE_20 } from '../../common/constants/Constants'; @Component export default struct BannerComponent { - bannerList: BannerData[]; + bannerList: BannerData[] = []; build() { Column({ space: Banner.SPACE }) { Swiper() { - ForEach(this.bannerList, (item) => { + ForEach(this.bannerList, (item: BannerData) => { Image(item.imgSrc) .width(PERCENTAGE_100) .objectFit(ImageFit.Contain) - }, item => JSON.stringify(item)) + }, (item: BannerData) => JSON.stringify(item)) } .cachedCount(Banner.CACHE_COUNT) .index(Banner.POSITION) diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/GoodsComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/GoodsComponent.ets index 831e286bee23202cd7c66d72c89321cfb2862d56..fcf461910c57bcc875c78bb145beed0d75231d80 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/GoodsComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/GoodsComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,23 +15,26 @@ import GoodsItemComponent from './GoodsItemComponent'; import { GoodsList } from '../../common/constants/HomeConstants'; -import GoodsData from '../../common/bean/GoodsData'; +import GoodsData from '../../viewmodel/GoodsData'; import { PERCENTAGE_100, PERCENTAGE_50 } from '../../common/constants/Constants'; @Component export default struct GoodsComponent { - private goodsList: GoodsData[]; - private startPage: (index: number) => void; + private goodsList: GoodsData[] = []; + private startPage: (index: number) => void = (index: number) => {}; build() { Grid() { - ForEach(this.goodsList, (item, index) => { + ForEach(this.goodsList, (item: GoodsData, index?: number) => { GridItem() { GoodsItemComponent({ config: item }) }.onClick(() => { + if (!index) { + index = 0; + } this.startPage(index); }) - }, item => JSON.stringify(item)) + }, (item: GoodsData) => JSON.stringify(item)) } .columnsTemplate(GoodsList.GRID_STYLE) .columnsGap(GoodsList.SPACE) diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/GoodsItemComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/GoodsItemComponent.ets index eabfccbabb231a91e921c194eb8cfd897d563808..b1b12aade67df3d79f020ea24fcb4f2ce4a3df42 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/GoodsItemComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/GoodsItemComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,12 +14,12 @@ */ import { AppFontSize, AppFontWeight, PERCENTAGE_100 } from '../../common/constants/Constants'; -import GoodsData from '../../common/bean/GoodsData'; +import GoodsData from '../../viewmodel/GoodsData'; import { GoodsListItem } from '../../common/constants/HomeConstants'; @Component export default struct GoodsItemComponent { - private config: GoodsData; + private config: GoodsData = new GoodsData(); build() { Column() { diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/HomePage.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/HomePage.ets index a126cea82c0a1c93acc53a623194ad1fc206ee97..a8461d0bda259e5a98984fe5864a6b40d53714aa 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/HomePage.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/HomePage.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -21,9 +21,9 @@ import SearchComponent from './SearchComponent'; import MenusComponent from './MenusComponent'; import BannerComponent from './BannerComponent'; import GoodsComponent from './GoodsComponent'; -import BannerData from '../../common/bean/BannerData'; -import MenuData from '../../common/bean/MenuData'; -import GoodsData from '../../common/bean/GoodsData'; +import BannerData from '../../viewmodel/BannerData'; +import MenuData from '../../viewmodel/MenuData'; +import GoodsData from '../../viewmodel/GoodsData'; import { HomePageStyle, PERCENTAGE_100 } from '../../common/constants/Constants'; let viewModel: HomeViewModel = new HomeViewModel(); @@ -60,7 +60,7 @@ export default struct HomePage { MenusComponent({ menus: this.menus }) // Goods list view GoodsComponent({ goodsList: this.goodsList, startPage: (index) => { - let handler = getContext(this) as AppContext.Context; + let handler = getContext(this) as AppContext.UIAbilityContext; viewModel.startDetailsAbility(handler, index); } }) } diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/MenusComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/MenusComponent.ets index 0d2ff09bd993d9efd26a8187b9d6334dd298b860..5881864874ff801c0f199735e9b1c1eb90b2c116 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/MenusComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/MenusComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,16 +14,16 @@ */ import { AppFontSize } from '../../common/constants/Constants'; -import MenuData from '../../common/bean/MenuData'; +import MenuData from '../../viewmodel/MenuData'; import { Menus } from '../../common/constants/HomeConstants'; @Component export default struct MenusComponent { - menus: MenuData[]; + menus: MenuData[] = []; build() { Row() { - ForEach(this.menus, (item) => { + ForEach(this.menus, (item: MenuData) => { Column() { Text(item?.menuName) .fontColor(item?.fontColor) @@ -37,7 +37,7 @@ export default struct MenusComponent { .width(Menus.LAYOUT_WEIGHT) .padding({ top: Menus.ITEM_PADDING_VERTICAL, bottom: Menus.ITEM_PADDING_VERTICAL }) - }, item => JSON.stringify(item)) + }, (item: MenuData) => JSON.stringify(item)) } .justifyContent(FlexAlign.Center) .padding({ top: Menus.CONTAINER_PADDING_VERTICAL, diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/SearchComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/SearchComponent.ets index 83a7233a01508d555e40571793134867a0dbf95c..fb461731af589e394ffc448934f808ad66a2a1b7 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/SearchComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/SearchComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/TabsComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/TabsComponent.ets index 4162475e969d9e7f00c16443df119b70094eda02..1c160d2afb1b7adcf0ea5c7ede04864df8584351 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/TabsComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/TabsComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -18,16 +18,16 @@ import { GoodsTabs } from '../../common/constants/HomeConstants'; @Component export default struct TabsComponent { - private tabMenus: Resource[]; + private tabMenus: Resource[] = []; build() { Row() { Tabs({ barPosition: BarPosition.Start, }) { - ForEach(this.tabMenus, (item, index) => { + ForEach(this.tabMenus, (item: Resource, index?: number) => { TabContent() { } - .tabBar(this.TabBuilder(index)) - }, item => JSON.stringify(item)) + .tabBar(this.TabBuilder(index ? index : 0)) + }, (item: Resource) => JSON.stringify(item)) } .vertical(false) .scrollable(true) @@ -68,7 +68,7 @@ export default struct TabsComponent { .align(Alignment.Start) } - isIndexPageWithinTabs(position): boolean { + isIndexPageWithinTabs(position: number): boolean { return GoodsTabs.TABVIEW_POSITION_INDEX_PAGE === position; } } \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/TopBarComponent.ets b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/TopBarComponent.ets index 9d09626dffba0e0b216aecf5bd0494a48f2aa7b8..1ecc6b6a78ea4256aee2961cf9c6cdc88ab0b669 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/view/home/TopBarComponent.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/view/home/TopBarComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -20,7 +20,7 @@ import { PERCENTAGE_100 } from '../../common/constants/Constants'; @Component export default struct TopBarComponent { build() { - BalanceComponent({ left: this.LogoLayout(), right: this.QRCodeLayout() }) + BalanceComponent({ left: this.LogoLayout, right: this.QRCodeLayout }) .width(PERCENTAGE_100) .height(TopBar.HEIGHT) } diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/common/bean/BannerData.ets b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/BannerData.ets similarity index 87% rename from Ability/StageAbilityDemo/entry/src/main/ets/common/bean/BannerData.ets rename to Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/BannerData.ets index 13f364912be1a0164df057ed455392a9c53a6cc2..30dffc7f2d09b3ac194876fb7b5c4c0b0b7764c0 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/common/bean/BannerData.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/BannerData.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,5 +17,5 @@ * BannerData is used to initialize the BannerComponent. */ export default class BannerData { - imgSrc: Resource; + imgSrc: Resource = $rawfile('index/banner1.png'); } \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/DetailsViewModel.ets b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/DetailsViewModel.ets index 529c109ae49704d06127935a7960f85725d6912f..3690ae754feb32a54fc22d5c3e87314947199548 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/DetailsViewModel.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/DetailsViewModel.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,7 +14,7 @@ */ import DataModel from '../model/DataModel'; -import GoodsData from '../common/bean/GoodsData'; +import GoodsData from './GoodsData'; export default class DetailsViewModel { public loadDetails(position: number): GoodsData { diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/common/bean/VideoItem.ets b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/GoodsData.ets similarity index 57% rename from ETSUI/SwiperArkTS/entry/src/main/ets/common/bean/VideoItem.ets rename to Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/GoodsData.ets index 0e9493c03dbd4126e1cf1275fb28fd485b14a959..9667bb489f99e8a846dacf4704ff88f3a40c2b20 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/common/bean/VideoItem.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/GoodsData.ets @@ -14,22 +14,14 @@ */ /** - * Video entity class. + * GoodsData is used to initialize the GoodsComponent. */ -@Observed export class VideoItem { - id: string; - src: Resource; - likesCount: number; - isLikes: boolean; - comment: number; - shareTimes: number; - - constructor(id: string, src: Resource, likesCount: number, isLikes: boolean, comment: number, shareTimes: number) { - this.id = id; - this.src = src; - this.likesCount = likesCount; - this.isLikes = isLikes; - this.comment = comment; - this.shareTimes = shareTimes; - } +export default class GoodsData { + goodsName: Resource = $r('app.string.goods_list_item_1'); + price: string = ''; + originalPrice: string = ''; + discounts: Resource = $r('app.string.goods_list_item_1_save'); + label: Resource = $r('app.string.goods_list_activity_new'); + goodsImg: Resource = $rawfile('index/good1.png'); + goodsDescription: Resource = $r('app.string.goods_list_item_1_desc'); } \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/common/bean/GoodsServiceData.ets b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/GoodsServiceData.ets similarity index 80% rename from Ability/StageAbilityDemo/entry/src/main/ets/common/bean/GoodsServiceData.ets rename to Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/GoodsServiceData.ets index 6f7e1d69747622b73116b58470d853207f252186..6b531a757d19f16ed6f111185704e1bc506165f3 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/common/bean/GoodsServiceData.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/GoodsServiceData.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,7 +17,7 @@ * GoodsData is used to initialize ServicesComponent. */ export default class GoodsServiceData { - id: number; - name: Resource; - description: Resource; + id: number = 0; + name: Resource | null = null; + description: Resource = $r('app.string.goods_service_1_desc'); } \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/HomeViewModel.ets b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/HomeViewModel.ets index be92c5dad051954edcfdba2fc58efd879b9873fe..bebd858914daa3491da5b91704da87ec10aad9c0 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/HomeViewModel.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/HomeViewModel.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,10 +14,12 @@ */ import hilog from '@ohos.hilog'; +import Want from '@ohos.app.ability.Want'; +import common from '@ohos.app.ability.common'; import DataModel from '../model/DataModel'; -import GoodsData from '../common/bean/GoodsData'; -import BannerData from '../common/bean/BannerData'; -import MenuData from '../common/bean/MenuData'; +import GoodsData from './GoodsData'; +import BannerData from './BannerData'; +import MenuData from './MenuData'; import { DETAILS_ABILITY_NAME } from '../common/constants/Constants'; const TAG = 'HomeViewModel'; @@ -40,8 +42,8 @@ export default class HomeViewModel { return DataModel.BANNER; } - public startDetailsAbility(context, index: number): void { - const want = { + public startDetailsAbility(context: common.UIAbilityContext, index: number): void { + const want: Want = { bundleName: getContext(context).applicationInfo.name, abilityName: DETAILS_ABILITY_NAME, parameters: { diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/common/bean/MenuData.ets b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/MenuData.ets similarity index 74% rename from Ability/StageAbilityDemo/entry/src/main/ets/common/bean/MenuData.ets rename to Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/MenuData.ets index 8a30e9a5337f8ec4398af0c45c934c4d891b87d8..e4bfa6ff2d3acd33e5c1e16c1ed0324e8e6fab0e 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/common/bean/MenuData.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/MenuData.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,8 +17,8 @@ * MenuData is used to initialize MenusComponent. */ export default class MenuData { - menuName: Resource; - menuContent: Resource; - fontWeight: string; - fontColor: string; + menuName: Resource = $r('app.string.home_menu_all'); + menuContent: Resource = $r('app.string.home_menu_all_content'); + fontWeight: string = ''; + fontColor: string = ''; } \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/NavViewModel.ets b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/NavViewModel.ets index e89a35dcaa66b5dd410d69be946da19d3b5f0ed6..49e7baea2141b81428c54733f7ca93afc35ef95b 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/NavViewModel.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/NavViewModel.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,7 +14,7 @@ */ import DataModel from '../model/DataModel'; -import ToolBarConfig from '../common/bean/ToolBarData'; +import ToolBarConfig from './ToolBarData'; export default class NavViewModel { public loadNavigationTab(): ToolBarConfig[] { diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/ServicesViewModel.ets b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/ServicesViewModel.ets index 35100cef76ad7d688010e8715a74726a8427d117..7013fbaac4b6cebc5bae7529e661ddc486210dbe 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/ServicesViewModel.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/ServicesViewModel.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,7 +14,7 @@ */ import DataModel from '../model/DataModel'; -import Service from '../common/bean/GoodsServiceData'; +import Service from './GoodsServiceData'; export default class ServicesViewModel { // Load the data of goods service for the GoodsServiceList view. diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/common/bean/ToolBarData.ets b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/ToolBarData.ets similarity index 74% rename from Ability/StageAbilityDemo/entry/src/main/ets/common/bean/ToolBarData.ets rename to Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/ToolBarData.ets index 568009c17e21a624928aaacd067af0c2cdd2524a..6a5dfadbd4b4ffe0da16e655c28026333ceb34be 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/common/bean/ToolBarData.ets +++ b/Ability/StageAbilityDemo/entry/src/main/ets/viewmodel/ToolBarData.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,8 +17,8 @@ * ToolBarData is used to initialize ToolBarComponent. */ export default class ToolBarData { - num: number; - text: Resource; - icon_after: Resource; - icon: Resource; + num: number = 0; + text: Resource = $r('app.string.nav_index'); + icon_after: Resource = $rawfile('index/home.png'); + icon: Resource = $rawfile('index/home_selected.png'); } \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/resources/rawfile/index/banner3.png b/Ability/StageAbilityDemo/entry/src/main/resources/rawfile/index/banner3.png new file mode 100644 index 0000000000000000000000000000000000000000..efea93f52bf8fb70325410a8c2061c32e5902822 Binary files /dev/null and b/Ability/StageAbilityDemo/entry/src/main/resources/rawfile/index/banner3.png differ diff --git a/Ability/StageAbilityDemo/hvigor/hvigor-config.json5 b/Ability/StageAbilityDemo/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/Ability/StageAbilityDemo/hvigor/hvigor-config.json5 +++ b/Ability/StageAbilityDemo/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/Ability/UIAbilityLifeCycle/README.md b/Ability/UIAbilityLifeCycle/README.md index 742c98fe27ee43b753f9ef05be9c9476b52b5925..01ebd7131463f5804c495361bc4520c83ade451c 100644 --- a/Ability/UIAbilityLifeCycle/README.md +++ b/Ability/UIAbilityLifeCycle/README.md @@ -14,13 +14,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -73,7 +73,8 @@ import UIAbility from '@ohos.app.ability.UIAbility'; import Window from '@ohos.window'; export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { + ... + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { // 初始化应用 ... } @@ -90,20 +91,27 @@ export default class EntryAbility extends UIAbility { ```typescript // EntryAbility.ts import UIAbility from '@ohos.app.ability.UIAbility'; -import Window from '@ohos.window'; +import window from '@ohos.window'; export default class EntryAbility extends UIAbility { ... - onWindowStageCreate(windowStage: Window.WindowStage) { + onWindowStageCreate(windowStage: window.WindowStage): void { + this.windowStage = windowStage; // 设置WindowStage事件订阅(获取/失焦、可见/不可见) try { windowStage.on('windowStageEvent', (data) => { - hilog.info(0x0000, 'testTag', 'Succeeded in enabling the listener for window stage event changes. Data: ' + - JSON.stringify(data)); + hilog.info( + this.domain, + 'Succeeded in enabling the listener for window stage event changes. Data: %{public}', + JSON.stringify(data) ?? '' + ); }); } catch (exception) { - hilog.info(0x0000, 'testTag', 'Failed to enable the listener for window stage event changes. Cause:' + - JSON.stringify(exception)); + hilog.error( + this.domain, + 'Failed to enable the listener for window stage event changes. Cause: %{public}', + JSON.stringify(exception) ?? '' + ); } // 设置UI加载 windowStage.loadContent('pages/LifeCyclePage', (err, data) => { @@ -130,18 +138,18 @@ import UIAbility from '@ohos.app.ability.UIAbility'; export default class EntryAbility extends UIAbility { ... - onForeground() { + onForeground(): void { // 申请系统所需的资源或在onBackground中申请释放的资源 } - onBackground() { + onBackground(): void { // UI不可见时释放无用资源,或在此回调中执行耗时操作 // 例如,状态保存 } } ``` -**Destroy状态** +**Destory状态** Destroy状态在UIAbility实例销毁时触发。可以在onDestroy\(\)回调中进行系统资源的释放、数据的保存等操作。 @@ -154,7 +162,7 @@ import Window from '@ohos.window'; export default class EntryAbility extends UIAbility { ... - onDestroy() { + onDestroy(): void | Promise { // 释放系统资源,保存数据 } } @@ -215,26 +223,26 @@ export default class EntryAbility extends UIAbility { aboutToAppear() { this.textColor = Color.Blue; - Logger.info('[LifeCyclePage] LifeCyclePage aboutToAppear') + Logger.info('[LifeCyclePage] LifeCyclePage aboutToAppear'); } onPageShow() { this.textColor = Color.Brown; - Logger.info('[LifeCyclePage] LifeCyclePage onPageShow') + Logger.info('[LifeCyclePage] LifeCyclePage onPageShow'); } onPageHide() { - Logger.info('[LifeCyclePage] LifeCyclePage onPageHide') + Logger.info('[LifeCyclePage] LifeCyclePage onPageHide'); } onBackPress() { this.textColor = Color.Red; - Logger.info('[LifeCyclePage] LifeCyclePage onBackPress') + Logger.info('[LifeCyclePage] LifeCyclePage onBackPress'); return false; } aboutToDisappear() { - Logger.info('[LifeCyclePage] LifeCyclePage aboutToDisappear') + Logger.info('[LifeCyclePage] LifeCyclePage aboutToDisappear'); } build() { diff --git a/Ability/UIAbilityLifeCycle/entry/src/main/ets/common/util/Logger.ets b/Ability/UIAbilityLifeCycle/entry/src/main/ets/common/util/Logger.ets index b80b518a37fcda3b94145589136db036d3ca7058..823cc09fcf0793d840798ae9ad123a6c31c4960d 100644 --- a/Ability/UIAbilityLifeCycle/entry/src/main/ets/common/util/Logger.ets +++ b/Ability/UIAbilityLifeCycle/entry/src/main/ets/common/util/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Ability/UIAbilityLifeCycle/entry/src/main/ets/entryability/EntryAbility.ts b/Ability/UIAbilityLifeCycle/entry/src/main/ets/entryability/EntryAbility.ts index 196e7c9416dade499c01a47d217bf34cc4ef02ef..603be29ed036fc45190ce6cce70d9bf7699775ef 100644 --- a/Ability/UIAbilityLifeCycle/entry/src/main/ets/entryability/EntryAbility.ts +++ b/Ability/UIAbilityLifeCycle/entry/src/main/ets/entryability/EntryAbility.ts @@ -26,33 +26,32 @@ export default class EntryAbility extends UIAbility { want: Want; launchParam: AbilityConstant.LaunchParam; - onCreate(want, launchParam) { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { this.want = want; this.launchParam = launchParam; hilog.info(this.domain, this.tag, 'Ability is onCreate.'); } - onDestroy() { + onDestroy(): void | Promise { hilog.info(this.domain, this.tag, 'Ability is onDestroy.'); } - onWindowStageCreate(windowStage: window.WindowStage) { + onWindowStageCreate(windowStage: window.WindowStage): void { this.windowStage = windowStage; - // Setting Event Subscription for WindowStage (Obtained/Out-of-focus, Visible/Invisible) try { windowStage.on('windowStageEvent', (data) => { hilog.info( this.domain, 'Succeeded in enabling the listener for window stage event changes. Data: %{public}', - JSON.stringify(data)?? '' + JSON.stringify(data) ?? '' ); }); } catch (exception) { hilog.error( this.domain, 'Failed to enable the listener for window stage event changes. Cause: %{public}', - JSON.stringify(exception)?? '' + JSON.stringify(exception) ?? '' ); } @@ -69,7 +68,7 @@ export default class EntryAbility extends UIAbility { }); } - onWindowStageDestroy() { + onWindowStageDestroy(): void { // Releasing UI Resources // Unregisters the WindowStage event for getting/out of focus in onWindowStageDestroy() try { @@ -80,12 +79,12 @@ export default class EntryAbility extends UIAbility { } } - onForeground() { + onForeground(): void { // Ability has brought to foreground hilog.info(this.domain, this.tag, 'Ability is onForeground.'); } - onBackground() { + onBackground(): void { // Ability has back to background hilog.info(this.domain, this.tag, 'Ability is onBackground.'); } diff --git a/Ability/UIAbilityLifeCycle/hvigor/hvigor-config.json5 b/Ability/UIAbilityLifeCycle/hvigor/hvigor-config.json5 index e5bf1bf2b10d77ae8849c97d378d3831f13480b2..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/Ability/UIAbilityLifeCycle/hvigor/hvigor-config.json5 +++ b/Ability/UIAbilityLifeCycle/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.1.1", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.1.1" + "@ohos/hvigor-ohos-plugin": "2.4.2" } -} +} \ No newline at end of file diff --git a/Card/MovieCard/README.md b/Card/MovieCard/README.md index d4d7c8487f1f7e17c5baedda291bd448a863aa8a..86ba0243bf803997f703ba9ca43f044233bd1fc1 100644 --- a/Card/MovieCard/README.md +++ b/Card/MovieCard/README.md @@ -20,13 +20,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -52,9 +52,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──FormBean.ets // 卡片对象 -│ │ │ └──MovieDataBean.ets // 电影详情bean类 │ │ ├──constants │ │ │ ├──CommonConstants.ets // 常量类 │ │ │ └──StyleConstants.ets // 格式常量类 @@ -63,6 +60,7 @@ │ │ │ └──MovieListData.ets // 电影列表数据 │ │ └──utils │ │ ├──CommonUtils.ets // 数据操作工具类 +│ │ ├──GlobalContext.ets // 全局上下文工具类 │ │ └──Logger.ets // 日志打印工具类 │ ├──detailsability │ │ └──EntryDetailsAbility.ets // 电影详情入口类 @@ -73,13 +71,17 @@ │ ├──pages │ │ ├──MovieDetailsPage.ets // 电影详情页 │ │ └──MovieListPage.ets // 主页面 -│ └──view -│ ├──MovieDetailsTitle.ets // 电影详情头部组件 -│ ├──MovieItem.ets // 列表item组件 -│ ├──MovieStarring.ets // 电影主演组件 -│ ├──MovieStills.ets // 电影剧照组件 -│ ├──StarsWidget.ets // 电影评分组件 -│ └──StoryIntroduce.ets // 电影简介组件 +│ ├──view +│ │ ├──MovieDetailsTitle.ets // 电影详情头部组件 +│ │ ├──MovieItem.ets // 列表item组件 +│ │ ├──MovieStarring.ets // 电影主演组件 +│ │ ├──MovieStills.ets // 电影剧照组件 +│ │ ├──StarsWidget.ets // 电影评分组件 +│ │ └──StoryIntroduce.ets // 电影简介组件 +│ └──viewmodel +│ ├──FormBean.ets // 卡片对象 +│ ├──FormDataBean.ets // 卡片数据对象 +│ └──MovieDataBean.ets // 电影数据对象 ├──entry/src/main/js // js代码区 │ ├──card2x2 // 2x2卡片目录 │ ├──card2x4 // 2x4卡片目录 @@ -114,22 +116,19 @@ // CommonUtils.ets import relationalStore from '@ohos.data.relationalStore'; + async createRdbStore(context: Context) { - if (this.isEmpty(globalThis.rdbStore)) { - await relationalStore.getRdbStore(context, CommonConstants.STORE_CONFIG) - .then((rdbStore: relationalStore.RdbStore) => { - if (!this.isEmpty(rdbStore)) { - // 创建卡片表 - rdbStore.executeSql(CommonConstants.CREATE_TABLE_FORM).catch((error) => { - Logger.error(CommonConstants.TAG_COMMON_UTILS, 'executeSql error ' + JSON.stringify(error)); - }); - globalThis.rdbStore = rdbStore; - } - }).catch((error) => { - Logger.error(CommonConstants.TAG_COMMON_UTILS, 'createRdbStore error ' + JSON.stringify(error)); + let rdbStore = GlobalContext.getContext().getObject('rdbStore') as relationalStore.RdbStore; + if (this.isEmpty(rdbStore)) { + rdbStore = await relationalStore.getRdbStore(context, CommonConstants.STORE_CONFIG); + if (!this.isEmpty(rdbStore)) { + rdbStore.executeSql(CommonConstants.CREATE_TABLE_FORM).catch((error: Error) => { + Logger.error(CommonConstants.TAG_COMMON_UTILS, 'executeSql error ' + JSON.stringify(error)); }); + GlobalContext.getContext().setObject('rdbStore', rdbStore); + } } - return globalThis.rdbStore; + return rdbStore; } ``` @@ -154,7 +153,7 @@ build() { // 电影item MovieItem({ movieItem: item }); } - }, item => JSON.stringify(item)) + }, (item: MovieDataBean) => JSON.stringify(item)) } ... } @@ -183,7 +182,7 @@ build() { params: { index: this.sort } - }).catch((error) => { + }).catch((error: Error) => { ... }); }) @@ -201,20 +200,21 @@ build() { ```typescript // MovieDetailPage.ets aboutToAppear() { - let index: number = 0; - if (!CommonUtils.isEmpty(router.getParams())) { - // 获取从电影列表页面传过来的索引 - index = router.getParams()[CommonConstants.INDEX_KEY] ?? 0; - } - ... - let listData: MovieDataBean[] = CommonUtils.getListData(); - if (CommonUtils.isEmptyArr(listData)) { - Logger.error(CommonConstants.TAG_DETAILS_PAGE, 'listData is 0'); - return; - } - // 获取当前电影信息 - this.movieData = listData[index]; - ... + let index: number = 0; + let params = router.getParams() as Record; + if (!CommonUtils.isEmpty(params)) { + index = params.index as number; + } else { + let position = GlobalContext.getContext().getObject('position') as number; + index = position ?? 0; + } + let listData: MovieDataBean[] = CommonUtils.getListData(); + if (CommonUtils.isEmptyArr(listData)) { + Logger.error(CommonConstants.TAG_DETAILS_PAGE, 'listData is 0'); + return; + } + this.movieData = listData[index]; + this.introduction = listData[index].introduction; } build() { @@ -271,24 +271,24 @@ build() { ```typescript // EntryFormAbility.ets onAddForm(want: Want) { - let formId: string = want.parameters[CommonConstants.IDENTITY_KEY] as string; - let formName: string = want.parameters[CommonConstants.NAME_KEY] as string; - let dimensionFlag: number = want.parameters[CommonConstants.DIMENSION_KEY] as number; - // 创建数据库 - CommonUtils.createRdbStore(this.context).then((rdbStore: relationalStore.RdbStore) => { - let form: Form = new Form(); - form.formId = formId; - form.formName = formName; - form.dimension = dimensionFlag; - // 插入卡片信息 - CommonUtils.insertForm(form, rdbStore); - }).catch((error) => { - ... - }); - ... - let listData: MovieDataBean[] = CommonUtils.getListData(); - let formData = CommonUtils.getFormData(listData); - return formBindingData.createFormBindingData(formData); + if (want.parameters === undefined) { + return formBindingData.createFormBindingData(); + } + let formId: string = want.parameters[CommonConstants.IDENTITY_KEY] as string; + let formName: string = want.parameters[CommonConstants.NAME_KEY] as string; + let dimensionFlag: number = want.parameters[CommonConstants.DIMENSION_KEY] as number; + CommonUtils.createRdbStore(this.context).then((rdbStore: relationalStore.RdbStore) => { + let form: FormBean = new FormBean(); + form.formId = formId; + form.formName = formName; + form.dimension = dimensionFlag; + CommonUtils.insertForm(form, rdbStore); + }).catch((error: Error) => { + Logger.error(CommonConstants.TAG_FORM_ABILITY, 'onAddForm create rdb error ' + JSON.stringify(error)); + }); + let listData: MovieDataBean[] = CommonUtils.getListData(); + let formData = CommonUtils.getFormData(listData); + return formBindingData.createFormBindingData(formData); } ``` @@ -306,60 +306,45 @@ onAddForm(want: Want) { // CommonUtils.ets startTimer() { - if (this.isEmpty(globalThis.intervalId)) { - globalThis.intervalId = setInterval(() => { - this.updateMovieCardData(globalThis.rdbStore); + let intervalId = GlobalContext.getContext().getObject('intervalId') as number; + if (this.isEmpty(intervalId)) { + intervalId = setInterval(() => { + let rdbStore = GlobalContext.getContext().getObject('rdbStore') as relationalStore.RdbStore; + this.updateMovieCardData(rdbStore); }, CommonConstants.INTERVAL_DELAY_TIME); } + GlobalContext.getContext().setObject('intervalId', intervalId); } // 更新电影卡片数据 updateMovieCardData(rdbStore: relationalStore.RdbStore) { - ... - let predicates: relationalStore.RdbPredicates = - new relationalStore.RdbPredicates(CommonConstants.TABLE_NAME); - rdbStore.query(predicates).then((resultSet: relationalStore.ResultSet) => { - ... - let listData: MovieDataBean[] = this.getListData(); - resultSet.goToFirstRow(); - do { - let formData = this.getFormData(listData); - let formId: string = resultSet.getString(resultSet.getColumnIndex(CommonConstants.FORM_ID)); - formProvider.updateForm(formId, formBindingData.createFormBindingData(formData)) - .catch((error) => { - ... - }); - } while (resultSet.goToNextRow()); - resultSet.close(); - }).catch((error) => { - ... - }); - } - ``` - -2. 卡片添加到桌面后,在EntryFormAbility的onAddForm方法中,调用formProvider.setFormNextRefreshTime方法设置倒计时。时间到了则通过CommonUtils.updateMovieCardData方法更新电影卡片数据。 - - ```typescript - // EntryFormAbility.ets - onAddForm(want: Want) { - ... - // 五分钟倒计时 - formProvider.setFormNextRefreshTime(formId, CommonConstants.FIVE_MINUTES, (error, data) => { - ... - }); - } - - onUpdateForm(formId: string) { - CommonUtils.createRdbStore(this.context).then((rdbStore: relationalStore.RdbStore) => { - CommonUtils.updateMovieCardData(rdbStore); - }).catch((error) => { - ... - }); - ... - } + if (this.isEmpty(rdbStore)) { + Logger.error(CommonConstants.TAG_COMMON_UTILS, 'rdbStore is null'); + return; + } + let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates(CommonConstants.TABLE_NAME); + rdbStore.query(predicates).then((resultSet: relationalStore.ResultSet) => { + if (resultSet.rowCount <= 0) { + Logger.error(CommonConstants.TAG_COMMON_UTILS, 'updateCardMovieData rowCount <= 0'); + return; + } + let listData: MovieDataBean[] = this.getListData(); + resultSet.goToFirstRow(); + do { + let formData = this.getFormData(listData); + let formId: string = resultSet.getString(resultSet.getColumnIndex(CommonConstants.FORM_ID)); + formProvider.updateForm(formId, formBindingData.createFormBindingData(formData)) + .catch((error: Error) => { + Logger.error(CommonConstants.TAG_COMMON_UTILS, 'updateForm error ' + JSON.stringify(error)); + }); + } while (resultSet.goToNextRow()); + resultSet.close(); + }).catch((error: Error) => { + Logger.error(CommonConstants.TAG_COMMON_UTILS, 'updateCardMovieData error ' + JSON.stringify(error)); + }); ``` -3. 通过src/main/resources/base/profile/form_config.json配置文件,根据updateDuration或者scheduledUpdateTime字段配置刷新时间。updateDuration优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration配置的刷新时间为准。当配置的刷新时间到了,系统调用onUpdateForm方法进行更新。 +2. 通过src/main/resources/base/profile/form_config.json配置文件,根据updateDuration或者scheduledUpdateTime字段配置刷新时间。updateDuration优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration配置的刷新时间为准。当配置的刷新时间到了,系统调用onUpdateForm方法进行更新。 ```typescript // form_config.json @@ -398,7 +383,7 @@ onAddForm(want: Want) { onUpdateForm(formId: string) { CommonUtils.createRdbStore(this.context).then((rdbStore: relationalStore.RdbStore) => { CommonUtils.updateMovieCardData(rdbStore); - }).catch((error) => { + }).catch((error: Error) => { ... }); ... @@ -415,7 +400,7 @@ onRemoveForm(formId: string) { CommonUtils.createRdbStore(this.context).then((rdbStore: relationalStore.RdbStore) => { // 从数据库中删除电影卡片信息 CommonUtils.deleteFormData(formId, rdbStore); - }).catch((error) => { + }).catch((error: Error) => { ... }); } @@ -423,10 +408,9 @@ onRemoveForm(formId: string) { // CommonUtils.ets deleteFormData(formId: string, rdbStore: relationalStore.RdbStore) { ... - let predicates: relationalStore.RdbPredicates = - new relationalStore.RdbPredicates(CommonConstants.TABLE_NAME); + let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates(CommonConstants.TABLE_NAME); predicates.equalTo(CommonConstants.FORM_ID, formId); - rdbStore.delete(predicates).catch((error) => { + rdbStore.delete(predicates).catch((error: Error) => { ... }); } diff --git a/Card/MovieCard/entry/src/main/ets/common/constants/CommonConstants.ets b/Card/MovieCard/entry/src/main/ets/common/constants/CommonConstants.ets index 0f77faac4ed4dbcec6886b2f69bb79c9aca3e86b..845e13d9b0f8aa26afe46bf4a07605e04b9f985b 100644 --- a/Card/MovieCard/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/Card/MovieCard/entry/src/main/ets/common/constants/CommonConstants.ets @@ -23,120 +23,77 @@ export default class CommonConstants { * The entry ability tag. */ static readonly TAG_ABILITY: string = 'EntryAbility'; - /** * The entry details ability tag. */ static readonly TAG_DETAILS: string = 'EntryDetailsAbility'; - - /** - * The movie list page tag. - */ - static readonly TAG_MOVIE_LIST: string = 'MovieListPage'; - /** * The movie details page tag. */ static readonly TAG_DETAILS_PAGE: string = 'MovieDetailsPage'; - /** * The entry form ability tag. */ static readonly TAG_FORM_ABILITY: string = 'EntryFormAbility'; - /** * The movie item component tag. */ static readonly TAG_MOVIE_ITEM: string = 'MovieItem'; - /** * The movie details item component tag. */ static readonly TAG_DETAILS_COMPONENT: string = 'MovieDetailTitle'; - /** * The common utils tag. */ static readonly TAG_COMMON_UTILS: string = 'CommonUtils'; - /** * Database store configuration. */ static readonly STORE_CONFIG: relationalStore.StoreConfig = { name: 'FormDatabase.db', securityLevel: relationalStore.SecurityLevel.S1, encrypt: false }; - /** * SQL statement for creating a form. */ static readonly CREATE_TABLE_FORM: string = 'CREATE TABLE IF NOT EXISTS Form ' + '(id INTEGER PRIMARY KEY AUTOINCREMENT, formId TEXT NOT NULL, formName TEXT NOT NULL, dimension INTEGER)'; - /** * ID parameter for creating a form. */ static readonly IDENTITY_KEY: string = 'ohos.extra.param.key.form_identity'; - /** * Name parameter for creating a form. */ static readonly NAME_KEY: string = 'ohos.extra.param.key.form_name'; - /** * Dimension parameter for creating a form. */ static readonly DIMENSION_KEY: string = 'ohos.extra.param.key.form_dimension'; - /** * Table name */ static readonly TABLE_NAME: string = 'Form'; - - /** - * Refresh time in 5 minute. - */ - static readonly FIVE_MINUTES: number = 5; - /** * Form ID field in the database table. */ static readonly FORM_ID: string = 'formId'; - /** * Time interval of the 300000. */ static readonly INTERVAL_DELAY_TIME: number = 300000; - - /** - * Notification id of the 1008. - */ - static readonly NOTIFICATIONS_ID: number = 1008; - /** * Random multiply ten. */ static readonly MULTIPLY_TEN: number = 10; - - /** - * Random minus two. - */ - static readonly MINUS_TWO: number = 2; - /** * Default lines of the 5. */ static readonly DEFAULT_LINES: number = 5; - /** * Max lines of the 10. */ static readonly MAX_LINES: number = 10; - - /** - * Index key - */ - static readonly INDEX_KEY: string = 'index'; - /** * See button push page url. */ diff --git a/Card/MovieCard/entry/src/main/ets/common/constants/StyleConstants.ets b/Card/MovieCard/entry/src/main/ets/common/constants/StyleConstants.ets index 0e89bd9f6757453e3cb15722fee2a923800e4675..3c9d566531235ccaabd3a3160bf1efba5f34c1c1 100644 --- a/Card/MovieCard/entry/src/main/ets/common/constants/StyleConstants.ets +++ b/Card/MovieCard/entry/src/main/ets/common/constants/StyleConstants.ets @@ -21,42 +21,34 @@ export default class StyleConstants { * Common left the percentage of the 6.7. */ static readonly COMMON_MARGIN_LEFT: string = '6.7%'; - /** * Details common margin size the percentage of the 1.5. */ static readonly DETAILS_COMMON_MARGIN: string = '1.5%'; - /** * Column details width the percentage of the 93.4. */ static readonly COLUMN_DETAILS_WIDTH: string = '93.4%'; - /** * Starring text width the percentage of the 76.6. */ static readonly STARRING_TEXT_WIDTH: string = '76.6%'; - /** * Common margin top the percentage of the 3.2. */ static readonly COMMON_MARGIN_TOP: string = '3.2%'; - /** * Common margin right the percentage of the 3.3. */ static readonly COMMON_MARGIN_RIGHT: string = '3.3%'; - /** * Common margin bottom the percentage of the 1. */ static readonly COMMON_MARGIN_BOTTOM: string = '1%'; - /** * Starring width the percentage of the 90. */ static readonly STARRING_WIDTH: string = '90%'; - /** * Starring space of the 8. */ @@ -65,65 +57,52 @@ export default class StyleConstants { * Rstarring list width the percentage of the 93.3. */ static readonly STARRING_LIST_WIDTH: string = '93.3%'; - /** * Rstarring list height the percentage of the 14.4. */ static readonly STARRING_LIST_HEIGHT: string = '14.4%'; - /** * Stills text width the percentage of the 76.6. */ static readonly STILLS_TEXT_WIDTH: string = '76.6%'; - /** * Stills width the percentage of the 90. */ static readonly STILLS_WIDTH: string = '90%'; - /** * Stills list space of the 4. */ static readonly STILLS_LIST_SPACE: number = 4; - /** * Stills list width the percentage of the 93.3. */ static readonly STILLS_LIST_WIDTH: string = '93.3%'; - /** * List title margin the percentage of the 1.5. */ static readonly LIST_TITLE_MARGIN: string = '1.5%'; - /** * List compoent space of the 12. */ static readonly LIST_COMPONENT_SPACE: number = 12; - /** * Item width the percentage of the 93.4. */ static readonly ITEM_WIDTH: string = '93.4%'; - /** * Stars list space of the 3. */ static readonly STARS_LIST_SPACE: number = 3; - /** * Layout weight size of the 1. */ static readonly WEIGHT_ONE: number = 1; - /** * Width the percentage of the 100. */ static readonly FULL_WIDTH: string = '100%'; - /** * Height the percentage of the 100. */ static readonly FULL_HEIGHT: string = '100%'; - } \ No newline at end of file diff --git a/Card/MovieCard/entry/src/main/ets/common/datasource/DataSource.ets b/Card/MovieCard/entry/src/main/ets/common/datasource/DataSource.ets index 8715b35e21a894591d134310f5e63468e3672ab9..f0465fceefcc194577e2f9867235e0ccc82c3da0 100644 --- a/Card/MovieCard/entry/src/main/ets/common/datasource/DataSource.ets +++ b/Card/MovieCard/entry/src/main/ets/common/datasource/DataSource.ets @@ -32,9 +32,8 @@ export default class DataSource implements IDataSource { } registerDataChangeListener() { - } unregisterDataChangeListener() { } -} +} \ No newline at end of file diff --git a/Card/MovieCard/entry/src/main/ets/common/datasource/MovieListData.ets b/Card/MovieCard/entry/src/main/ets/common/datasource/MovieListData.ets index 8ad5cf1858d14b2d905ab41d416b88bb40aff44d..171c0c6a6cf7bf18f83a8dd68fc4f71098dece67 100644 --- a/Card/MovieCard/entry/src/main/ets/common/datasource/MovieListData.ets +++ b/Card/MovieCard/entry/src/main/ets/common/datasource/MovieListData.ets @@ -12,130 +12,131 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import MovieDataBean from '../../viewmodel/MovieDataBean'; /** * Movie list Data */ -export const MOVIE_LIST_DATA = [ +export const MOVIE_LIST_DATA: MovieDataBean[] = [ { - 'sort': 0, - 'isShowSort': true, - 'sortImage': $r('app.media.ic_first'), - 'title': '冰上姐妹', - 'describe': '讲述冰上女运动员之间团结友爱,互帮互助的故事', - 'movieImage': $r('app.media.ic_movie_one'), - 'cardImage': '/common/ic_movie_one.png', - 'stars': [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star')], - 'rating': '9.5', - 'introduction': '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' + sort: 0, + isShowSort: true, + sortImage: $r('app.media.ic_first'), + title: '冰上姐妹', + describe: '讲述冰上女运动员之间团结友爱,互帮互助的故事', + movieImage: $r('app.media.ic_movie_one'), + cardImage: '/common/ic_movie_one.png', + stars: [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star')], + rating: '9.5', + introduction: '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' }, { - 'sort': 1, - 'isShowSort': true, - 'sortImage': $r('app.media.ic_second'), - 'title': '冲破黎明前的黑暗', - 'describe': '通过地道战的方式与日寇作斗争的故事', - 'movieImage': $r('app.media.ic_movie_two'), - 'cardImage': '/common/ic_movie_two.png', - 'stars': [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star')], - 'rating': '9.5', - 'introduction': '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' + sort: 1, + isShowSort: true, + sortImage: $r('app.media.ic_second'), + title: '冲破黎明前的黑暗', + describe: '通过地道战的方式与日寇作斗争的故事', + movieImage: $r('app.media.ic_movie_two'), + cardImage: '/common/ic_movie_two.png', + stars: [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star')], + rating: '9.5', + introduction: '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' }, { - 'sort': 2, - 'isShowSort': true, - 'sortImage': $r('app.media.ic_third'), - 'title': '党的女儿', - 'describe': '带领群众继续作斗争,最后壮烈牺牲的故事', - 'movieImage': $r('app.media.ic_movie_three'), - 'cardImage': '/common/ic_movie_three.png', - 'stars': [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star')], - 'rating': '9.5', - 'introduction': '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' + sort: 2, + isShowSort: true, + sortImage: $r('app.media.ic_third'), + title: '党的女儿', + describe: '带领群众继续作斗争,最后壮烈牺牲的故事', + movieImage: $r('app.media.ic_movie_three'), + cardImage: '/common/ic_movie_three.png', + stars: [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star')], + rating: '9.5', + introduction: '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' }, { - 'sort': 3, - 'isShowSort': true, - 'sortImage': $r('app.media.ic_fourth'), - 'title': '古刹钟声', - 'describe': '抗日战争时期,八路军剿灭日本特务的故事', - 'movieImage': $r('app.media.ic_movie_four'), - 'cardImage': '/common/ic_movie_four.png', - 'stars': [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_empty_star')], - 'rating': '9.0', - 'introduction': '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' + sort: 3, + isShowSort: true, + sortImage: $r('app.media.ic_fourth'), + title: '古刹钟声', + describe: '抗日战争时期,八路军剿灭日本特务的故事', + movieImage: $r('app.media.ic_movie_four'), + cardImage: '/common/ic_movie_four.png', + stars: [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_empty_star')], + rating: '9.0', + introduction: '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' }, { - 'sort': 4, - 'isShowSort': true, - 'sortImage': $r('app.media.ic_fifth'), - 'title': '花木兰', - 'describe': '花木兰替父从军,英姿飒爽的故事', - 'movieImage': $r('app.media.ic_movie_five'), - 'cardImage': '/common/ic_movie_five.png', - 'stars': [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_empty_star')], - 'rating': '9.0', - 'introduction': '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' + sort: 4, + isShowSort: true, + sortImage: $r('app.media.ic_fifth'), + title: '花木兰', + describe: '花木兰替父从军,英姿飒爽的故事', + movieImage: $r('app.media.ic_movie_five'), + cardImage: '/common/ic_movie_five.png', + stars: [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_empty_star')], + rating: '9.0', + introduction: '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' }, { - 'sort': 5, - 'isShowSort': false, - 'sortImage': $r('app.media.icon'), - 'title': '画中人', - 'describe': '讲述了一对相爱的年轻人,受到昏君的迫害,遇到仙人相助的故事', - 'movieImage': $r('app.media.ic_movie_six'), - 'cardImage': '/common/ic_movie_six.png', - 'stars': [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star'), $r('app.media.ic_empty_star')], - 'rating': '8.5', - 'introduction': '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' + sort: 5, + isShowSort: false, + sortImage: $r('app.media.icon'), + title: '画中人', + describe: '讲述了一对相爱的年轻人,受到昏君的迫害,遇到仙人相助的故事', + movieImage: $r('app.media.ic_movie_six'), + cardImage: '/common/ic_movie_six.png', + stars: [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star'), $r('app.media.ic_empty_star')], + rating: '8.5', + introduction: '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' }, { - 'sort': 6, - 'isShowSort': false, - 'sortImage': $r('app.media.icon'), - 'title': '马兰花开', - 'describe': '讲述一位家庭妇女,为了参加新中国的建设,主动要学习驾驶推土机一系列故事', - 'movieImage': $r('app.media.ic_movie_seven'), - 'cardImage': '/common/ic_movie_seven.png', - 'stars': [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star'), $r('app.media.ic_empty_star')], - 'rating': '8.5', - 'introduction': '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' + sort: 6, + isShowSort: false, + sortImage: $r('app.media.icon'), + title: '马兰花开', + describe: '讲述一位家庭妇女,为了参加新中国的建设,主动要学习驾驶推土机一系列故事', + movieImage: $r('app.media.ic_movie_seven'), + cardImage: '/common/ic_movie_seven.png', + stars: [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star'), $r('app.media.ic_empty_star')], + rating: '8.5', + introduction: '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' }, { - 'sort': 7, - 'isShowSort': false, - 'sortImage': $r('app.media.icon'), - 'title': '五朵金花', - 'describe': '讲述了大理地区,一对男女青年之间,产生了阴差阳错误会的爱情故事', - 'movieImage': $r('app.media.ic_movie_eight'), - 'cardImage': '/common/ic_movie_eight.png', - 'stars': [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star'), $r('app.media.ic_empty_star')], - 'rating': '8.5', - 'introduction': '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' + sort: 7, + isShowSort: false, + sortImage: $r('app.media.icon'), + title: '五朵金花', + describe: '讲述了大理地区,一对男女青年之间,产生了阴差阳错误会的爱情故事', + movieImage: $r('app.media.ic_movie_eight'), + cardImage: '/common/ic_movie_eight.png', + stars: [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star'), $r('app.media.ic_empty_star')], + rating: '8.5', + introduction: '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' }, { - 'sort': 8, - 'isShowSort': false, - 'sortImage': $r('app.media.icon'), - 'title': '战火中的青春', - 'describe': '讲述了解放战争期间,女扮男装高山参加解放军,成为副排长,与排长共同战斗的故事', - 'movieImage': $r('app.media.ic_movie_eight'), - 'cardImage': '/common/ic_movie_eight.png', - 'stars': [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star'), $r('app.media.ic_empty_star')], - 'rating': '8.5', - 'introduction': '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' + sort: 8, + isShowSort: false, + sortImage: $r('app.media.icon'), + title: '战火中的青春', + describe: '讲述了解放战争期间,女扮男装高山参加解放军,成为副排长,与排长共同战斗的故事', + movieImage: $r('app.media.ic_movie_eight'), + cardImage: '/common/ic_movie_eight.png', + stars: [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star'), $r('app.media.ic_empty_star')], + rating: '8.5', + introduction: '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' }, { - 'sort': 9, - 'isShowSort': false, - 'sortImage': $r('app.media.icon'), - 'title': '祖国的花朵', - 'describe': '讲述了北京的一所小学,五年级的同学们先进帮后进的故事', - 'movieImage': $r('app.media.ic_movie_seven'), - 'cardImage': '/common/ic_movie_seven.png', - 'stars': [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star'), $r('app.media.ic_empty_star')], - 'rating': '8.5', - 'introduction': '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' + sort: 9, + isShowSort: false, + sortImage: $r('app.media.icon'), + title: '祖国的花朵', + describe: '讲述了北京的一所小学,五年级的同学们先进帮后进的故事', + movieImage: $r('app.media.ic_movie_seven'), + cardImage: '/common/ic_movie_seven.png', + stars: [$r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_star'), $r('app.media.ic_half_star'), $r('app.media.ic_empty_star')], + rating: '8.5', + introduction: '剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介。简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情简介剧情。' } ]; diff --git a/Card/MovieCard/entry/src/main/ets/common/utils/CommonUtils.ets b/Card/MovieCard/entry/src/main/ets/common/utils/CommonUtils.ets index 547ff409e5a349228b4dbcc232fdb219d266ebbe..ed948d98644d08e5044577beaf08631166c37411 100644 --- a/Card/MovieCard/entry/src/main/ets/common/utils/CommonUtils.ets +++ b/Card/MovieCard/entry/src/main/ets/common/utils/CommonUtils.ets @@ -16,11 +16,13 @@ import relationalStore from '@ohos.data.relationalStore'; import formProvider from '@ohos.app.form.formProvider'; import formBindingData from '@ohos.app.form.formBindingData'; -import FormBean from '../bean/FormBean'; +import FormBean from '../../viewmodel/FormBean'; import CommonConstants from '../constants/CommonConstants'; -import MovieDataBean from '../bean/MovieDataBean'; +import MovieDataBean from '../../viewmodel/MovieDataBean'; import Logger from './Logger'; import { MOVIE_LIST_DATA, STARRING_DATA, STILLS_DATA } from '../datasource/MovieListData'; +import { GlobalContext } from './GlobalContext'; +import FormDataBean from '../../viewmodel/FormDataBean'; /** * Movie data common class. @@ -30,23 +32,20 @@ export class CommonUtils { * Create rdb store. * * @param {context} Context - * @return {globalThis.rdbStore} return rdbStore RDB database + * @return {rdbStore} return rdbStore RDB database */ async createRdbStore(context: Context) { - if (this.isEmpty(globalThis.rdbStore)) { - await relationalStore.getRdbStore(context, CommonConstants.STORE_CONFIG) - .then((rdbStore: relationalStore.RdbStore) => { - if (!this.isEmpty(rdbStore)) { - rdbStore.executeSql(CommonConstants.CREATE_TABLE_FORM).catch((error) => { - Logger.error(CommonConstants.TAG_COMMON_UTILS, 'executeSql error ' + JSON.stringify(error)); - }); - globalThis.rdbStore = rdbStore; - } - }).catch((error) => { - Logger.error(CommonConstants.TAG_COMMON_UTILS, 'createRdbStore error ' + JSON.stringify(error)); + let rdbStore = GlobalContext.getContext().getObject('rdbStore') as relationalStore.RdbStore; + if (this.isEmpty(rdbStore)) { + rdbStore = await relationalStore.getRdbStore(context, CommonConstants.STORE_CONFIG); + if (!this.isEmpty(rdbStore)) { + rdbStore.executeSql(CommonConstants.CREATE_TABLE_FORM).catch((error: Error) => { + Logger.error(CommonConstants.TAG_COMMON_UTILS, 'executeSql error ' + JSON.stringify(error)); }); + GlobalContext.getContext().setObject('rdbStore', rdbStore); + } } - return globalThis.rdbStore; + return rdbStore; } /** @@ -61,7 +60,7 @@ export class CommonUtils { Logger.error(CommonConstants.TAG_COMMON_UTILS, 'insertForm rdbStore or form is null'); return; } - rdbStore.insert(CommonConstants.TABLE_NAME, form.toValuesBucket()).catch((error) => { + rdbStore.insert(CommonConstants.TABLE_NAME, form.toValuesBucket()).catch((error: Error) => { Logger.error(CommonConstants.TAG_COMMON_UTILS, 'insertForm error ' + JSON.stringify(error)); }); } @@ -88,12 +87,12 @@ export class CommonUtils { let formData = this.getFormData(listData); let formId: string = resultSet.getString(resultSet.getColumnIndex(CommonConstants.FORM_ID)); formProvider.updateForm(formId, formBindingData.createFormBindingData(formData)) - .catch((error) => { + .catch((error: Error) => { Logger.error(CommonConstants.TAG_COMMON_UTILS, 'updateForm error ' + JSON.stringify(error)); }); } while (resultSet.goToNextRow()); resultSet.close(); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.TAG_COMMON_UTILS, 'updateCardMovieData error ' + JSON.stringify(error)); }); } @@ -124,7 +123,7 @@ export class CommonUtils { } let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates(CommonConstants.TABLE_NAME); predicates.equalTo(CommonConstants.FORM_ID, formId); - rdbStore.delete(predicates).catch((error) => { + rdbStore.delete(predicates).catch((error: Error) => { Logger.error(CommonConstants.TAG_COMMON_UTILS, 'deleteFormData error ' + JSON.stringify(error)); }); } @@ -135,26 +134,12 @@ export class CommonUtils { * @return {listMovieData} return list movie data */ getListData(): MovieDataBean[] { - if (this.isEmptyArr(globalThis.listMovieData)) { - let listMovieData: MovieDataBean[] = []; - MOVIE_LIST_DATA.forEach((itemMovie) => { - let movieItem: MovieDataBean = { - sort: itemMovie.sort, - isShowSort: itemMovie.isShowSort, - sortImage: itemMovie.sortImage, - title: itemMovie.title, - describe: itemMovie.describe, - movieImage: itemMovie.movieImage, - cardImage: itemMovie.cardImage, - stars: itemMovie.stars, - rating: itemMovie.rating, - introduction: itemMovie.introduction, - }; - listMovieData.push(movieItem); - }); - globalThis.listMovieData = listMovieData; + let listMovieData = GlobalContext.getContext().getObject('listMovieData') as MovieDataBean[]; + if (this.isEmptyArr(listMovieData)) { + listMovieData = MOVIE_LIST_DATA; + GlobalContext.getContext().setObject('listMovieData', listMovieData); } - return globalThis.listMovieData; + return listMovieData; } /** @@ -165,7 +150,7 @@ export class CommonUtils { getFormData(listData: MovieDataBean[]): object { if (this.isEmptyArr(listData)) { Logger.error(CommonConstants.TAG_COMMON_UTILS, 'getFormData listData is empty'); - return; + return []; } let oneRandom: number = this.getRandomInt(listData.length); let twoRandom: number = this.getRandomInt(oneRandom); @@ -180,7 +165,7 @@ export class CommonUtils { bottomMovieImage: bottomMovie.cardImage, bottomTitle: bottomMovie.title, bottomDescribe: bottomMovie.describe - }; + } as FormDataBean; return formData; } @@ -188,11 +173,14 @@ export class CommonUtils { * Start timer */ startTimer() { - if (this.isEmpty(globalThis.intervalId)) { - globalThis.intervalId = setInterval(() => { - this.updateMovieCardData(globalThis.rdbStore); + let intervalId = GlobalContext.getContext().getObject('intervalId') as number; + if (this.isEmpty(intervalId)) { + intervalId = setInterval(() => { + let rdbStore = GlobalContext.getContext().getObject('rdbStore') as relationalStore.RdbStore; + this.updateMovieCardData(rdbStore); }, CommonConstants.INTERVAL_DELAY_TIME); } + GlobalContext.getContext().setObject('intervalId', intervalId); } /** @@ -227,7 +215,7 @@ export class CommonUtils { * @param {object} obj * @return {boolean} true(empty) */ - isEmpty(obj): boolean { + isEmpty(obj: object | string | number): boolean { return (obj === undefined || obj === null || obj === ''); } @@ -237,7 +225,7 @@ export class CommonUtils { * @param {Array}array * @return {boolean} true(empty) */ - isEmptyArr(array): boolean { + isEmptyArr(array: MovieDataBean[]): boolean { return (this.isEmpty(array) || array.length === 0); } } diff --git a/Card/MovieCard/entry/src/main/ets/common/utils/GlobalContext.ets b/Card/MovieCard/entry/src/main/ets/common/utils/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..9e37636fb97fa89482a076659f92dd055acf8217 --- /dev/null +++ b/Card/MovieCard/entry/src/main/ets/common/utils/GlobalContext.ets @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { + } + + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/Card/MovieCard/entry/src/main/ets/common/utils/Logger.ets b/Card/MovieCard/entry/src/main/ets/common/utils/Logger.ets index 43d37dd0dda6307c80ea7439d4d95fd5f1fc4f35..93dd93e9b6f69f8b997bf5bb9953327a6349a7ec 100644 --- a/Card/MovieCard/entry/src/main/ets/common/utils/Logger.ets +++ b/Card/MovieCard/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Card/MovieCard/entry/src/main/ets/detailsability/EntryDetailsAbility.ets b/Card/MovieCard/entry/src/main/ets/detailsability/EntryDetailsAbility.ets index 78330607a51448d46bc9fe13b45e9912fa39d114..d6d787d85bf92659a49c860911300012b4dbb936 100644 --- a/Card/MovieCard/entry/src/main/ets/detailsability/EntryDetailsAbility.ets +++ b/Card/MovieCard/entry/src/main/ets/detailsability/EntryDetailsAbility.ets @@ -13,24 +13,27 @@ * limitations under the License. */ +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; import UIAbility from '@ohos.app.ability.UIAbility'; +import Want from '@ohos.app.ability.Want'; import window from '@ohos.window'; import CommonConstants from '../common/constants/CommonConstants'; import Logger from '../common/utils/Logger'; +import { GlobalContext } from '../common/utils/GlobalContext'; /** * Lift cycle management of Ability. */ export default class EntryDetailsAbility extends UIAbility { - onCreate(want, launchParam) { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { Logger.info(CommonConstants.TAG_DETAILS, 'want =' + JSON.stringify(want)); Logger.info(CommonConstants.TAG_DETAILS, 'launchParam =' + JSON.stringify(launchParam)); - let params = want?.parameters?.params; + let params = want?.parameters?.params as string; Logger.info(CommonConstants.TAG_DETAILS, 'params ' + params); - let parseParams = JSON.parse(params); + let parseParams = JSON.parse(params) as Record; Logger.info(CommonConstants.TAG_DETAILS, 'parseParams ' + parseParams); - let index = parseParams?.index; - globalThis.position = index; + let index: number = parseParams?.index as number; + GlobalContext.getContext().setObject('position', index); } onWindowStageCreate(windowStage: window.WindowStage) { diff --git a/Card/MovieCard/entry/src/main/ets/entryformability/EntryFormAbility.ets b/Card/MovieCard/entry/src/main/ets/entryformability/EntryFormAbility.ets index a9a29db58270e064662f95adfa084b59a1551245..1041e61c551b3d8d58df0b4acb8b3762e921f546 100644 --- a/Card/MovieCard/entry/src/main/ets/entryformability/EntryFormAbility.ets +++ b/Card/MovieCard/entry/src/main/ets/entryformability/EntryFormAbility.ets @@ -16,12 +16,11 @@ import relationalStore from '@ohos.data.relationalStore'; import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility'; import formBindingData from '@ohos.app.form.formBindingData'; -import formProvider from '@ohos.app.form.formProvider'; import Want from '@ohos.app.ability.Want'; import CommonConstants from '../common/constants/CommonConstants'; -import FormBean from '../common/bean/FormBean'; +import FormBean from '../viewmodel/FormBean'; import CommonUtils from '../common/utils/CommonUtils'; -import MovieDataBean from '../common/bean/MovieDataBean'; +import MovieDataBean from '../viewmodel/MovieDataBean'; import Logger from '../common/utils/Logger'; /** @@ -29,6 +28,9 @@ import Logger from '../common/utils/Logger'; */ export default class EntryFormAbility extends FormExtensionAbility { onAddForm(want: Want) { + if (want.parameters === undefined) { + return formBindingData.createFormBindingData(); + } let formId: string = want.parameters[CommonConstants.IDENTITY_KEY] as string; let formName: string = want.parameters[CommonConstants.NAME_KEY] as string; let dimensionFlag: number = want.parameters[CommonConstants.DIMENSION_KEY] as number; @@ -38,18 +40,9 @@ export default class EntryFormAbility extends FormExtensionAbility { form.formName = formName; form.dimension = dimensionFlag; CommonUtils.insertForm(form, rdbStore); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.TAG_FORM_ABILITY, 'onAddForm create rdb error ' + JSON.stringify(error)); }); - - // Refresh every five minutes. - formProvider.setFormNextRefreshTime(formId, CommonConstants.FIVE_MINUTES, (error, data) => { - if (error) { - Logger.error(CommonConstants.TAG_FORM_ABILITY, 'setRefreshTime error ' + JSON.stringify(error)); - } else { - Logger.info(CommonConstants.TAG_FORM_ABILITY, 'setRefreshTime success ' + JSON.stringify(data)); - } - }); let listData: MovieDataBean[] = CommonUtils.getListData(); let formData = CommonUtils.getFormData(listData); return formBindingData.createFormBindingData(formData); @@ -58,24 +51,16 @@ export default class EntryFormAbility extends FormExtensionAbility { onUpdateForm(formId: string) { CommonUtils.createRdbStore(this.context).then((rdbStore: relationalStore.RdbStore) => { CommonUtils.updateMovieCardData(rdbStore); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.TAG_FORM_ABILITY, 'onUpdateForm create rdb error ' + JSON.stringify(error)); }); - // Refresh every five minutes. - formProvider.setFormNextRefreshTime(formId, CommonConstants.FIVE_MINUTES, (error, data) => { - if (error) { - Logger.error(CommonConstants.TAG_FORM_ABILITY, 'update setTime error' + JSON.stringify(error)); - } else { - Logger.info(CommonConstants.TAG_FORM_ABILITY, 'update setTime success ' + JSON.stringify(data)); - } - }); } onRemoveForm(formId: string) { // Deleting card information from the database. CommonUtils.createRdbStore(this.context).then((rdbStore: relationalStore.RdbStore) => { CommonUtils.deleteFormData(formId, rdbStore); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.TAG_FORM_ABILITY, 'removeForm create rdb error ' + JSON.stringify(error)); }); } diff --git a/Card/MovieCard/entry/src/main/ets/pages/MovieDetailsPage.ets b/Card/MovieCard/entry/src/main/ets/pages/MovieDetailsPage.ets index baa66f361d11e331228247ab5c992923b5ccec03..b4c693fc0038e32ad852616ff7d4ebcfb4802627 100644 --- a/Card/MovieCard/entry/src/main/ets/pages/MovieDetailsPage.ets +++ b/Card/MovieCard/entry/src/main/ets/pages/MovieDetailsPage.ets @@ -19,23 +19,26 @@ import MovieStarring from '../view/MovieStarring'; import CommonConstants from '../common/constants/CommonConstants'; import StyleConstants from '../common/constants/StyleConstants'; import CommonUtils from '../common/utils/CommonUtils'; -import MovieDataBean from '../common/bean/MovieDataBean'; +import MovieDataBean from '../viewmodel/MovieDataBean'; import StoryIntroduce from '../view/StoryIntroduce'; import MovieDetailsTitle from '../view/MovieDetailsTitle'; import Logger from '../common/utils/Logger'; +import { GlobalContext } from '../common/utils/GlobalContext'; @Entry @Component struct MovieDetailPage { - private introduction: string; - private movieData: MovieDataBean; + private introduction: string = ''; + private movieData: MovieDataBean = new MovieDataBean(); aboutToAppear() { let index: number = 0; - if (!CommonUtils.isEmpty(router.getParams())) { - index = router.getParams()[CommonConstants.INDEX_KEY] ?? 0; + let params = router.getParams() as Record; + if (!CommonUtils.isEmpty(params)) { + index = params.index as number; } else { - index = globalThis.position ?? 0; + let position = GlobalContext.getContext().getObject('position') as number; + index = position ?? 0; } let listData: MovieDataBean[] = CommonUtils.getListData(); if (CommonUtils.isEmptyArr(listData)) { diff --git a/Card/MovieCard/entry/src/main/ets/pages/MovieListPage.ets b/Card/MovieCard/entry/src/main/ets/pages/MovieListPage.ets index c7bed75b03e3946bfbe689a92a882ebb2ca232dd..6b044a75986e190a391d46c3f9ccd8cf0726be25 100644 --- a/Card/MovieCard/entry/src/main/ets/pages/MovieListPage.ets +++ b/Card/MovieCard/entry/src/main/ets/pages/MovieListPage.ets @@ -15,9 +15,10 @@ import StyleConstants from '../common/constants/StyleConstants'; import DataSource from '../common/datasource/DataSource'; -import MovieDataBean from '../common/bean/MovieDataBean'; +import MovieDataBean from '../viewmodel/MovieDataBean'; import MovieItem from '../view/MovieItem'; import CommonUtils from '../common/utils/CommonUtils'; +import { GlobalContext } from '../common/utils/GlobalContext'; /** * MovieListPage is the program entry and displays movie ranking data. @@ -28,7 +29,7 @@ import CommonUtils from '../common/utils/CommonUtils'; @Component struct MovieListPage { // Lazy loading of matching data sources. - private dataSource: DataSource; + private dataSource: DataSource = new DataSource([]); aboutToAppear() { this.dataSource = new DataSource(CommonUtils.getListData()); @@ -37,7 +38,8 @@ struct MovieListPage { } aboutToDisappear() { - clearInterval(globalThis.intervalId); + let intervalId = GlobalContext.getContext().getObject('intervalId') as number; + clearInterval(intervalId); } build() { @@ -57,7 +59,7 @@ struct MovieListPage { ListItem() { MovieItem({ movieItem: item }); } - }, item => JSON.stringify(item)) + }, (item: MovieDataBean) => JSON.stringify(item)) } .listDirection(Axis.Vertical) .edgeEffect(EdgeEffect.None) diff --git a/Card/MovieCard/entry/src/main/ets/view/MovieDetailsTitle.ets b/Card/MovieCard/entry/src/main/ets/view/MovieDetailsTitle.ets index 7d4013a413c333f32cc061efbb689bd6edcaa672..07ff61689bc0e346ff00506251ddf00b80b3372f 100644 --- a/Card/MovieCard/entry/src/main/ets/view/MovieDetailsTitle.ets +++ b/Card/MovieCard/entry/src/main/ets/view/MovieDetailsTitle.ets @@ -16,18 +16,18 @@ import CommonConstants from '../common/constants/CommonConstants'; import StyleConstants from '../common/constants/StyleConstants'; import CommonUtils from '../common/utils/CommonUtils'; -import MovieDataBean from '../common/bean/MovieDataBean'; +import MovieDataBean from '../viewmodel/MovieDataBean'; import StarsWidget from './StarsWidget'; import Logger from '../common/utils/Logger'; @Component export default struct MovieDetailsTitle { - private movieDetail: MovieDataBean; - private movieImage: Resource; - private title: string; - private rating: string; - private stars: Resource[]; - private describe: string; + private movieDetail: MovieDataBean = new MovieDataBean(); + private movieImage: Resource = $r('app.media.ic_movie_one'); + private title: string = ''; + private rating: string = ''; + private stars: Resource[] = []; + private describe: string = ''; aboutToAppear() { if (CommonUtils.isEmpty(this.movieDetail)) { diff --git a/Card/MovieCard/entry/src/main/ets/view/MovieItem.ets b/Card/MovieCard/entry/src/main/ets/view/MovieItem.ets index df1204c0c47bf2c5cf8160a016a4a0f0cd7b1275..50cfe46c817c6349a5c6ade71de35780a1c6eee0 100644 --- a/Card/MovieCard/entry/src/main/ets/view/MovieItem.ets +++ b/Card/MovieCard/entry/src/main/ets/view/MovieItem.ets @@ -17,21 +17,21 @@ import router from '@ohos.router'; import Logger from '../common/utils/Logger'; import CommonConstants from '../common/constants/CommonConstants'; import StyleConstants from '../common/constants/StyleConstants'; -import MovieDataBean from '../common/bean/MovieDataBean'; +import MovieDataBean from '../viewmodel/MovieDataBean'; import StarsWidget from './StarsWidget'; import CommonUtils from '../common/utils/CommonUtils'; @Component export default struct MovieItem { - private movieItem: MovieDataBean; - private sort: number; - private isShowSort: boolean; - private sortImage: Resource; - private title: string; - private describe: string; - private movieImage: Resource; - private stars: Resource[]; - private rating: string; + private movieItem: MovieDataBean = new MovieDataBean(); + private sort: number = 0; + private isShowSort: boolean = true; + private sortImage: Resource = $r('app.media.ic_first'); + private title: string = '冰山姐妹'; + private describe: string = '讲述冰上女运动员之间团结友爱,互帮互助的故事'; + private movieImage: Resource = $r('app.media.ic_movie_one'); + private stars: Resource[] = []; + private rating: string = '9'; aboutToAppear() { if (CommonUtils.isEmpty(this.movieItem)) { @@ -103,7 +103,7 @@ export default struct MovieItem { params: { index: this.sort } - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.TAG_MOVIE_ITEM, 'push error ' + JSON.stringify(error)); }); }) diff --git a/Card/MovieCard/entry/src/main/ets/view/MovieStarring.ets b/Card/MovieCard/entry/src/main/ets/view/MovieStarring.ets index 0083c2a0d9c73460c98117a577c2bee5e52ff899..24b4a00e16ce06f6f20f67cb342a805843e8ade0 100644 --- a/Card/MovieCard/entry/src/main/ets/view/MovieStarring.ets +++ b/Card/MovieCard/entry/src/main/ets/view/MovieStarring.ets @@ -19,7 +19,7 @@ import DataSource from '../common/datasource/DataSource'; @Component export default struct MovieStarring { - private dataSource: DataSource; + private dataSource: DataSource = new DataSource([]); aboutToAppear() { this.dataSource = new DataSource(CommonUtils.getStarringData()); @@ -78,7 +78,7 @@ export default struct MovieStarring { .fontWeight(FontWeight.Normal) } } - }, item => JSON.stringify(item)) + }, (item: Resource) => JSON.stringify(item)) } .listDirection(Axis.Horizontal) .edgeEffect(EdgeEffect.None) diff --git a/Card/MovieCard/entry/src/main/ets/view/MovieStills.ets b/Card/MovieCard/entry/src/main/ets/view/MovieStills.ets index 11a55f3ce439269d6625a5b0e6fd6da6fba3fe2b..af4a8b652414ddfd3a4f4137a1e4f42bb68bb483 100644 --- a/Card/MovieCard/entry/src/main/ets/view/MovieStills.ets +++ b/Card/MovieCard/entry/src/main/ets/view/MovieStills.ets @@ -19,7 +19,7 @@ import DataSource from '../common/datasource/DataSource'; @Component export default struct MovieStills { - private dataSource: DataSource; + private dataSource: DataSource = new DataSource([]); aboutToAppear() { this.dataSource = new DataSource(CommonUtils.getStillsData()); @@ -61,7 +61,7 @@ export default struct MovieStills { .height($r('app.float.stills_image_height')) .borderRadius($r('app.float.stills_image_radius')) } - }, item => JSON.stringify(item)) + }, (item: Resource) => JSON.stringify(item)) } .listDirection(Axis.Horizontal) .edgeEffect(EdgeEffect.None) diff --git a/Card/MovieCard/entry/src/main/ets/view/StarsWidget.ets b/Card/MovieCard/entry/src/main/ets/view/StarsWidget.ets index d5ea6157535b8028ab9b520d476ca1eba46b0643..7cdbef68afcf938090a70df5e27eeb1b178d6fb9 100644 --- a/Card/MovieCard/entry/src/main/ets/view/StarsWidget.ets +++ b/Card/MovieCard/entry/src/main/ets/view/StarsWidget.ets @@ -18,18 +18,18 @@ import StyleConstants from '../common/constants/StyleConstants'; @Component export default struct StarsWidget { private rating: string = ''; - private stars: Resource[]; + private stars: Resource[] = []; build() { Row() { List({ space: StyleConstants.STARS_LIST_SPACE }) { - ForEach(this.stars, (item) => { + ForEach(this.stars, (item: Resource) => { ListItem() { Image(item) .width($r('app.float.stars_image_size')) .height($r('app.float.stars_image_size')) } - }, (item, index) => JSON.stringify(item) + index) + }, (item: Resource) => JSON.stringify(item)) } .listDirection(Axis.Horizontal) .edgeEffect(EdgeEffect.None) diff --git a/Card/MovieCard/entry/src/main/ets/view/StoryIntroduce.ets b/Card/MovieCard/entry/src/main/ets/view/StoryIntroduce.ets index 472f49af57a5027d540923e57def2e7c41b46dce..0de5a5ad5c420d652e2f8f5e55eb341fc775be65 100644 --- a/Card/MovieCard/entry/src/main/ets/view/StoryIntroduce.ets +++ b/Card/MovieCard/entry/src/main/ets/view/StoryIntroduce.ets @@ -19,7 +19,7 @@ import CommonConstants from '../common/constants/CommonConstants'; export default struct StoryIntroduce { @State tipsTextLines: number = CommonConstants.DEFAULT_LINES; @State tipsText: Resource = $r("app.string.expand_text"); - private introduction: string; + private introduction: string = ''; build() { Column() { diff --git a/Card/MovieCard/entry/src/main/ets/common/bean/FormBean.ets b/Card/MovieCard/entry/src/main/ets/viewmodel/FormBean.ets similarity index 84% rename from Card/MovieCard/entry/src/main/ets/common/bean/FormBean.ets rename to Card/MovieCard/entry/src/main/ets/viewmodel/FormBean.ets index d03831a42dee8d30990cc5f7054a573299cfc7a9..65f9f03524a65aeb84271126069d5aa5d1ae7000 100644 --- a/Card/MovieCard/entry/src/main/ets/common/bean/FormBean.ets +++ b/Card/MovieCard/entry/src/main/ets/viewmodel/FormBean.ets @@ -13,6 +13,8 @@ * limitations under the License. */ +import relationalStore from '@ohos.data.relationalStore'; + /** * Database form entity class. */ @@ -20,24 +22,22 @@ export default class FormBean { /** * Form ID */ - formId: string; - + formId: string = ''; /** * Form name */ - formName: string; - + formName: string = ''; /** * Card dimension */ - dimension: number; + dimension: number = 0; /** * Get inserted form data. * * @return Return form data */ - toValuesBucket() { + toValuesBucket(): relationalStore.ValuesBucket { return { 'formId': this.formId, 'formName': this.formName, diff --git a/Card/MovieCard/entry/src/main/ets/viewmodel/FormDataBean.ets b/Card/MovieCard/entry/src/main/ets/viewmodel/FormDataBean.ets new file mode 100644 index 0000000000000000000000000000000000000000..2d92d51b9bce378aea39a46fc103df7998ade22c --- /dev/null +++ b/Card/MovieCard/entry/src/main/ets/viewmodel/FormDataBean.ets @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export default interface FormDataBean { + topIndex: number; + topMovieImage: string; + topTitle: string; + topDescribe: string; + bottomIndex: number; + bottomMovieImage: string; + bottomTitle: string; + bottomDescribe: string; +} \ No newline at end of file diff --git a/Card/MovieCard/entry/src/main/ets/common/bean/MovieDataBean.ets b/Card/MovieCard/entry/src/main/ets/viewmodel/MovieDataBean.ets similarity index 69% rename from Card/MovieCard/entry/src/main/ets/common/bean/MovieDataBean.ets rename to Card/MovieCard/entry/src/main/ets/viewmodel/MovieDataBean.ets index d15ebc8163888498c631b3a40a6977936f39a54c..4b58bbb1d18bf69d5c525d39860ceeb92448dae9 100644 --- a/Card/MovieCard/entry/src/main/ets/common/bean/MovieDataBean.ets +++ b/Card/MovieCard/entry/src/main/ets/viewmodel/MovieDataBean.ets @@ -20,50 +20,41 @@ export default class MovieDataBean { /** * Movie sort number */ - sort: number; - + sort: number = 0; /** * Is show sort image */ - isShowSort: boolean; - + isShowSort: boolean = true; /*** * Movie sort image */ - sortImage: Resource; - + sortImage: Resource = $r('app.media.ic_first'); /** * Movie title */ - title: string; - + title: string = '冰上姐妹'; /** * Movie describe */ - describe: string; - + describe: string = '讲述冰上女运动员之间团结友爱,互帮互助的故事'; /** * Movie image */ - movieImage: Resource; - + movieImage: Resource = $r('app.media.ic_movie_one'); /** * Show card image */ - cardImage: string; - + cardImage: string = '/common/ic_movie_one.png'; /** * Movie stars */ - stars: Resource[]; - + stars: Resource[] = [$r('app.media.ic_star')]; /** * Movie rating */ - rating: string; - + rating: string = '9.5'; /** * Movie introduction */ - introduction: string; + introduction: string = '默认简介'; } \ No newline at end of file diff --git a/Card/MovieCard/hvigor/hvigor-config.json5 b/Card/MovieCard/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/Card/MovieCard/hvigor/hvigor-config.json5 +++ b/Card/MovieCard/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } -} +} \ No newline at end of file diff --git a/Card/StepsCardJS/README.md b/Card/StepsCardJS/README.md index 682ea2139d50ad27707b868cd326287fcecf07ad..69d0e964967cff0c877a84bb1519c91a63bb6d54 100644 --- a/Card/StepsCardJS/README.md +++ b/Card/StepsCardJS/README.md @@ -14,9 +14,9 @@ - [消息通知](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-notificationManager.md):提供通知管理的能力,包括发布、取消发布通知,创建、获取、移除通知通道,订阅、取消订阅通知,获取通知的使能状态、角标使能状态,获取通知的相关信息等。 - [关系型数据库](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-data-relationalStore.md):关系型数据库基于SQLite组件提供了一套完整的对本地数据库进行管理的机制,对外提供了一系列的增、删、改、查等接口,也可以直接运行用户输入的SQL语句来满足复杂的场景需要。 - [元服务卡片开发](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-app-form-formExtensionAbility.md):卡片是一种界面展示形式,可以将应用的重要信息或操作前置到卡片,以达到服务直达、减少体验层级的目的。 - - 卡片提供方:显示卡片内容,控制卡片布局以及控件点击事件。 - - 卡片使用方:显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。 - - 卡片管理服务:用于管理系统中所添加卡片的常驻代理服务,包括卡片对象的管理与使用,以及卡片周期性刷新等。 +- 卡片提供方:显示卡片内容,控制卡片布局以及控件点击事件。 +- 卡片使用方:显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。 +- 卡片管理服务:用于管理系统中所添加卡片的常驻代理服务,包括卡片对象的管理与使用,以及卡片周期性刷新等。 @@ -24,13 +24,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -58,11 +58,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──ChartPoint.ets // 图表点bean -│ │ │ ├──ChartValues.ets // 图表值bean -│ │ │ ├──FormData.ets // 表单数据bean -│ │ │ └──PointStyle.ets // 图表点样式bean │ │ ├──constants │ │ │ └──CommonConstants.ets // 常量类 │ │ ├──database @@ -72,13 +67,19 @@ │ │ ├──ChartDataUtils.ets // 图表数据操作工具类 │ │ ├──DatabaseUtils.ets // 数据库工具类 │ │ ├──DateUtils.ets // 日期工具类 +│ │ ├──GlobalContext.ets // 项目工具类 │ │ └──Logger.ets // 日志打印工具类 │ ├──entryability │ │ └──EntryAbility.ets // 程序入口类 │ ├──entryformability │ │ └──EntryFormAbility.ets // 卡片创建,更新,删除操作类 -│ └──pages -│ └──MainPage.ets // 主界面 +│ ├──pages +│ │ └──MainPage.ets // 主界面 +│ └──viewmodel +│ ├──ChartPoint.ets // 图表点类 +│ ├──ChartValues.ets // 图表值类 +│ ├──FormData.ets // 表单数据类 +│ └──PointStyle.ets // 图表点样式类 ├──entry/src/main/js // js代码区 │ ├──card2x2 // 2x2卡片目录 │ ├──card2x4 // 2x4卡片目录 @@ -93,30 +94,31 @@ 1. 数据库创建使用的SQLite。 - ```typescript - // CommonConstants.ets - // 表单SQLite - static readonly CREATE_TABLE_FORM: string = 'CREATE TABLE IF NOT EXISTS Form ' + - '(id INTEGER PRIMARY KEY AUTOINCREMENT, formId STRING, formName STRING, dimension INTEGER)'; - // 行走步数SQLite - static readonly CREATE_TABLE_SENSOR_DATA: string = 'CREATE TABLE IF NOT EXISTS SensorData ' + - '(id INTEGER PRIMARY KEY AUTOINCREMENT, date STRING, stepsValue INTEGER)'; - ``` +```typescript + // CommonConstants.ets + // 表单SQLite + static readonly CREATE_TABLE_FORM: string = 'CREATE TABLE IF NOT EXISTS Form ' + + '(id INTEGER PRIMARY KEY AUTOINCREMENT, formId TEXT NOT NULL, formName TEXT NOT NULL, dimension INTEGER)'; + // 行走步数SQLite + static readonly CREATE_TABLE_SENSOR_DATA: string = 'CREATE TABLE IF NOT EXISTS SensorData ' + + '(id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT NOT NULL, stepsValue INTEGER)'; +``` 2. 在EntryAbility的onCreate方法通过DatabaseUtils.createRdbStore方法创建数据库,并创建相应的表。 - ```typescript - // EntryAbility.ets - onCreate(want: Want) { - globalThis.abilityWant = want; - DatabaseUtils.createRdbStore(this.context).then((rdbStore: DataRdb.RdbStore) => { - // 添加前三天行走模拟数据 - DatabaseUtils.addSimulationData(rdbStore); - }).catch((error) => { - ... - }); - } - ``` +```typescript + // EntryAbility.ets + onCreate(want: Want, param: AbilityConstant.LaunchParam): void { + GlobalContext.getContext().setObject('abilityWant', want); + GlobalContext.getContext().setObject('abilityParam', param); + DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => { + // 添加前三天行走模拟数据 + DatabaseUtils.addSimulationData(rdbStore as DataRdb.RdbStore); + }).catch((error: Error) => { + ... + }); + } +``` ## 消息通知 @@ -135,7 +137,7 @@ aboutToAppear() { requestNotification() { Notification.requestEnableNotification().then(() => { ... - }).catch((err) => { + }).catch((err: Error) => { ... }); } @@ -150,28 +152,27 @@ requestNotification() { // 发送通知 sendNotifications(stepsValue: string, notificationId: number) { // 获取当前系统语言 - let Language: string = I18n.System.getSystemLanguage(); let notificationBarTitle: string; + let Language: string = I18n.System.getSystemLanguage(); // 判断是否为中文 if (Language.match(CommonConstants.CHINESE_LANGUAGE)) { - notificationBarTitle = CommonConstants.NOTIFICATIONS_TITLE_GONE_TODAY_ZH + - stepsValue + CommonConstants.NOTIFICATIONS_TITLE_STEPS_ZH; + notificationBarTitle = CommonConstants.NOTIFICATIONS_TITLE_GONE_TODAY_ZH + + stepsValue + CommonConstants.NOTIFICATIONS_TITLE_STEPS_ZH; } else { - notificationBarTitle = CommonConstants.NOTIFICATIONS_TITLE_GONE_TODAY_EN + - stepsValue + CommonConstants.NOTIFICATIONS_TITLE_STEPS_EN; + notificationBarTitle = CommonConstants.NOTIFICATIONS_TITLE_GONE_TODAY_EN + + stepsValue + CommonConstants.NOTIFICATIONS_TITLE_STEPS_EN; } - // 构造NotificationRequest对象. - let notificationRequest = { - id: notificationId, + // 发布NotificationRequest. + Notification.publish({ + id: CommonConstants.NOTIFICATIONS_ID, content: { - contentType: Notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, - normal: { - title: notificationBarTitle, - text: '' - } + contentType: Notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, + normal: { + title: notificationBarTitle, + text: '' + } } - }; - Notification.publish(notificationRequest).then(() => { + }).then(() => { ... }); } @@ -210,19 +211,23 @@ sendNotifications(stepsValue: string, notificationId: number) { ```typescript // EntryFormAbility.ets onAddForm(want: Want) { - let formId: string = want.parameters[CommonConstants.FORM_PARAM_IDENTITY_KEY] as string; - let formName: string = want.parameters[CommonConstants.FORM_PARAM_NAME_KEY] as string; - let dimensionFlag: number = want.parameters[CommonConstants.FORM_PARAM_DIMENSION_KEY] as number; + let formId: string = want.parameters !== undefined ? + want.parameters[CommonConstants.FORM_PARAM_IDENTITY_KEY] as string : ''; + let formName: string = want.parameters !== undefined ? + want.parameters[CommonConstants.FORM_PARAM_NAME_KEY] as string : ''; + let dimensionFlag: number = want.parameters !== undefined ? + want.parameters[CommonConstants.FORM_PARAM_DIMENSION_KEY] as number : 0; // 创建数据库 - DatabaseUtils.createRdbStore(this.context).then((rdbStore: DataRdb.RdbStore) => { + DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => { // 存储卡片信息 let form: Form = new Form(); form.formId = formId; form.formName = formName; form.dimension = dimensionFlag; ... - DatabaseUtils.insertForm(form, rdbStore); - }).catch((error) => { + DatabaseUtils.insertForm(form, rdbStore as DataRdb.RdbStore); + getToDaySteps(rdbStore as DataRdb.RdbStore, dimensionFlag, formId); + }).catch((error: Error) => { ... }); ... @@ -237,133 +242,134 @@ onAddForm(want: Want) { ### 更新元服务卡片 1. 初始化加载主页面布局之前,在MainPage的aboutToAppear方法中,调用setInterval方法开启定时器。时间到则先通过DatabaseUtils.insertValues方法把步数插入到数据库,再通过DatabaseUtils.updateForms方法更新卡片步数。 - ```typescript - // MainPage.ets - aboutToAppear() { - ... - DatabaseUtils.getSensorData(globalThis.rdbStore, DateUtils.getDate(0)) - .then((sensorData: SensorData) => { - if (sensorData != null) { - this.stepsValue = sensorData.stepsValue; - } - // 开启定时器 - this.intervalId = setInterval(() => { - ... - DatabaseUtils.insertValues(this.stepsValue, globalThis.rdbStore); - DatabaseUtils.updateForms(this.stepsValue,globalThis.rdbStore); - }, CommonConstants.INTERVAL_DELAY_TIME); - }); - } - - // DatabaseUtils.ets - updateForms(stepValue: number, rdbStore: DataRdb.RdbStore) { - let predicates: DataRdb.RdbPredicates = - new DataRdb.RdbPredicates(CommonConstants.TABLE_FORM); - // 查询卡片 - rdbStore.query(predicates).then((resultSet: DataRdb.ResultSet) => { - ... - // 查询第一行 - resultSet.goToFirstRow(); - do { - let formId: string = resultSet.getString(resultSet.getColumnIndex(CommonConstants.FIELD_FORM_ID)); - let dimension: number = resultSet.getLong(resultSet.getColumnIndex(CommonConstants.FIELD_DIMENSION)); - ChartDataUtils.getFormData(formId, stepValue, dimension, rdbStore) - .then((formData: FormData) => { - // 更新多张卡片 - FormProvider.updateForm(formData.formId, FormBindingData.createFormBindingData(formData)) - .catch((error) => { - ... - }); - }).catch((error) => { - ... - }); - } while (resultSet.goToNextRow()); - resultSet.close(); - }).catch((error) => { - ... - }); - } - ``` +```typescript +// MainPage.ets +aboutToAppear() { + ... + DatabaseUtils.getSensorData(rdbStoreValue, DateUtils.getDate(0)) + .then((sensorData: SensorData) => { + if (sensorData) { + this.stepsValue = sensorData.stepsValue; + } + // 开启定时器 + this.intervalId = setInterval(() => { + ... + DatabaseUtils.insertValues(this.stepsValue, rdbStoreValue); + DatabaseUtils.updateForms(this.stepsValue, rdbStoreValue); + }, CommonConstants.INTERVAL_DELAY_TIME); + ... + }); +} + +// DatabaseUtils.ets +updateForms(stepValue: number, rdbStore: DataRdb.RdbStore) { + let predicates: DataRdb.RdbPredicates = + new DataRdb.RdbPredicates(CommonConstants.TABLE_FORM); + // 查询卡片 + rdbStore.query(predicates).then((resultSet: DataRdb.ResultSet) => { + ... + // 查询第一行 + resultSet.goToFirstRow(); + do { + let formId: string = resultSet.getString(resultSet.getColumnIndex(CommonConstants.FIELD_FORM_ID)); + let dimension: number = resultSet.getLong(resultSet.getColumnIndex(CommonConstants.FIELD_DIMENSION)); + ChartDataUtils.getFormData(formId, stepValue, dimension, rdbStore) + .then((formData: FormData) => { + // 更新多张卡片 + FormProvider.updateForm(formData.formId, FormBindingData.createFormBindingData(formData)) + .catch((error: Error) => { + ... + }); + }).catch((error: Error) => { + ... + }); + } while (resultSet.goToNextRow()); + resultSet.close(); + }).catch((error: Error) => { + ... + }); +} +``` 2. 卡片添加到桌面后,在EntryFormAbility的onAddForm方法中,调用formProvider.setFormNextRefreshTime方法设置倒计时。时间到了则通过updateSensorData方法更新卡片步数。 - ```typescript - // EntryFormAbility.ets - onAddForm(want: Want) { - ... - // 五分钟倒计时 - formProvider.setFormNextRefreshTime(formId, CommonConstants.FIVE_MINUTES, (error, data) => { - ... - }); - } - - onUpdateForm(formId: string) { - // 更新步数 - updateSensorData(); - ... - } - - function updateSensorData() { - DatabaseUtils.createRdbStore(this.context).then((rdbStore: DataRdb.RdbStore) => { - ... - // 获取今天步数 - let getSensorData: Promise = DatabaseUtils.getSensorData(rdbStore, - DateUtils.getDate(0)); - getSensorData.then((sensorData: SensorData) => { - let stepValue: number = 0; - if (sensorData) { - stepValue = sensorData.stepsValue; - } - // 更新卡片数据 - DatabaseUtils.updateForms(stepValue, rdbStore); - }).catch((error) => { - ... - }); - }).catch((error) => { - ... - }); - } - ``` +```typescript + // EntryFormAbility.ets + onAddForm(want: Want) { + ... + // 五分钟倒计时 + formProvider.setFormNextRefreshTime(formId, CommonConstants.FIVE_MINUTES, (error, data) => { + ... + }); + } + + onUpdateForm(formId: string) { + // 更新步数 + this.updateSensorData(); + ... + } + + updateSensorData() { + DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => { + ... + // 获取今天步数 + let getSensorData: Promise = + DatabaseUtils.getSensorData(rdbStore as DataRdb.RdbStore, DateUtils.getDate(0)); + getSensorData.then((sensorData: SensorData) => { + let stepValue: number = 0; + if (sensorData) { + stepValue = sensorData.stepsValue; + } + // 更新卡片数据 + DatabaseUtils.updateForms(stepValue, rdbStore); + }).catch((error: Error) => { + ... + }); + }).catch((error: Error) => { + ... + }); + } +``` 3. 通过src/main/resources/base/profile/form_config.json配置文件,根据updateDuration或者scheduledUpdateTime字段配置刷新时间。updateDuration优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration配置的刷新时间为准。当配置的刷新时间到了,系统调用onUpdateForm方法进行更新。 - ```typescript - // form_config.json - { - // 卡片的类名 - "name": "card2x2", - // 卡片的描述 - "description": "This is a service widget.", - // 卡片对应完整路径 - "src": "./js/card2x2/pages/index/index", - // 定义与显示窗口相关的配置 - "window": { - "designWidth": 720, - "autoDesignWidth": true - }, - // 卡片的主题样式 - "colorMode": "auto", - // 是否为默认卡片 - "isDefault": true, - // 卡片是否支持周期性刷新 - "updateEnabled": true, - // 采用24小时制,精确到分钟 - "scheduledUpdateTime": "00:00", - // 当取值为0时,表示该参数不生效,当取值为正整数N时,表示刷新周期为30*N分钟。 - "updateDuration": 1, - // 卡片默认外观规格 - "defaultDimension": "2*2", - // 卡片支持外观规格 - "supportDimensions": [ - "2*2" - ] - } - - // EntryFormAbility.ets - onUpdateForm(formId: string) { - // 更新步数 - updateSensorData(); - ... - } - ``` +```typescript + // form_config.json + { + // 卡片的类名 + "name": "card2x2", + // 卡片的描述 + "description": "This is a service widget.", + // 卡片对应完整路径 + "src": "./js/card2x2/pages/index/index", + // 定义与显示窗口相关的配置 + "window": { + "designWidth": 720, + "autoDesignWidth": true + }, + // 卡片的主题样式 + "colorMode": "auto", + // 是否为默认卡片 + "isDefault": true, + // 卡片是否支持周期性刷新 + "updateEnabled": true, + // 采用24小时制,精确到分钟 + "scheduledUpdateTime": "00:00", + // 当取值为0时,表示该参数不生效,当取值为正整数N时,表示刷新周期为30*N分钟。 + "updateDuration": 1, + // 卡片默认外观规格 + "defaultDimension": "2*2", + // 卡片支持外观规格 + "supportDimensions": [ + "2*2" + ] + } + + // EntryFormAbility.ets + onUpdateForm(formId: string) { + // 更新步数 + updateSensorData(); + ... + } +``` ### 删除元服务卡片 @@ -371,11 +377,11 @@ onAddForm(want: Want) { ```typescript // EntryFormAbility.ets onRemoveForm(formId: string) { - DatabaseUtils.createRdbStore(this.context).then((rdbStore: DataRdb.RdbStore) => { + DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => { ... // 删除数据库中对应的卡片信息 - DatabaseUtils.deleteFormData(formId, rdbStore); - }).catch((error) => { + DatabaseUtils.deleteFormData(formId, rdbStore as DataRdb.RdbStore); + }).catch((error: Error) => { ... }); } @@ -384,7 +390,7 @@ onRemoveForm(formId: string) { deleteFormData(formId: string, rdbStore: DataRdb.RdbStore) { let predicates: DataRdb.RdbPredicates = new DataRdb.RdbPredicates(CommonConstants.TABLE_FORM); predicates.equalTo(CommonConstants.FIELD_FORM_ID, formId); - rdbStore.delete(predicates).catch((error) => { + rdbStore.delete(predicates).catch((error: Error) => { ... }); } diff --git a/Card/StepsCardJS/entry/src/main/ets/common/constants/CommonConstants.ets b/Card/StepsCardJS/entry/src/main/ets/common/constants/CommonConstants.ets index e4235f65a315a1c1cca7fb994d6869fcb599ce20..d3a80202111a87c92b998f16e029998bdf34140b 100644 --- a/Card/StepsCardJS/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/Card/StepsCardJS/entry/src/main/ets/common/constants/CommonConstants.ets @@ -23,256 +23,206 @@ export default class CommonConstants { * The entry ability tag. */ static readonly ENTRY_ABILITY_TAG: string = 'EntryAbility'; - /** * The main page tag. */ static readonly MAIN_PAGE_TAG: string = 'MainPage'; - /** * The entry form ability tag. */ static readonly ENTRY_FORM_ABILITY_TAG: string = 'EntryFormAbility'; - /** * The database tag. */ static readonly DATABASE_TAG: string = 'DatabaseUtils'; - /** * The chart data tag. */ static readonly TAG_CHART: string = 'ChartDataUtils'; - /** * Database store configuration. */ static readonly RDB_STORE_CONFIG: relationalStore.StoreConfig = { name: 'FormDatabase.db', securityLevel: relationalStore.SecurityLevel.S1, encrypt: false }; - /** * SQL statement for creating a form. */ static readonly CREATE_TABLE_FORM: string = 'CREATE TABLE IF NOT EXISTS Form ' + '(id INTEGER PRIMARY KEY AUTOINCREMENT, formId TEXT NOT NULL, formName TEXT NOT NULL, dimension INTEGER)'; - /** * SQL statement for creating steps. */ static readonly CREATE_TABLE_SENSOR_DATA: string = 'CREATE TABLE IF NOT EXISTS SensorData ' + '(id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT NOT NULL, stepsValue INTEGER)'; - /** * Table sensor name. */ static readonly TABLE_SENSOR: string = 'SensorData'; - /** * Table form name. */ static readonly TABLE_FORM: string = 'Form'; - /** * Step count superimposed value. */ static readonly INTERVAL_STEPS_VALUE: number = 2; - /** * Time interval. */ static readonly INTERVAL_DELAY_TIME: number = 10000; - /** - * The notification id is increased by 1. + * Notification ID. */ - static readonly ID_VALUE: number = 1; - + static readonly NOTIFICATIONS_ID: number = 1008; /** * Chinese field judgment. */ static readonly CHINESE_LANGUAGE: string = 'zh'; - /** * Title of the notification bar in Chinese. */ static readonly NOTIFICATIONS_TITLE_GONE_TODAY_ZH: string = '今天走了'; - /** * Title of the notification bar in English. */ static readonly NOTIFICATIONS_TITLE_GONE_TODAY_EN: string = 'Gone today '; - /** * Title of the notification bar in Chinese. */ static readonly NOTIFICATIONS_TITLE_STEPS_ZH: string = '步'; - /** * Title of the notification bar in English. */ static readonly NOTIFICATIONS_TITLE_STEPS_EN: string = ' steps'; - /** * Form ID field in the database table. */ static readonly FIELD_FORM_ID: string = 'formId'; - /** * Specification fields in the database table. */ static readonly FIELD_DIMENSION: string = 'dimension'; - /** * Time field in the database table. */ static readonly FIELD_DATE_NAME: string = 'date'; - /** * Steps value field in the database table. */ static readonly FIELD_STEPS_NAME: string = 'stepsValue'; - /** * Top margin of main page text. */ static readonly MAIN_TITLE_TEXT_MARGIN_TOP: number = 243; - /** * Bottom margin of main page text. */ static readonly MAIN_TITLE_TEXT_MARGIN_BOTTOM: number = 30; - /** * Main page title text size. */ static readonly MAIN_TITLE_TEXT_FONT_SIZE: number = 20; - /** * Main page content text size. */ static readonly MAIN_CONTENT_TEXT_FONT_SIZE: number = 60; - /** * ID parameter for creating a form. */ static readonly FORM_PARAM_IDENTITY_KEY: string = 'ohos.extra.param.key.form_identity'; - /** * Name parameter for creating a form. */ static readonly FORM_PARAM_NAME_KEY: string = 'ohos.extra.param.key.form_name'; - /** * Dimension parameter for creating a form. */ static readonly FORM_PARAM_DIMENSION_KEY: string = 'ohos.extra.param.key.form_dimension'; - /** * Refresh time, in seconds. */ static readonly FORM_NEXT_REFRESH_TIME: number = 5; - /** * Chart point text position. */ static readonly TEXT_LOCATION: string = 'top'; - /** * Chart point draw shape. */ static readonly SHAPE_CIRCLE: string = 'circle'; - /** * Fill white color. */ static readonly WHITE_COLOR: string = '#FFFFFF'; - /** * Fill line color. */ static readonly CHART_VALUES_STROKE_COLOR: string = '#40FFFFFF'; - /** * Chart point fill color. */ static readonly CHART_VALUES_FILL_COLOR: string = '#00000000'; - /** * Target steps. */ static readonly TARGET_STEPS: number = 1000; - /** * 2x2 Card steps progress. */ static readonly HUNDRED_PERCENT: number = 100; - /** * 2x4 Card dimension. */ static readonly DIMENSION_TWO_BY_FOUR: number = 3; - /** * Chart point size. */ static readonly POINT_SIZE: number = 5; - /** * Meter per step. */ static readonly METER_PER_STEP: number = 0.6; - /** * Obtain the data of the last three days. */ static readonly THE_FIRST_THREE_DAYS: number = 3; - /** * Number of milliseconds in a day. */ static readonly TODAY_MILLI_SECOND: number = 86400000; - /** * Add yesterday's simulation data. */ static readonly SIMULATION_YESTERDAY_VALUE: number = 800; - /** * Add the simulation data of the day before yesterday. */ static readonly SIMULATION_BEFORE_YESTERDAY_VALUE: number = 560; - /** * Add the simulation data of three days ago. */ static readonly SIMULATION_THREE_DAYS_AGO_VALUE: number = 990; - /** * Current month plus one. */ static readonly MONTH_PLUS_ONE: number = 1; - /** * Yesterday's value. */ static readonly YESTERDAY: number = 1; - /** * Value of the day before yesterday. */ static readonly BEFORE_YESTERDAY: number = 2; - /** * The value three days ago. */ static readonly THREE_DAYS_AGO: number = 3; - /** * Width the percentage of the 100. */ static readonly FULL_WIDTH: string = '100%'; - /** * Height the percentage of the 100. */ diff --git a/Card/StepsCardJS/entry/src/main/ets/common/database/Form.ets b/Card/StepsCardJS/entry/src/main/ets/common/database/Form.ets index f970899a0ff9cacfa46694d71bf39d2c6f2b386d..8b36159b926652051ffd5d6bf271daf906694ba3 100644 --- a/Card/StepsCardJS/entry/src/main/ets/common/database/Form.ets +++ b/Card/StepsCardJS/entry/src/main/ets/common/database/Form.ets @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import relationalStore from '@ohos.data.relationalStore'; /** * Database form entity class. @@ -20,28 +21,26 @@ export default class Form { /** * Form ID. */ - formId: string; - + formId: string = ''; /** * Form name. */ - formName: string; - + formName: string = ''; /** * Card dimension. */ - dimension: number; + dimension: number = 0; /** * Get inserted form data. * * @return Return form data. */ - toValuesBucket() { + toValuesBucket(): relationalStore.ValuesBucket { return { 'formId': this.formId, 'formName': this.formName, 'dimension': this.dimension }; } -} +} \ No newline at end of file diff --git a/Card/StepsCardJS/entry/src/main/ets/common/database/SensorData.ets b/Card/StepsCardJS/entry/src/main/ets/common/database/SensorData.ets index d9d97b124908cba68fe5120d1b46066a4cab0d5a..cef430b3cdb31461422703644ddeec97ad07e4be 100644 --- a/Card/StepsCardJS/entry/src/main/ets/common/database/SensorData.ets +++ b/Card/StepsCardJS/entry/src/main/ets/common/database/SensorData.ets @@ -13,6 +13,8 @@ * limitations under the License. */ +import relationalStore from '@ohos.data.relationalStore'; + /** * Database sensor steps entity class. */ @@ -20,22 +22,21 @@ export default class SensorData { /** * Time of walking steps. */ - date: string; - + date: string = ''; /** * Value of steps. */ - stepsValue: number; + stepsValue: number = 0; /** * Gets the number of steps to insert a form. * * @return Return steps. */ - toValuesBucket() { + toValuesBucket(): relationalStore.ValuesBucket { return { 'date': this.date, 'stepsValue': this.stepsValue }; } -} +} \ No newline at end of file diff --git a/Card/StepsCardJS/entry/src/main/ets/common/utils/ChartDataUtils.ets b/Card/StepsCardJS/entry/src/main/ets/common/utils/ChartDataUtils.ets index 489d104a09ba9c0bf6fc4ca828910aedecd7c4ba..830719f564266faf23c50a3ad852147354d38e65 100644 --- a/Card/StepsCardJS/entry/src/main/ets/common/utils/ChartDataUtils.ets +++ b/Card/StepsCardJS/entry/src/main/ets/common/utils/ChartDataUtils.ets @@ -14,12 +14,12 @@ */ import DataRdb from '@ohos.data.relationalStore'; -import ChartValues from '../bean/ChartValues'; -import ChartPoint from '../bean/ChartPoint'; -import PointStyle from '../bean/PointStyle'; +import ChartValues from '../../viewmodel/ChartValues'; +import ChartPoint from '../../viewmodel/ChartPoint'; +import PointStyle from '../../viewmodel/PointStyle'; import DatabaseUtils from './DatabaseUtils'; import CommonConstants from '../constants/CommonConstants'; -import FormData from '../bean/FormData'; +import FormData from '../../viewmodel/FormData'; import Logger from '../utils/Logger'; /** @@ -33,7 +33,7 @@ export class ChartDataUtils { * @return Return the steps value of the last three days. */ async getChartPoints(rdbStore: DataRdb.RdbStore) { - let chartPoints = await DatabaseUtils.getLastThreeDaysValue(rdbStore).catch((error) => { + let chartPoints = await DatabaseUtils.getLastThreeDaysValue(rdbStore).catch((error: Error) => { Logger.error(CommonConstants.TAG_CHART, 'getLastThreeDaysValue error ' + JSON.stringify(error)); }); return chartPoints; @@ -54,16 +54,16 @@ export class ChartDataUtils { chartValues.strokeColor = CommonConstants.CHART_VALUES_STROKE_COLOR; chartValues.gradient = true; // Gets a collection of points from the previous three days. - let chartPoints: Array; - await this.getChartPoints(rdbStore).then((pointArray: Array) => { - chartPoints = pointArray; - }).catch((error) => { + let chartPoints: ChartPoint[]; + await this.getChartPoints(rdbStore).then((pointArray: ChartPoint[] | void) => { + chartPoints = pointArray as ChartPoint[]; + let nowChartPoint: ChartPoint = this.getChartPoint(stepsValue); + // Join today's steps value. + chartPoints.push(nowChartPoint); + chartValues.data = chartPoints; + }).catch((error: Error) => { Logger.error(CommonConstants.TAG_CHART, 'getChartPoints error ' + JSON.stringify(error)); }); - let nowChartPoint: ChartPoint = this.getChartPoint(stepsValue); - // Join today's steps value. - chartPoints.push(nowChartPoint); - chartValues.data = chartPoints; return chartValues; } @@ -116,7 +116,7 @@ export class ChartDataUtils { // Get chart point set data. await this.getChartValues(stepValue, rdbStore).then((result) => { dataSets.push(result); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.TAG_CHART, 'getFormData chartValues error ' + JSON.stringify(error)); }); // Add Field. diff --git a/Card/StepsCardJS/entry/src/main/ets/common/utils/DatabaseUtils.ets b/Card/StepsCardJS/entry/src/main/ets/common/utils/DatabaseUtils.ets index 77f16950eaa97c391a1152e35e4848474668d9a6..2a9e9752cb40b7bf5be2e46f8824e4dcd5ed061e 100644 --- a/Card/StepsCardJS/entry/src/main/ets/common/utils/DatabaseUtils.ets +++ b/Card/StepsCardJS/entry/src/main/ets/common/utils/DatabaseUtils.ets @@ -21,11 +21,12 @@ import FormBindingData from '@ohos.app.form.formBindingData'; import Form from '../database/Form'; import SensorData from '../database/SensorData'; import DateUtils from './DateUtils'; -import ChartPoint from '../bean/ChartPoint'; +import ChartPoint from '../../viewmodel/ChartPoint'; import ChartDataUtils from '../utils/ChartDataUtils'; import CommonConstants from '../constants/CommonConstants'; -import FormData from '../bean/FormData'; +import FormData from '../../viewmodel/FormData'; import Logger from '../utils/Logger'; +import { GlobalContext } from './GlobalContext'; /** * Database operation tool class. @@ -38,23 +39,23 @@ export class DatabaseUtils { * @return {globalThis.rdbStore} return rdbStore RDB database */ async createRdbStore(context: Context) { - if (!globalThis.rdbStore) { + if (!GlobalContext.getContext().getObject('rdbStore')) { await DataRdb.getRdbStore(context, CommonConstants.RDB_STORE_CONFIG) .then((rdbStore: DataRdb.RdbStore) => { if (rdbStore) { - rdbStore.executeSql(CommonConstants.CREATE_TABLE_FORM).catch((error) => { + rdbStore.executeSql(CommonConstants.CREATE_TABLE_FORM).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'executeSql Form error ' + JSON.stringify(error)); }); - rdbStore.executeSql(CommonConstants.CREATE_TABLE_SENSOR_DATA).catch((error) => { + rdbStore.executeSql(CommonConstants.CREATE_TABLE_SENSOR_DATA).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'executeSql Sensor error ' + JSON.stringify(error)); }); - globalThis.rdbStore = rdbStore; + GlobalContext.getContext().setObject('rdbStore', rdbStore); } - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'createRdbStore error ' + JSON.stringify(error)); }); } - return globalThis.rdbStore; + return GlobalContext.getContext().getObject('rdbStore'); } /** @@ -65,7 +66,7 @@ export class DatabaseUtils { * @return Return the operation information. */ insertForm(form: Form, rdbStore: DataRdb.RdbStore) { - rdbStore.insert(CommonConstants.TABLE_FORM, form.toValuesBucket()).catch((error) => { + rdbStore.insert(CommonConstants.TABLE_FORM, form.toValuesBucket()).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'insertForm error ' + JSON.stringify(error)); }); } @@ -89,7 +90,7 @@ export class DatabaseUtils { todayData.stepsValue = sensorData.stepsValue; let predicates: DataRdb.RdbPredicates = new DataRdb.RdbPredicates(CommonConstants.TABLE_SENSOR); predicates.equalTo(CommonConstants.FIELD_DATE_NAME, now); - rdbStore.update(todayData.toValuesBucket(), predicates).catch((error) => { + rdbStore.update(todayData.toValuesBucket(), predicates).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'insertValues update error ' + JSON.stringify(error)); }); } @@ -116,15 +117,15 @@ export class DatabaseUtils { ChartDataUtils.getFormData(formId, stepValue, dimension, rdbStore).then((formData: FormData) => { // Update multiple cards. FormProvider.updateForm(formData.formId, FormBindingData.createFormBindingData(formData)) - .catch((error) => { + .catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'updateForm error ' + JSON.stringify(error)); }); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'updateForms getFormData error ' + JSON.stringify(error)); }); } while (resultSet.goToNextRow()); resultSet.close(); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'updateForms query error ' + JSON.stringify(error)); }); } @@ -139,6 +140,7 @@ export class DatabaseUtils { let formPredicates: DataRdb.RdbPredicates = new DataRdb.RdbPredicates(CommonConstants.TABLE_SENSOR); formPredicates.equalTo(CommonConstants.FIELD_DATE_NAME, date); let sensorData: SensorData; + sensorData = new SensorData(); // To fix await rdbStore.query(formPredicates).then((resultSet: DataRdb.ResultSet) => { if (resultSet.rowCount <= 0) { Logger.error(CommonConstants.DATABASE_TAG, 'getSensorData rowCount <=0'); @@ -148,10 +150,10 @@ export class DatabaseUtils { let date: string = resultSet.getString(resultSet.getColumnIndex(CommonConstants.FIELD_DATE_NAME)); let stepsValue: number = resultSet.getLong(resultSet.getColumnIndex(CommonConstants.FIELD_STEPS_NAME)); resultSet.close(); - sensorData = new SensorData(); + sensorData.date = date; sensorData.stepsValue = stepsValue; - }).catch((err) => { + }).catch((err: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'Get Sensor Data, err: ' + JSON.stringify(err)); }); return sensorData; @@ -166,7 +168,7 @@ export class DatabaseUtils { deleteFormData(formId: string, rdbStore: DataRdb.RdbStore) { let predicates: DataRdb.RdbPredicates = new DataRdb.RdbPredicates(CommonConstants.TABLE_FORM); predicates.equalTo(CommonConstants.FIELD_FORM_ID, formId); - rdbStore.delete(predicates).catch((error) => { + rdbStore.delete(predicates).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'deleteFormData delete error ' + JSON.stringify(error)); }); } @@ -191,7 +193,7 @@ export class DatabaseUtils { results.push(ChartDataUtils.getChartPoint(stepsValue)); } resultSet.close(); - }).catch((err) => { + }).catch((err: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'getLastThreeDaysValue err: ' + JSON.stringify(err)); }); index--; @@ -203,21 +205,19 @@ export class DatabaseUtils { * Send Notifications * * @param {string} stepsValue Steps displayed. - * @param {number} notificationId Notification id. */ - async sendNotifications(stepsValue: string, notificationId: number) { + async sendNotifications(stepsValue: string) { let notificationBarTitle: string; let Language: string = I18n.System.getSystemLanguage(); if (Language.match(CommonConstants.CHINESE_LANGUAGE)) { - notificationBarTitle = CommonConstants.NOTIFICATIONS_TITLE_GONE_TODAY_ZH + + notificationBarTitle = CommonConstants.NOTIFICATIONS_TITLE_GONE_TODAY_ZH + stepsValue + CommonConstants.NOTIFICATIONS_TITLE_STEPS_ZH; } else { - notificationBarTitle = CommonConstants.NOTIFICATIONS_TITLE_GONE_TODAY_EN + + notificationBarTitle = CommonConstants.NOTIFICATIONS_TITLE_GONE_TODAY_EN + stepsValue + CommonConstants.NOTIFICATIONS_TITLE_STEPS_EN; } - // Construct the notificationRequest object. - let notificationRequest = { - id: notificationId, + Notification.publish({ + id: CommonConstants.NOTIFICATIONS_ID, content: { contentType: Notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { @@ -225,13 +225,9 @@ export class DatabaseUtils { text: '' } } - }; - Notification.publish(notificationRequest).then(() => { - if (notificationId > CommonConstants.ID_VALUE) { - // Cancel a sent message - Notification.cancel(notificationId - CommonConstants.ID_VALUE); - } - }).catch((err) => { + }).then(() => { + Logger.info(CommonConstants.DATABASE_TAG, 'publish promise success req.id : ' + CommonConstants.NOTIFICATIONS_ID); + }).catch((err: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'publish promise failed because ' + JSON.stringify(err)); }); } @@ -250,21 +246,21 @@ export class DatabaseUtils { let yesterday: SensorData = new SensorData(); yesterday.date = DateUtils.getDate(CommonConstants.YESTERDAY); yesterday.stepsValue = CommonConstants.SIMULATION_YESTERDAY_VALUE; - rdbStore.insert(CommonConstants.TABLE_SENSOR, yesterday.toValuesBucket()).catch((error) => { + rdbStore.insert(CommonConstants.TABLE_SENSOR, yesterday.toValuesBucket()).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'yesterday insert error ' + JSON.stringify(error)); }); // Add the simulation data of the day before yesterday. let beforeYesterday: SensorData = new SensorData(); beforeYesterday.date = DateUtils.getDate(CommonConstants.BEFORE_YESTERDAY) beforeYesterday.stepsValue = CommonConstants.SIMULATION_BEFORE_YESTERDAY_VALUE; - rdbStore.insert(CommonConstants.TABLE_SENSOR, beforeYesterday.toValuesBucket()).catch((error) => { + rdbStore.insert(CommonConstants.TABLE_SENSOR, beforeYesterday.toValuesBucket()).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'beforeYesterday insert error ' + JSON.stringify(error)); }); // Add the simulation data of three days ago. let threeDaysAgo: SensorData = new SensorData(); threeDaysAgo.date = DateUtils.getDate(CommonConstants.THREE_DAYS_AGO); threeDaysAgo.stepsValue = CommonConstants.SIMULATION_THREE_DAYS_AGO_VALUE; - rdbStore.insert(CommonConstants.TABLE_SENSOR, threeDaysAgo.toValuesBucket()).catch((error) => { + rdbStore.insert(CommonConstants.TABLE_SENSOR, threeDaysAgo.toValuesBucket()).catch((error: Error) => { Logger.error(CommonConstants.DATABASE_TAG, 'threeDaysAgo insert error ' + JSON.stringify(error)); }); } diff --git a/Card/StepsCardJS/entry/src/main/ets/common/utils/GlobalContext.ets b/Card/StepsCardJS/entry/src/main/ets/common/utils/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..23f5130a61c9e0ac09c5d885cdcaa2c878e0d522 --- /dev/null +++ b/Card/StepsCardJS/entry/src/main/ets/common/utils/GlobalContext.ets @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { + } + + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/Card/StepsCardJS/entry/src/main/ets/common/utils/Logger.ets b/Card/StepsCardJS/entry/src/main/ets/common/utils/Logger.ets index 9c03497a7ce71b3966d1ba60a676e8ff3d551d8e..6578abd79d46c5e8f763a9d302f5f756c2f0248b 100644 --- a/Card/StepsCardJS/entry/src/main/ets/common/utils/Logger.ets +++ b/Card/StepsCardJS/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: Object[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: Object[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: Object[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: Object[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Card/StepsCardJS/entry/src/main/ets/entryability/EntryAbility.ets b/Card/StepsCardJS/entry/src/main/ets/entryability/EntryAbility.ets index 5a9103074df9230e015784a44c59692a1ab2c5aa..387aebe94fb1bf515e85ad253cb97184986ed0f1 100644 --- a/Card/StepsCardJS/entry/src/main/ets/entryability/EntryAbility.ets +++ b/Card/StepsCardJS/entry/src/main/ets/entryability/EntryAbility.ets @@ -21,22 +21,23 @@ import window from '@ohos.window'; import Logger from '../common/utils/Logger'; import CommonConstants from '../common/constants/CommonConstants'; import DatabaseUtils from '../common/utils/DatabaseUtils'; +import { GlobalContext } from '../common/utils/GlobalContext'; /** * Lift cycle management of Ability. */ export default class EntryAbility extends UIAbility { - onCreate(want: Want, param: AbilityConstant.LaunchParam) { - globalThis.abilityWant = want; - globalThis.abilityParam = param; - DatabaseUtils.createRdbStore(this.context).then((rdbStore: DataRdb.RdbStore) => { - DatabaseUtils.addSimulationData(rdbStore); - }).catch((error) => { + onCreate(want: Want, param: AbilityConstant.LaunchParam): void { + GlobalContext.getContext().setObject('abilityWant', want); + GlobalContext.getContext().setObject('abilityParam', param); + DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => { + DatabaseUtils.addSimulationData(rdbStore as DataRdb.RdbStore); + }).catch((error: Error) => { Logger.error(CommonConstants.ENTRY_ABILITY_TAG, 'onCreate rdb error ' + JSON.stringify(error)); }); } - onWindowStageCreate(windowStage: window.WindowStage) { + onWindowStageCreate(windowStage: window.WindowStage): void { Logger.info(CommonConstants.ENTRY_ABILITY_TAG, 'onWindowStageCreate'); windowStage.loadContent('pages/MainPage', (err, data) => { if (err.code) { diff --git a/Card/StepsCardJS/entry/src/main/ets/entryformability/EntryFormAbility.ets b/Card/StepsCardJS/entry/src/main/ets/entryformability/EntryFormAbility.ets index 884683a8da46eafeda5795f8991c48187629c546..bae4bf2c0541e74302f2efe3685ec3da13b4441f 100644 --- a/Card/StepsCardJS/entry/src/main/ets/entryformability/EntryFormAbility.ets +++ b/Card/StepsCardJS/entry/src/main/ets/entryformability/EntryFormAbility.ets @@ -25,26 +25,29 @@ import DateUtils from '../common/utils/DateUtils'; import ChartDataUtils from '../common/utils/ChartDataUtils'; import SensorData from '../common/database/SensorData'; import CommonConstants from '../common/constants/CommonConstants'; -import FormData from '../common/bean/FormData'; +import FormData from '../viewmodel/FormData'; /** * Form management of Ability. */ export default class EntryFormAbility extends FormExtensionAbility { onAddForm(want: Want) { - let formId: string = want.parameters[CommonConstants.FORM_PARAM_IDENTITY_KEY] as string; - let formName: string = want.parameters[CommonConstants.FORM_PARAM_NAME_KEY] as string; - let dimensionFlag: number = want.parameters[CommonConstants.FORM_PARAM_DIMENSION_KEY] as number; - DatabaseUtils.createRdbStore(this.context).then((rdbStore: DataRdb.RdbStore) => { + let formId: string = want.parameters !== undefined ? + want.parameters[CommonConstants.FORM_PARAM_IDENTITY_KEY] as string : ''; + let formName: string = want.parameters !== undefined ? + want.parameters[CommonConstants.FORM_PARAM_NAME_KEY] as string : ''; + let dimensionFlag: number = want.parameters !== undefined ? + want.parameters[CommonConstants.FORM_PARAM_DIMENSION_KEY] as number : 0; + DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => { // Stores card information. let form: Form = new Form(); form.formId = formId; form.formName = formName; form.dimension = dimensionFlag; - DatabaseUtils.addSimulationData(rdbStore); - DatabaseUtils.insertForm(form, rdbStore); - getToDaySteps(rdbStore, dimensionFlag, formId); - }).catch((error) => { + DatabaseUtils.addSimulationData(rdbStore as DataRdb.RdbStore); + DatabaseUtils.insertForm(form, rdbStore as DataRdb.RdbStore); + getToDaySteps(rdbStore as DataRdb.RdbStore, dimensionFlag, formId); + }).catch((error: Error) => { Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'onAddForm rdb error ' + JSON.stringify(error)); }); // Refresh every five minutes. @@ -61,8 +64,8 @@ export default class EntryFormAbility extends FormExtensionAbility { return FormBindingData.createFormBindingData(formData); } - onUpdateForm(formId: string) { - updateSensorData(); + onUpdateForm(formId: string): void { + this.updateSensorData(); // Refresh every five minutes. FormProvider.setFormNextRefreshTime(formId, CommonConstants.FORM_NEXT_REFRESH_TIME, (error, data) => { if (error) { @@ -73,18 +76,45 @@ export default class EntryFormAbility extends FormExtensionAbility { }); } - onRemoveForm(formId: string) { + onRemoveForm(formId: string): void { // Deleting card information from the database. - DatabaseUtils.createRdbStore(this.context).then((rdbStore: DataRdb.RdbStore) => { + DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => { if (!rdbStore) { Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'update sensor data rdbStore is null'); return; } - DatabaseUtils.deleteFormData(formId, rdbStore); - }).catch((error) => { + DatabaseUtils.deleteFormData(formId, rdbStore as DataRdb.RdbStore); + }).catch((error: Error) => { Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'onRemoveForm rdb error ' + JSON.stringify(error)); }); } + + + /** + * Update Steps. + */ + updateSensorData() { + // Get today's steps. + DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => { + if (!rdbStore) { + Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'update sensor data rdbStore is null'); + return; + } + let getSensorData: Promise = + DatabaseUtils.getSensorData(rdbStore as DataRdb.RdbStore, DateUtils.getDate(0)); + getSensorData.then((sensorData: SensorData) => { + let stepValue: number = 0; + if (sensorData) { + stepValue = sensorData.stepsValue; + } + DatabaseUtils.updateForms(stepValue, rdbStore as DataRdb.RdbStore); + }).catch((error: Error) => { + Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'updateSensor getSensorData err ' + JSON.stringify(error)); + }); + }).catch((error: Error) => { + Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'updateSensor rdb err ' + JSON.stringify(error)); + }); + } }; /** @@ -102,35 +132,11 @@ function getToDaySteps(rdbStore: DataRdb.RdbStore, dimensionFlag: number, formId stepValue = sensorData.stepsValue; } getFormData(formId, stepValue, dimensionFlag, rdbStore); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'getToDaySteps error ' + JSON.stringify(error)); }); } -/** - * Update Steps. - */ -function updateSensorData() { - // Get today's steps. - DatabaseUtils.createRdbStore(this.context).then((rdbStore: DataRdb.RdbStore) => { - if (!rdbStore) { - Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'update sensor data rdbStore is null'); - return; - } - let getSensorData: Promise = DatabaseUtils.getSensorData(rdbStore, DateUtils.getDate(0)); - getSensorData.then((sensorData: SensorData) => { - let stepValue: number = 0; - if (sensorData) { - stepValue = sensorData.stepsValue; - } - DatabaseUtils.updateForms(stepValue, rdbStore); - }).catch((error) => { - Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'updateSensor getSensorData err ' + JSON.stringify(error)); - }); - }).catch((error) => { - Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'updateSensor rdb err ' + JSON.stringify(error)); - }); -} /** * Get form and update data. @@ -144,7 +150,7 @@ function getFormData(formId: string, stepValue: number, dimensionFlag: number, r ChartDataUtils.getFormData(formId, stepValue, dimensionFlag, rdbStore) .then((formData: FormData) => { FormProvider.updateForm(formData.formId, FormBindingData.createFormBindingData(formData)); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'getFormData formData error ' + JSON.stringify(error)); }); } diff --git a/Card/StepsCardJS/entry/src/main/ets/pages/MainPage.ets b/Card/StepsCardJS/entry/src/main/ets/pages/MainPage.ets index d8cf64d78fc18436203a3731b2cc9cbf37af7b80..d1e50f12422ef92d49d284a714775a1c31705df6 100644 --- a/Card/StepsCardJS/entry/src/main/ets/pages/MainPage.ets +++ b/Card/StepsCardJS/entry/src/main/ets/pages/MainPage.ets @@ -13,12 +13,14 @@ * limitations under the License. */ +import DataRdb from '@ohos.data.relationalStore'; import Notification from '@ohos.notificationManager'; import DatabaseUtils from '../common/utils/DatabaseUtils'; import DateUtils from '../common/utils/DateUtils'; import Logger from "../common/utils/Logger" import SensorData from '../common/database/SensorData'; import CommonConstants from '../common/constants/CommonConstants'; +import { GlobalContext } from '../common/utils/GlobalContext'; /** * The MainPage is the entry point of the application and shows how to develop the MainPage. @@ -31,25 +33,24 @@ import CommonConstants from '../common/constants/CommonConstants'; struct MainPage { @State stepsValue: number = 0; private intervalId: number = 0; - private notificationId: number = 0; private iconStepsBackground: Resource = $r('app.media.icon_steps_background'); aboutToAppear() { + let rdbStoreValue: DataRdb.RdbStore = GlobalContext.getContext().getObject('rdbStore') as DataRdb.RdbStore; this.requestNotification(); - DatabaseUtils.getSensorData(globalThis.rdbStore, DateUtils.getDate(0)) + DatabaseUtils.getSensorData(rdbStoreValue, DateUtils.getDate(0)) .then((sensorData: SensorData) => { if (sensorData) { this.stepsValue = sensorData.stepsValue; } // Start the timer. this.intervalId = setInterval(() => { - this.notificationId += CommonConstants.ID_VALUE; this.stepsValue += CommonConstants.INTERVAL_STEPS_VALUE; - DatabaseUtils.insertValues(this.stepsValue, globalThis.rdbStore); - DatabaseUtils.updateForms(this.stepsValue, globalThis.rdbStore); - DatabaseUtils.sendNotifications(this.stepsValue.toString(), this.notificationId); + DatabaseUtils.insertValues(this.stepsValue, rdbStoreValue); + DatabaseUtils.updateForms(this.stepsValue, rdbStoreValue); + DatabaseUtils.sendNotifications(this.stepsValue.toString()); }, CommonConstants.INTERVAL_DELAY_TIME); - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.MAIN_PAGE_TAG, 'getSensorData error ' + JSON.stringify(error)); }); } @@ -66,7 +67,7 @@ struct MainPage { requestNotification() { Notification.requestEnableNotification().then(() => { Logger.info(CommonConstants.MAIN_PAGE_TAG, 'requestEnableNotification success'); - }).catch((err) => { + }).catch((err: Error) => { Logger.error(CommonConstants.MAIN_PAGE_TAG, 'requestEnableNotification failed : ' + JSON.stringify(err)); }); } @@ -101,7 +102,8 @@ struct MainPage { } // Steps text common style. -@Extend(Text) function progressTextStyle(styleFontSize: number, styleFontWeight: number) { +@Extend(Text) +function progressTextStyle(styleFontSize: number, styleFontWeight: number) { .fontColor(Color.White) .fontSize(styleFontSize) .fontWeight(styleFontWeight) diff --git a/Card/StepsCardJS/entry/src/main/ets/common/bean/ChartPoint.ets b/Card/StepsCardJS/entry/src/main/ets/viewmodel/ChartPoint.ets similarity index 81% rename from Card/StepsCardJS/entry/src/main/ets/common/bean/ChartPoint.ets rename to Card/StepsCardJS/entry/src/main/ets/viewmodel/ChartPoint.ets index 326c543ffea8ebcd937a366a7532d85dc92e3b67..04e8b1ccedf85dc2dd5e74c6d11853cee0cc9409 100644 --- a/Card/StepsCardJS/entry/src/main/ets/common/bean/ChartPoint.ets +++ b/Card/StepsCardJS/entry/src/main/ets/viewmodel/ChartPoint.ets @@ -22,25 +22,26 @@ export default class ChartPoint { /** * Step value. */ - value: number; - + value: number = 0; /** * Style of chart points. */ - pointStyle: PointStyle; - + pointStyle: PointStyle = { + shape: '', + fillColor: '', + strokeColor: '', + size: 0 + }; /** * Description of icon points. */ - description: string; - + description: string = ''; /** * Chart text position. */ - textLocation: string; - + textLocation: string = ''; /** * Chart text color. */ - textColor: string; + textColor: string = ''; } \ No newline at end of file diff --git a/Card/StepsCardJS/entry/src/main/ets/common/bean/ChartValues.ets b/Card/StepsCardJS/entry/src/main/ets/viewmodel/ChartValues.ets similarity index 88% rename from Card/StepsCardJS/entry/src/main/ets/common/bean/ChartValues.ets rename to Card/StepsCardJS/entry/src/main/ets/viewmodel/ChartValues.ets index 7cd480b29eaabcbb8946fe642d8eeaccf696ac0c..e27fbfe21a8b2a7858d809a3bef660dab2ebe230 100644 --- a/Card/StepsCardJS/entry/src/main/ets/common/bean/ChartValues.ets +++ b/Card/StepsCardJS/entry/src/main/ets/viewmodel/ChartValues.ets @@ -22,20 +22,17 @@ export default class ChartValues { /** * Chart fill color. */ - fillColor: string; - + fillColor: string = ''; /** * Chart line color. */ - strokeColor: string; - + strokeColor: string = ''; /** * Sets whether to display the fill gradient color. */ - gradient: boolean; - + gradient: boolean = false; /** * Draw a set of points in a line type chart. */ - data: Array; + data: Array = []; } \ No newline at end of file diff --git a/Card/StepsCardJS/entry/src/main/ets/common/bean/FormData.ets b/Card/StepsCardJS/entry/src/main/ets/viewmodel/FormData.ets similarity index 83% rename from Card/StepsCardJS/entry/src/main/ets/common/bean/FormData.ets rename to Card/StepsCardJS/entry/src/main/ets/viewmodel/FormData.ets index 136c47c71be875f156e6d513412e7e9c1d2f4ad8..b6ee4fe1c4bdcc0ffce7ab89da4459582ce7880e 100644 --- a/Card/StepsCardJS/entry/src/main/ets/common/bean/FormData.ets +++ b/Card/StepsCardJS/entry/src/main/ets/viewmodel/FormData.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import ChartValues from '../bean/ChartValues'; +import ChartValues from './ChartValues'; /** * Form data entity class. @@ -22,25 +22,21 @@ export default class FormData { /** * Form ID */ - formId: string; - + formId: string = ''; /** * Step percentage. */ - percent: number; - + percent: number = 0; /** * Form steps. */ - steps: number; - + steps: number = 0; /** * Chart data point collection. */ - datasets: Array; - + datasets: Array = []; /** * Travel mileage. */ - mileage: number; + mileage: number = 0; } \ No newline at end of file diff --git a/Card/StepsCardJS/entry/src/main/ets/common/bean/PointStyle.ets b/Card/StepsCardJS/entry/src/main/ets/viewmodel/PointStyle.ets similarity index 89% rename from Card/StepsCardJS/entry/src/main/ets/common/bean/PointStyle.ets rename to Card/StepsCardJS/entry/src/main/ets/viewmodel/PointStyle.ets index 8f6c6b44e8645bd50a3b0c7549bc054e7d384346..2358b16dcd4ce7a9af3ce832ec2f016f588fd5c9 100644 --- a/Card/StepsCardJS/entry/src/main/ets/common/bean/PointStyle.ets +++ b/Card/StepsCardJS/entry/src/main/ets/viewmodel/PointStyle.ets @@ -20,20 +20,17 @@ export default class PointStyle { /** * The shape of the point. */ - shape: string; - + shape: string = ''; /** * Fill color. */ - fillColor: string; - + fillColor: string = ''; /** * Border color. */ - strokeColor: string; - + strokeColor: string = ''; /** * Size of high bright spots. */ - size: number; + size: number = 0; } \ No newline at end of file diff --git a/Card/StepsCardJS/hvigor/hvigor-config.json5 b/Card/StepsCardJS/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/Card/StepsCardJS/hvigor/hvigor-config.json5 +++ b/Card/StepsCardJS/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/CommonEventAndNotification/AlarmClock/README.md b/CommonEventAndNotification/AlarmClock/README.md index e68d75f5cf416aeb3b320eca032e85d0cbcfbd69..e4ca9ad7928f944644ccec6b205a674171ea19ed 100644 --- a/CommonEventAndNotification/AlarmClock/README.md +++ b/CommonEventAndNotification/AlarmClock/README.md @@ -22,20 +22,14 @@ ### 相关权限 -本篇Codelab使用了后台代理提醒,需要在配置文件module.json5文件里添加权限:ohos.permission.PUBLISH_AGENT_REMINDER。 +本篇Codelab需要在module.json5中配置如下权限: ``` -{ - "module": { - "name": "entry", - ... - "requestPermissions": [ - { - "name": "ohos.permission.PUBLISH_AGENT_REMINDER" - } - ] +"requestPermissions": [ + { + "name": "ohos.permission.PUBLISH_AGENT_REMINDER" } -} +] ``` ## 环境搭建 @@ -43,13 +37,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -77,10 +71,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──AlarmItemBean.ets // 闹钟属性类 -│ │ │ ├──AlarmSettingBean.ets // 闹钟设置属性类 -│ │ │ └──ReminderItemBean.ets // 后台提醒属性类 │ │ ├──constants │ │ │ ├──AlarmSettingType.ets // 闹钟设置类型枚举 │ │ │ ├──CommonConstants.ets // 公共常量类 @@ -88,7 +78,8 @@ │ │ │ └──MainConstant.ets // 首页常量类 │ │ └──utils │ │ ├──DataTypeUtils.ets // 数据类型工具类 -│ │ └──DimensionUtil.ets // 屏幕适配工具类 +│ │ ├──DimensionUtil.ets // 屏幕适配工具类 +│ │ └──GlobalContext.ets // 全局变量工具类 │ ├──entryability │ │ └──EntryAbility.ets // 程序入口类 │ ├──model @@ -115,8 +106,12 @@ │ │ │ └──ClockArea.ets // 主页时钟组件 │ │ └──BackContainer.ets // 自定义头部组件 │ └──viewmodel +│ ├──AlarmItemBean.ets // 闹钟属性类 +│ ├──AlarmSettingBean.ets // 闹钟设置属性类 +│ ├──DayDateBean.ets // 日期属性类 │ ├──DetailViewModel.ets // 详情模块逻辑功能类 -│ └──MainViewModel.ets // 主页逻辑功能类 +│ ├──MainViewModel.ets // 主页逻辑功能类 +│ └──ReminderItemBean.ets // 后台提醒属性类 └──entry/src/main/resources // 资源文件目录 ``` @@ -143,6 +138,7 @@ // ClockArea.ets @Component export default struct ClockArea { + ... build() { Canvas(this.renderContext) .width(this.canvasSize) @@ -156,7 +152,6 @@ export default struct ClockArea { this.showClock = !this.showClock; }) } - ... // 启动绘画任务 private startDrawTask() { let that = this; @@ -168,6 +163,7 @@ export default struct ClockArea { that.drawClockArea(); }, MainConstant.DEFAULT_ONE_SECOND_MS); } + ... } ``` @@ -180,8 +176,8 @@ export default struct ClockArea { private drawClockArea(): void{ this.renderContext.clearRect( -this.canvasSize, - -this.canvasSize / Constants.DEFAULT_DOUBLE, - this.canvasSize * Constants.DEFAULT_DOUBLE, + -this.canvasSize / CommonConstants.DEFAULT_DOUBLE, + this.canvasSize * CommonConstants.DEFAULT_DOUBLE, this.canvasSize); let date = new Date(); let hours = date.getHours(); @@ -203,11 +199,12 @@ private drawClockArea(): void{ public queryAlarmsTasker(callback: (alarms: Array) => void) { let that = this; that.queryDatabaseAlarms(callback); - globalThis.preference.addPreferencesListener({ + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + preference.addPreferencesListener({ onDataChanged() { that.queryDatabaseAlarms(callback); } - }) + } as PreferencesListener) } ``` @@ -227,8 +224,7 @@ export default struct AlarmList { }.onClick(() => { router.pushUrl({ url: "pages/DetailIndex", params: { alarmItem: item } }); }) - }, - item => item.id.toString()) + }, (item: AlarmItem) => JSON.stringify(item)) } .padding({ left: DimensionUtil.getVp($r('app.float.alarm_list_content_distance')), @@ -285,7 +281,8 @@ public openAlarm(id: number, isOpen: boolean) { } else { this.reminderService.deleteReminder(this.alarms[i].id); } - globalThis.preference.set(ALARM_KEY, JSON.stringify(this.alarms)); + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + preference.set(CommonConstants.ALARM_KEY, JSON.stringify(this.alarms)); break; } } @@ -311,18 +308,28 @@ public openAlarm(id: number, isOpen: boolean) { ```typescript // DetailIndex.ets -build() { - Row() { +build() +{ + Column() { + ... Button() { - Image(this.backImgRes == null ? $r('app.media.ic_public_back') : this.backImgRes).objectFit(ImageFit.Fill) + Image($r('app.media.ic_confirm')).objectFit(ImageFit.Fill) } .backgroundColor($r('app.color.trans_parent')) .width(DimensionUtil.getVp($r('app.float.title_button_size'))) .height(DimensionUtil.getVp($r('app.float.title_button_size'))) .onClick(() => { - this.backFunc ? this.backFunc() : router.back(); + this.viewModel.setAlarmRemind(this.alarmItem); + router.back(); }) + ... + } +} +// BackContainer.ets +build() { + Row() { + ... Text(this.header) .fontSize(DimensionUtil.getFp($r('app.float.detail_title_font_size'))) .lineHeight(DimensionUtil.getVp($r('app.float.title_line_height'))) @@ -353,14 +360,14 @@ export default struct DatePickArea { build() { Stack({ alignContent: Alignment.Center }) { Row() { - ForEach(DetailConstant.DAY_DATA, (item) => { + ForEach(DetailConstant.DAY_DATA, (item: DayDataBean) => { TextPicker({ range: item.data, selected: item.delSelect }) .layoutWeight(CommonConstants.DEFAULT_LAYOUT_WEIGHT) .backgroundColor($r('app.color.grey_light')) .onChange((value: string, index: number) => { item.delSelect = index; }) - }, item => item.timeType) + }, (item: DayDataBean) => JSON.stringify(item)) } } .height(DimensionUtil.getVp($r('app.float.date_picker_height'))) @@ -380,7 +387,7 @@ export default struct DatePickArea { // SettingItem.ets build() { Column() { - ForEach(this.settingInfo, (item: SettingInfo, index: number) => { + ForEach(this.settingInfo, (item: AlarmSettingBean, index: number | undefined) => { Divider() ... Row() { @@ -392,7 +399,7 @@ build() { .onClick(() => { this.showSettingDialog(item.sType); }) - }, (item, index) => JSON.stringify(item) + index) + }, (item: AlarmSettingBean, index: number | undefined) => JSON.stringify(item) + index) } ... } @@ -405,33 +412,33 @@ build() { ```typescript // DetailViewModel.ets public async setAlarmRemind(alarmItem: AlarmItem) { - alarmItem.hour = this.getAlarmTime(Constants.DEFAULT_SINGLE); - alarmItem.minute = this.getAlarmTime(Constants.DEFAULT_DATA_PICKER_HOUR_SELECTION); + alarmItem.hour = this.getAlarmTime(CommonConstants.DEFAULT_SINGLE); + alarmItem.minute = this.getAlarmTime(CommonConstants.DEFAULT_DATA_PICKER_HOUR_SELECTION); let index = await this.findAlarmWithId(alarmItem.id); - if (index !== Constants.DEFAULT_NUMBER_NEGATIVE) { - // 已存在,删除原有提醒 + if (index !== CommonConstants.DEFAULT_NUMBER_NEGATIVE) { // 已存在,删除原有提醒 this.reminderService.deleteReminder(alarmItem.id); - } else { - // 不存在,以数据长度为notificationId新增闹钟数据 + } else { // 不存在,以数据长度为notificationId新增闹钟数据 index = this.alarms.length; alarmItem.notificationId = index; this.alarms.push(alarmItem); } - this.reminderService.addReminder(alarmItem, (newId) => { + this.reminderService.addReminder(alarmItem, (newId: number) => { alarmItem.id = newId; alarmItem.isOpen = true; this.alarms[index] = alarmItem; - globalThis.preference.set(ALARM_KEY, JSON.stringify(this.alarms)); + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + preference.set(CommonConstants.ALARM_KEY, JSON.stringify(this.alarms)); }) } public async removeAlarmRemind(id: number) { this.reminderService.deleteReminder(id); let index = await this.findAlarmWithId(id); - if (index !== Constants.DEFAULT_NUMBER_NEGATIVE) { - this.alarms.splice(index, Constants.DEFAULT_SINGLE); + if (index !== CommonConstants.DEFAULT_NUMBER_NEGATIVE) { + this.alarms.splice(index, CommonConstants.DEFAULT_SINGLE); } - globalThis.preference.set(ALARM_KEY, JSON.stringify(this.alarms)); + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + preference.set(CommonConstants.ALARM_KEY, JSON.stringify(this.alarms)); } ``` diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/CommonConstants.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/CommonConstants.ets index 15ac20646a2f30252c41cff0a8da531b7c574795..602646ea5c2bd8423d5e303ad02b815379735a4a 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/CommonConstants.ets @@ -13,174 +13,130 @@ * limitations under the License. */ -/** - * database preference id. - */ -export const PREFERENCE_ID = 'storageId'; - -/** - * database alarm data key. - */ -export const ALARM_KEY = 'alarmData'; - -/** - * database alarm item key. - */ -export const PARAM_KEY = 'alarmItem'; - -export const CommonConstants = { +export class CommonConstants { + /** + * database preference id. + */ + static readonly PREFERENCE_ID = 'storageId'; + /** + * database alarm data key. + */ + static readonly ALARM_KEY = 'alarmData'; /** * common full length */ - FULL_LENGTH: '100%', - + static readonly FULL_LENGTH: string = '100%'; /** * default string space. */ - DEFAULT_STRING_SPACE: ' ', - + static readonly DEFAULT_STRING_SPACE: string = ' '; /** * default string comma. */ - DEFAULT_STRING_COMMA: ',', - + static readonly DEFAULT_STRING_COMMA: string = ','; /** * default string no repeat. */ - DEFAULT_STRING_NO_REPEAT: '不重复', - + static readonly DEFAULT_STRING_NO_REPEAT: string = '不重复'; /** * default number negative. */ - DEFAULT_NUMBER_NEGATIVE: -1, - + static readonly DEFAULT_NUMBER_NEGATIVE: number = -1; /** * default layout weight. */ - DEFAULT_LAYOUT_WEIGHT: 1, - - /** - * default number monday. - */ - DEFAULT_NUMBER_MONDAY: 1, - - /** - * default number tuesday. - */ - DEFAULT_NUMBER_TUESDAY: 2, - - /** - * default number wednesday. - */ - DEFAULT_NUMBER_WEDNESDAY: 3, - - /** - * default number thursday. - */ - DEFAULT_NUMBER_THURSDAY: 4, - - /** - * default number friday. - */ - DEFAULT_NUMBER_FRIDAY: 5, - - /** - * default number saturday. - */ - DEFAULT_NUMBER_SATURDAY: 6, - - /** - * default number sunday. - */ - DEFAULT_NUMBER_SUNDAY: 7, - + static readonly DEFAULT_LAYOUT_WEIGHT: number = 1; /** * default single. */ - DEFAULT_SINGLE: 1, - + static readonly DEFAULT_SINGLE: number = 1; /** - * default double. - */ - DEFAULT_DOUBLE: 2, - + * default double. + */ + static readonly DEFAULT_DOUBLE: number = 2; /** * default data picker hour selection. */ - DEFAULT_DATA_PICKER_HOUR_SELECTION: 2, - + static readonly DEFAULT_DATA_PICKER_HOUR_SELECTION: number = 2; /** * default total minute. */ - DEFAULT_TOTAL_MINUTE: 60, - + static readonly DEFAULT_TOTAL_MINUTE: number = 60; /** * default string monday. */ - DEFAULT_STRING_MONDAY: '周一', - + static readonly DEFAULT_STRING_MONDAY: string = '周一'; /** * default string tuesday. */ - DEFAULT_STRING_TUESDAY: '周二', - + static readonly DEFAULT_STRING_TUESDAY: string = '周二'; /** * default string wednesday. */ - DEFAULT_STRING_WEDNESDAY: '周三', - + static readonly DEFAULT_STRING_WEDNESDAY: string = '周三'; /** * default string thursday. */ - DEFAULT_STRING_THURSDAY: '周四', - + static readonly DEFAULT_STRING_THURSDAY: string = '周四'; /** * default string friday. */ - DEFAULT_STRING_FRIDAY: '周五', - + static readonly DEFAULT_STRING_FRIDAY: string = '周五'; /** * default string saturday. */ - DEFAULT_STRING_SATURDAY: '周六', - + static readonly DEFAULT_STRING_SATURDAY: string = '周六'; /** * default string sunday. */ - DEFAULT_STRING_SUNDAY: '周日', - + static readonly DEFAULT_STRING_SUNDAY: string = '周日'; /** * default number moment. */ - DEFAULT_NUMBER_MOMENT: 3, - + static readonly DEFAULT_NUMBER_MOMENT: number = 3; /** * default interval step. */ - DEFAULT_INTERVAL_STEP: 5, - + static readonly DEFAULT_INTERVAL_STEP: number = 5; /** * default common degree */ - DEFAULT_COMMON_DEGREE: 6, - + static readonly DEFAULT_COMMON_DEGREE: number = 6; /** * default pointer width. */ - DEFAULT_POINTER_WIDTH: 10, - + static readonly DEFAULT_POINTER_WIDTH: number = 10; /** * default total hour. */ - DEFAULT_TOTAL_HOUR: 12, - + static readonly DEFAULT_TOTAL_HOUR: number = 12; /** * default interval time max. */ - DEFAULT_INTERVAL_TIME_MAX: 10, - + static readonly DEFAULT_INTERVAL_TIME_MAX: number = 10; /** * default interval minute max. */ - DEFAULT_INTERVAL_MINUTE_MAX: 30, + static readonly DEFAULT_INTERVAL_MINUTE_MAX: number = 30; + /** + * bundle name. + */ + static readonly BUNDLE_NAME: string = 'com.huawei.alarmclock'; + /** + * ability name. + */ + static readonly ABILITY_NAME: string = 'EntryAbility'; +} + +/** + * Default number for a week. + */ +export enum WeekDays { + DEFAULT_NUMBER_MONDAY = 1, + DEFAULT_NUMBER_TUESDAY = 2, + DEFAULT_NUMBER_WEDNESDAY = 3, + DEFAULT_NUMBER_THURSDAY = 4, + DEFAULT_NUMBER_FRIDAY = 5, + DEFAULT_NUMBER_SATURDAY = 6, + DEFAULT_NUMBER_SUNDAY = 7 } \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/DetailConstant.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/DetailConstant.ets index 7d8e114439644e6b241258d56d0f140d7954e757..03130a08c2dc584abffb287fa4aea0d1acdca072 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/DetailConstant.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/DetailConstant.ets @@ -12,72 +12,70 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import DayDataBean from '../../viewmodel/DayDateBean' /** * Detail page constant description. */ -export const DetailConstant = { +export class DetailConstant { /** * detail page day data. */ - DAY_DATA: [ - { timeType: 0, delSelect: 0, data: ['上午', '下午'] }, - { timeType: 1, delSelect: 0, data: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'] }, - { timeType: 2, delSelect: 0, data: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', - '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', - '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', - '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', - '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '00', - ] } - ], - + static readonly DAY_DATA: DayDataBean[] = [ + { timeType: 0, delSelect: 0, data: ['上午', '下午'] } as DayDataBean, + { timeType: 1, delSelect: 0, data: + [ + '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12' + ] + } as DayDataBean, + { timeType: 2, delSelect: 0, data: + [ + '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', + '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', + '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', + '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '00', + ] + } as DayDataBean + ]; /** * week day data. */ - WEEKDAY_DATA: [1, 2, 3, 4, 5, 6, 7], - + static readonly WEEKDAY_DATA: number[] = [1, 2, 3, 4, 5, 6, 7]; /** * ring duration list data. */ - RING_DURATION: [1, 5, 10, 15, 20, 30], - + static readonly RING_DURATION: number[] = [1, 5, 10, 15, 20, 30]; /** * default string minute. */ - DEFAULT_STRING_MINUTE: '分钟', - + static readonly DEFAULT_STRING_MINUTE: string = '分钟'; /** * default string group name. */ - DEFAULT_STRING_GROUP_NAME: 'radioGroup', - + static readonly DEFAULT_STRING_GROUP_NAME: string = 'radioGroup'; /** * default string provider key. */ - DEFAULT_PROVIDER_KEY: 'alarmItemProvide', - + static readonly DEFAULT_PROVIDER_KEY: string = 'alarmItemProvide'; /** * default string repeat. */ - DEFAULT_STRING_REPEAT: '重复', - + static readonly DEFAULT_STRING_REPEAT: string = '重复'; /** * default string alarm name. */ - DEFAULT_STRING_ALARM_NAME: '闹钟名', - + static readonly DEFAULT_STRING_ALARM_NAME: string = '闹钟名'; /** * default string interval. */ - DEFAULT_STRING_INTERVAL: '再响间隔', - + static readonly DEFAULT_STRING_INTERVAL: string = '再响间隔'; /** * default string duration. */ - DEFAULT_STRING_DURATION: '闹铃时长', - + static readonly DEFAULT_STRING_DURATION: string = '闹铃时长'; /** * default string times. */ - DEFAULT_STRING_TIMES: '次', + static readonly DEFAULT_STRING_TIMES: string = '次'; } \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/MainConstant.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/MainConstant.ets index 20aaeaa749bf916d71d081f226c4358d5052e476..3739e45f4a2cfbabc1eacb3ad408ab07acc2becd 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/MainConstant.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/constants/MainConstant.ets @@ -16,79 +16,65 @@ /** * Main page constant description. */ -export const MainConstant = { +export class MainConstant { /** * Main page times list. */ - TIMES: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2], - + static readonly TIMES: number[] = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2]; /** * Default single digit max. */ - DEFAULT_SINGLE_DIGIT_MAX: 9, - + static readonly DEFAULT_SINGLE_DIGIT_MAX: number = 9; /** * Default horizontal angle. */ - DEFAULT_HORIZONTAL_ANGLE: 180, - + static readonly DEFAULT_HORIZONTAL_ANGLE: number = 180; /** * Default one second ms. */ - DEFAULT_ONE_SECOND_MS: 1000, - + static readonly DEFAULT_ONE_SECOND_MS: number = 1000; /** * Default zeroing. */ - DEFAULT_ZEROING: "0", - + static readonly DEFAULT_ZEROING: string = '0'; /** * Default string morning. */ - DEFAULT_STRING_MORNING: '上午', - + static readonly DEFAULT_STRING_MORNING: string = '上午'; /** * Default string afternoon. */ - DEFAULT_STRING_AFTERNOON: '下午', - + static readonly DEFAULT_STRING_AFTERNOON: string = '下午'; /** * Default string alarm name. */ - DEFAULT_STRING_ALARM: '闹钟', - + static readonly DEFAULT_STRING_ALARM: string = '闹钟'; /** * Default string quotation. */ - DEFAULT_STRING_NULL: "", - + static readonly DEFAULT_STRING_NULL: string = ''; /** * Default string colon. */ - DEFAULT_STRING_COLON: ':', - + static readonly DEFAULT_STRING_COLON: string = ':'; /** * Default clock time font size unit. */ - CLOCK_TIME_FONT_SIZE_UNIT: 'px', - + static readonly CLOCK_TIME_FONT_SIZE_UNIT: string = 'px'; /** * Hour pointer image url. */ - HOUR_POINTER_IMAGE_URL: "../../../resources/base/media/ic_hour_pointer.png", - + static readonly HOUR_POINTER_IMAGE_URL: string = '../../../resources/base/media/ic_hour_pointer.png'; /** * Minute pointer image url. */ - MINUTE_POINTER_IMAGE_URL: "../../../resources/base/media/ic_minute_pointer.png", - + static readonly MINUTE_POINTER_IMAGE_URL: string = '../../../resources/base/media/ic_minute_pointer.png'; /** * Second pointer image url. */ - SECOND_POINTER_IMAGE_URL: "../../../resources/base/media/ic_second_pointer.png", - + static readonly SECOND_POINTER_IMAGE_URL: string = '../../../resources/base/media/ic_second_pointer.png'; /** * Clock pan image url. */ - CLOCK_PAN_IMAGE_URL: '../../../resources/base/media/ic_clock_pan.png', + static readonly CLOCK_PAN_IMAGE_URL: string = '../../../resources/base/media/ic_clock_pan.png'; } \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/DataTypeUtils.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/DataTypeUtils.ets index 90f063727525fcea471edce6da9e751db4ef3a56..79dd6e704ad530f6564aa5abd83fd24d75e87266 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/DataTypeUtils.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/DataTypeUtils.ets @@ -17,21 +17,12 @@ * Data type utils. */ export default class DataTypeUtils { - /** - * return value is number. - * - * @return boolean. - */ - static isNumber(value): boolean{ - return typeof value === 'number' && isFinite(value); - } - /** * return obj is null. * * @return boolean. */ - static isNull(obj): boolean { + static isNull(obj: Object): boolean { return (typeof obj === 'undefined' || obj == null || obj === ''); } @@ -40,18 +31,10 @@ export default class DataTypeUtils { * * @return type in obj. */ - static deepCopy(obj) { - var newObj = obj.constructor === Array ? [] : {}; - if (typeof obj !== 'object') { - return obj; - } else { - for (var i in obj) { - if (typeof obj[i] === 'object') { - newObj[i] = this.deepCopy(obj[i]); - } else { - newObj[i] = obj[i]; - } - } + static deepCopy(obj: number[]) { + let newObj: number[] = []; + for (let i = 0; i < obj.length; i++) { + newObj[i] = JSON.parse(JSON.stringify(obj[i])); } return newObj; } diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/DimensionUtil.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/DimensionUtil.ets index 82edab1d0d73cdb8c22a13ee331481510f0972fe..8f2b4b140184b12090b681e88476c5ed4218d88f 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/DimensionUtil.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/DimensionUtil.ets @@ -12,8 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import display from '@ohos.display'; +import { GlobalContext } from './GlobalContext'; -var context = getContext(this); +let context = getContext(this); /** * Design drawing width. @@ -35,7 +37,7 @@ export default class DimensionUtil { * @return number */ static adaptDimension(value: number): number { - let deviceDisplay = globalThis.display; + let deviceDisplay = GlobalContext.getContext().getObject('globalDisplay') as display.Display; let widthScale = deviceDisplay.width / DESIGN_WIDTH; let virtualHeight = widthScale * DESIGN_HEIGHT; let designDim = Math.sqrt(DESIGN_WIDTH * DESIGN_WIDTH + DESIGN_HEIGHT * DESIGN_HEIGHT); @@ -50,7 +52,7 @@ export default class DimensionUtil { */ static getPx(value: Resource): number { let beforeVp = context.resourceManager.getNumber(value.id); - return this.adaptDimension(beforeVp); + return DimensionUtil.adaptDimension(beforeVp); } /** @@ -60,7 +62,7 @@ export default class DimensionUtil { */ static getVp(value: Resource): number { let beforeVp = context.resourceManager.getNumber(value.id); - return px2vp(this.adaptDimension(beforeVp)); + return px2vp(DimensionUtil.adaptDimension(beforeVp)); } /** @@ -70,6 +72,6 @@ export default class DimensionUtil { */ static getFp(value: Resource): number { let beforeFp = context.resourceManager.getNumber(value.id); - return px2fp(this.adaptDimension(beforeFp)); + return px2fp(DimensionUtil.adaptDimension(beforeFp)); } } \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/GlobalContext.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..23f5130a61c9e0ac09c5d885cdcaa2c878e0d522 --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/utils/GlobalContext.ets @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { + } + + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/entryability/EntryAbility.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/entryability/EntryAbility.ets index 238b0819020eab0db5db6a70eebc10f5b76a2010..031bf20f5c2706c2b3ae4b0040be1a88e59703f3 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/entryability/EntryAbility.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/entryability/EntryAbility.ets @@ -16,19 +16,40 @@ import display from '@ohos.display'; import UIAbility from '@ohos.app.ability.UIAbility'; import PreferencesHandler from '../model/database/PreferencesHandler'; +import window from '@ohos.window'; +import { GlobalContext } from '../common/utils/GlobalContext'; +import hilog from '@ohos.hilog'; export default class EntryAbility extends UIAbility { - onCreate(want) { - let abilityInfo = this.context.abilityInfo; - globalThis.bundleName = abilityInfo.bundleName; - globalThis.abilityName = abilityInfo.name; - globalThis.abilityWant = want; - globalThis.preference = PreferencesHandler.getInstance(); + onCreate() { + GlobalContext.getContext().setObject('preference', PreferencesHandler.instance); } - async onWindowStageCreate(windowStage) { - globalThis.display = await display.getDefaultDisplay(); - await globalThis.preference.configure(this.context.getApplicationContext()); - windowStage.setUIContent(this.context, "pages/MainIndex", null); + async onWindowStageCreate(windowStage: window.WindowStage) { + // Main window is created, set main page for this ability + let globalDisplay: display.Display = display.getDefaultDisplaySync(); + GlobalContext.getContext().setObject('globalDisplay', globalDisplay); + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + await preference.configure(this.context.getApplicationContext()); + // windowStage.setUIContent(this.context, "pages/MainIndex", null); + + let windowClass: window.Window | null = null; + windowStage.getMainWindow((_err, data) => { + let isLayoutFullScreen = false; + windowClass = data; + windowClass.setWindowLayoutFullScreen(isLayoutFullScreen, (err) => { + if (err.code) { + return; + } + }); + }) + + windowStage.loadContent('pages/MainIndex', (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. Data: %{public}s', JSON.stringify(data) ?? ''); + }); } } \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/ReminderService.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/ReminderService.ets index e4c1078d2f416184e04364f0bae051931b08f5b1..addf437578c280674f0c3b0b64a3c028b0445032 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/ReminderService.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/ReminderService.ets @@ -16,7 +16,7 @@ import reminderAgent from '@ohos.reminderAgentManager'; import notification from '@ohos.notificationManager'; import { CommonConstants } from '../common/constants/CommonConstants'; -import ReminderItem from '../common/bean/ReminderItemBean'; +import ReminderItem from '../viewmodel/ReminderItemBean'; /** * Base on ohos reminder agent service @@ -28,7 +28,7 @@ export default class ReminderService { public openNotificationPermission() { notification.requestEnableNotification().then(() => { console.info('Enable notification success'); - }).catch((err) => { + }).catch((err: Error) => { console.error('Enable notification failed because ' + JSON.stringify(err)); }); } @@ -39,7 +39,7 @@ export default class ReminderService { * @param alarmItem ReminderItem * @param callback callback */ - public addReminder(alarmItem: ReminderItem, callback?) { + public addReminder(alarmItem: ReminderItem, callback?: (reminderId: number) => void) { let reminder = this.initReminder(alarmItem); reminderAgent.publishReminder(reminder, (err, reminderId) => { if (callback != null) { @@ -78,8 +78,8 @@ export default class ReminderService { }, ], wantAgent: { - pkgName: globalThis.bundleName, - abilityName: globalThis.abilityName + pkgName: CommonConstants.BUNDLE_NAME, + abilityName: CommonConstants.ABILITY_NAME }, notificationId: item.notificationId, expiredContent: 'this reminder has expired', diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/database/PreferencesHandler.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/database/PreferencesHandler.ets index 7c84d33a7d29a43e46aad1d9f62d11d59a9eaa95..2a9ddf4208e190e7ee106485b7afc67e4d2919c5 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/database/PreferencesHandler.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/database/PreferencesHandler.ets @@ -14,15 +14,15 @@ */ import data_preferences from '@ohos.data.preferences'; -import { PREFERENCE_ID } from '../../common/constants/CommonConstants'; +import { CommonConstants } from '../../common/constants/CommonConstants'; import PreferencesListener from './PreferencesListener'; /** * Based on lightweight databases preferences handler. */ export default class PreferencesHandler { - private static instance: PreferencesHandler; - private preferences; + static instance: PreferencesHandler = new PreferencesHandler(); + private preferences: data_preferences.Preferences | null = null; private defaultValue = ''; private listeners: PreferencesListener[]; @@ -35,23 +35,23 @@ export default class PreferencesHandler { * * @return instance */ - public static getInstance() { - if (this.instance == null) { - this.instance = new PreferencesHandler(); - } - return this.instance; - } + // public static getInstance() { + // if (this.instance == null) { + // this.instance = new PreferencesHandler(); + // } + // return this.instance; + // } /** * Configure PreferencesHandler. * * @param context Context */ - public async configure(context) { - this.preferences = await data_preferences.getPreferences(context, PREFERENCE_ID); - this.preferences.on('change', (key) => { + public async configure(context: Context) { + this.preferences = await data_preferences.getPreferences(context, CommonConstants.PREFERENCE_ID); + this.preferences.on('change', (data: Record) => { for (let preferencesListener of this.listeners) { - preferencesListener.onDataChanged(key); + preferencesListener.onDataChanged(data.key as string); } }); } @@ -62,7 +62,7 @@ export default class PreferencesHandler { * @param key string * @param value any */ - public async set(key: string, value) { + public async set(key: string, value: string) { if (this.preferences != null) { await this.preferences.put(key, value); await this.preferences.flush(); @@ -76,10 +76,10 @@ export default class PreferencesHandler { * @param defValue any * @return data about key */ - public async get(key: string, defValue?) { - let data; + public async get(key: string) { + let data: string = ''; if (this.preferences != null) { - data = await this.preferences.get(key, defValue == null ? this.defaultValue : defValue); + data = await this.preferences.get(key, this.defaultValue) as string; } return data; } @@ -98,13 +98,13 @@ export default class PreferencesHandler { * * @return data */ - public async getAll() { - let data; - if (this.preferences != null) { - data = await this.preferences.getAll(); - } - return data; - } + // public async getAll() { + // let data; + // if (this.preferences != null) { + // data = await this.preferences.getAll(); + // } + // return data; + // } /** * Add preferences listener in PreferencesHandler. diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/database/PreferencesListener.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/database/PreferencesListener.ets index d863486554de7fd15ef6c95f7f4248f7444dae77..ced9dd8cd3e470be1f67b9607120e03cda37a87d 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/database/PreferencesListener.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/model/database/PreferencesListener.ets @@ -22,5 +22,5 @@ export default interface PreferencesListener { * * @param key string */ - onDataChanged(key: string): void + onDataChanged: (key: string) => void } diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/DetailIndex.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/DetailIndex.ets index a7c2b8aa556b7caf785dfb3bac969e05acc2fa5c..bd207fc61624f2d66b92a610c66cb5170f3950d6 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/DetailIndex.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/DetailIndex.ets @@ -14,9 +14,9 @@ */ import router from '@ohos.router'; -import { PARAM_KEY, CommonConstants } from '../common/constants/CommonConstants'; -import AlarmItem from '../common/bean/AlarmItemBean'; -import AlarmSettingBean from '../common/bean/AlarmSettingBean'; +import { CommonConstants } from '../common/constants/CommonConstants'; +import AlarmItem from '../viewmodel/AlarmItemBean'; +import AlarmSettingBean from '../viewmodel/AlarmSettingBean'; import { AlarmSettingType } from '../common/constants/AlarmSettingType'; import { DetailConstant } from '../common/constants/DetailConstant'; import BackContainer from '../view/BackContainer'; @@ -32,13 +32,19 @@ struct DetailIndex { @State repeatSettingArr: Array = []; @State alarmSettingInfoArr: Array = []; private isNow: boolean = true; - private viewModel: DetailModel = DetailModel.getInstant(); + private viewModel: DetailModel = DetailModel.instant; aboutToAppear() { - if (router.getParams() != null && router.getParams().hasOwnProperty(PARAM_KEY)) { - this.isNow = false; - this.alarmItem = router.getParams()[PARAM_KEY]; - this.viewModel.setAlarmDefaultTime(this.alarmItem); + let params = router.getParams() as Record; + if (params !== undefined) { + let alarmItem: AlarmItem = params.alarmItem as AlarmItem; + if (alarmItem !== undefined) { + this.isNow = false; + this.alarmItem = alarmItem; + this.viewModel.setAlarmDefaultTime(this.alarmItem); + }else { + this.viewModel.setAlarmDefaultTime(); + } } else { this.viewModel.setAlarmDefaultTime(); } diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/MainIndex.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/MainIndex.ets index 005c59ed6923b91ff20f3c3171b3e74547707115..3670d04093f99943750c5b4dcd30bd6800b8ce3e 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/MainIndex.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/MainIndex.ets @@ -15,7 +15,7 @@ import router from '@ohos.router'; import { CommonConstants } from '../common/constants/CommonConstants'; -import AlarmItem from '../common/bean/AlarmItemBean'; +import AlarmItem from '../viewmodel/AlarmItemBean'; import { MainConstant } from '../common/constants/MainConstant'; import MainModel from '../viewmodel/MainViewModel'; import ClockArea from './../view/Main/ClockArea'; @@ -25,7 +25,7 @@ import DimensionUtil from '../common/utils/DimensionUtil'; @Entry @Component struct MainIndex { - private mainModel: MainModel = MainModel.getInstant(); + private mainModel: MainModel = MainModel.instant; @State alarmItems: Array = new Array(); @State isAuth: boolean = false; diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/BackContainer.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/BackContainer.ets index 9f5c92ae857fafa67efa3def2c4050d0949488d2..b7c16c495a9c07a8275463daa8f7c581f0046656 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/BackContainer.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/BackContainer.ets @@ -19,10 +19,10 @@ import DimensionUtil from '../common/utils/DimensionUtil'; @Component export default struct BackContainer { - private header: string | Resource; - private backImgRes: string | Resource; - private backFunc: () => void; - @BuilderParam closer: () => void; + private header: string | Resource = $r('app.string.new_alarm'); + private backImgRes: string | Resource = $r('app.media.ic_cancel'); + private backFunc?: () => void; + @BuilderParam closer?: () => void; build() { Row() { diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/DatePickArea.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/DatePickArea.ets index 27e08ffb1f0b5be46ceb2195026acd5f4016a8af..c16a99a8e5aaa771eb7f31fe8fe7c506a5e51643 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/DatePickArea.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/DatePickArea.ets @@ -16,20 +16,21 @@ import { DetailConstant } from '../../common/constants/DetailConstant'; import { CommonConstants } from '../../common/constants/CommonConstants'; import DimensionUtil from '../../common/utils/DimensionUtil'; +import DayDataBean from '../../viewmodel/DayDateBean'; @Component export default struct DatePickArea { build() { Stack({ alignContent: Alignment.Center }) { Row() { - ForEach(DetailConstant.DAY_DATA, (item) => { + ForEach(DetailConstant.DAY_DATA, (item: DayDataBean) => { TextPicker({ range: item.data, selected: item.delSelect }) .layoutWeight(CommonConstants.DEFAULT_LAYOUT_WEIGHT) .backgroundColor($r('app.color.grey_light')) .onChange((value: string, index: number) => { item.delSelect = index; }) - }, item => JSON.stringify(item)) + }, (item: DayDataBean) => JSON.stringify(item)) } } .height(DimensionUtil.getVp($r('app.float.date_picker_height'))) diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/SettingItem.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/SettingItem.ets index 31e639ee040d6856c4451cb5dd4e6da7e3bff023..c09afd70b76b210ff7d8690e36d8180755189dd8 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/SettingItem.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/SettingItem.ets @@ -15,7 +15,7 @@ import { CommonConstants } from '../../common/constants/CommonConstants'; import { AlarmSettingType } from '../../common/constants/AlarmSettingType'; -import AlarmSettingBean from '../../common/bean/AlarmSettingBean'; +import AlarmSettingBean from '../../viewmodel/AlarmSettingBean'; import DimensionUtil from '../../common/utils/DimensionUtil'; import IntervalDialog from './dialog/IntervalDialog'; import DurationDialog from './dialog/DurationDialog'; @@ -63,7 +63,7 @@ export default struct SettingItem { build() { Column() { - ForEach(this.settingInfo, (item: AlarmSettingBean, index: number) => { + ForEach(this.settingInfo, (item: AlarmSettingBean, index: number | undefined) => { Divider() .visibility(index === 0 ? Visibility.Hidden : Visibility.Visible) .opacity($r('app.float.divider_opacity')) @@ -101,7 +101,7 @@ export default struct SettingItem { .onClick(() => { this.showSettingDialog(item.sType); }) - }, (item, index) => JSON.stringify(item) + index) + }, (item: AlarmSettingBean, index: number | undefined) => JSON.stringify(item) + index) } .margin({ bottom: DimensionUtil.getVp($r('app.float.setting_item_interval')), diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/CommonDialog.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/CommonDialog.ets index 6061004fc5a338740f33ca8c274f6d418036b19f..f6524e154d6aefdc404063d4cba9f2a04ee9aac6 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/CommonDialog.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/CommonDialog.ets @@ -18,10 +18,12 @@ import DimensionUtil from '../../../common/utils/DimensionUtil'; @Component export default struct CommonDialog { - private title: string | Resource; - private controller: CustomDialogController; - private onConfirm: () => void; - @BuilderParam closer: () => void; + private title?: string | Resource; + private controller?: CustomDialogController; + private onConfirm: () => void = () => { + }; + @BuilderParam closer: () => void = () => { + }; build() { Column() { @@ -35,11 +37,17 @@ export default struct CommonDialog { this.closer() Row() { Button($r('app.string.cancel')).actionBtnStyle().onClick(() => { + if (!this.controller) { + return; + } this.controller.close(); }) if (this.onConfirm) { Button($r('app.string.confirm')).actionBtnStyle().onClick(() => { this.onConfirm(); + if (!this.controller) { + return; + } this.controller.close(); }) } diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/DurationDialog.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/DurationDialog.ets index e9c1d7c3ab763fbb599f3db4ae3058030aa9b901..975080505346225446f305d36d757b14e8d41d3c 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/DurationDialog.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/DurationDialog.ets @@ -15,7 +15,7 @@ import { CommonConstants } from '../../../common/constants/CommonConstants'; import { DetailConstant } from '../../../common/constants/DetailConstant'; -import AlarmItem from '../../../common/bean/AlarmItemBean'; +import AlarmItem from '../../../viewmodel/AlarmItemBean'; import CommonDialog from './CommonDialog'; import DimensionUtil from '../../../common/utils/DimensionUtil'; @@ -23,7 +23,7 @@ import DimensionUtil from '../../../common/utils/DimensionUtil'; export default struct DurationDialog { @Consume(DetailConstant.DEFAULT_PROVIDER_KEY) alarmItem: AlarmItem; private durations: Array = DetailConstant.RING_DURATION; //响铃时长,分钟 - controller: CustomDialogController; + controller?: CustomDialogController; build() { Flex() { @@ -31,17 +31,20 @@ export default struct DurationDialog { title: $r('app.string.ring_duration'), controller: this.controller }) { - ForEach(this.durations, item => { + ForEach(this.durations, (item: number) => { Row() { Text(item + CommonConstants.DEFAULT_STRING_SPACE + DetailConstant.DEFAULT_STRING_MINUTE) .layoutWeight(CommonConstants.DEFAULT_LAYOUT_WEIGHT) .fontColor($r('app.color.grey_divider')) .fontSize(DimensionUtil.getFp($r('app.float.duration_dialog_content_font_size'))) - Radio({ value: item, group: DetailConstant.DEFAULT_STRING_GROUP_NAME }) + Radio({ value: item.toString(), group: DetailConstant.DEFAULT_STRING_GROUP_NAME }) .checked(item === this.alarmItem.duration ? true : false) .height(DimensionUtil.getVp($r('app.float.duration_dialog_radio_size'))) .width(DimensionUtil.getVp($r('app.float.duration_dialog_radio_size'))) .onChange(() => { + if (!this.controller) { + return; + } this.controller.close(); this.alarmItem.duration = item }) diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/IntervalDialog.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/IntervalDialog.ets index bad0e73e4d975bc965478ec98eb982b0bd6aca4a..1f98f3cc324da961002e198e5afaa97489694410 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/IntervalDialog.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/IntervalDialog.ets @@ -15,7 +15,7 @@ import { CommonConstants } from '../../../common/constants/CommonConstants'; import { DetailConstant } from '../../../common/constants/DetailConstant'; -import AlarmItem from '../../../common/bean/AlarmItemBean'; +import AlarmItem from '../../../viewmodel/AlarmItemBean'; import CommonDialog from './CommonDialog'; import DimensionUtil from '../../../common/utils/DimensionUtil'; @@ -24,7 +24,7 @@ export default struct IntervalDialog { @Consume(DetailConstant.DEFAULT_PROVIDER_KEY) alarmItem: AlarmItem; @State intervalMinuteSelect: number = 0; @State intervalTimesSelect: number = 0; - controller: CustomDialogController; + controller?: CustomDialogController; aboutToAppear(): void{ this.intervalMinuteSelect = this.alarmItem.intervalMinute; diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/RenameDialog.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/RenameDialog.ets index 732e28790ddadc268b0a6e873efdbffa6d626fb7..fe22cbc43e30898421bb6f9045fb55392c628bad 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/RenameDialog.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/RenameDialog.ets @@ -15,15 +15,18 @@ import { CommonConstants } from '../../../common/constants/CommonConstants'; import { DetailConstant } from '../../../common/constants/DetailConstant'; -import AlarmItem from '../../../common/bean/AlarmItemBean'; +import AlarmItem from '../../../viewmodel/AlarmItemBean'; import CommonDialog from './CommonDialog'; import DimensionUtil from '../../../common/utils/DimensionUtil'; @CustomDialog export default struct RenameDialog { @Consume(DetailConstant.DEFAULT_PROVIDER_KEY) alarmItem: AlarmItem; - private name: string; - controller: CustomDialogController; + private name: string = ''; + controller: CustomDialogController = new CustomDialogController({ + builder: RenameDialog(), + autoCancel: true + }); build() { Flex() { diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/RepeatDialog.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/RepeatDialog.ets index 9879d3cbc1e2fa1c32ed4ccaaf76603727b2a7ac..5bc50acaae46cc185909a069a03957dd93a48acd 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/RepeatDialog.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Detail/dialog/RepeatDialog.ets @@ -15,7 +15,7 @@ import { CommonConstants } from '../../../common/constants/CommonConstants'; import { DetailConstant } from '../../../common/constants/DetailConstant'; -import AlarmItem from '../../../common/bean/AlarmItemBean'; +import AlarmItem from '../../../viewmodel/AlarmItemBean'; import DetailModel from '../../../viewmodel/DetailViewModel'; import CommonDialog from './CommonDialog'; import DataTypeUtils from '../../../common/utils/DataTypeUtils'; @@ -24,9 +24,12 @@ import DimensionUtil from '../../../common/utils/DimensionUtil'; @CustomDialog export default struct RepeatDialog { @Consume(DetailConstant.DEFAULT_PROVIDER_KEY) alarmItem: AlarmItem; - private viewModel: DetailModel = DetailModel.getInstant(); + private viewModel: DetailModel = DetailModel.instant; private selects: number[] = []; - controller: CustomDialogController; + controller: CustomDialogController = new CustomDialogController({ + builder: RepeatDialog(), + autoCancel: true + }); aboutToAppear() { this.selects = DataTypeUtils.deepCopy(this.alarmItem.repeatDays); @@ -43,14 +46,14 @@ export default struct RepeatDialog { this.alarmItem.isRepeat = this.selects.length > 0; } }) { - ForEach(DetailConstant.WEEKDAY_DATA, (item) => { + ForEach(DetailConstant.WEEKDAY_DATA, (item: number) => { Row() { Text(this.viewModel.transAlarmRepeatDayContent(item)) .layoutWeight(CommonConstants.DEFAULT_LAYOUT_WEIGHT) .fontColor($r('app.color.grey_divider')) .fontSize(DimensionUtil.getFp($r('app.float.repeat_dialog_check_font_size'))) - Checkbox({ name: item }) + Checkbox({ name: item.toString() }) .select(this.alarmItem.repeatDays.indexOf(item) !== CommonConstants.DEFAULT_NUMBER_NEGATIVE) .width(DimensionUtil.getVp($r('app.float.repeat_dialog_check_box_size'))) .height(DimensionUtil.getVp($r('app.float.repeat_dialog_check_box_size'))) diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/AlarmList.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/AlarmList.ets index 416d8ff19a2b8ddd75d52f45c066cf543df71a54..4bfef98abf7eb7a12279ec70f70759a5608748aa 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/AlarmList.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/AlarmList.ets @@ -15,7 +15,7 @@ import router from '@ohos.router'; import { CommonConstants } from '../../common/constants/CommonConstants'; -import AlarmItem from '../../common/bean/AlarmItemBean'; +import AlarmItem from '../../viewmodel/AlarmItemBean'; import AlarmListItem from '../Main/AlarmListItem'; import DimensionUtil from '../../common/utils/DimensionUtil'; @@ -31,7 +31,7 @@ export default struct AlarmList { }.onClick(() => { router.pushUrl({ url: "pages/DetailIndex", params: { alarmItem: item } }); }) - }, item => JSON.stringify(item)) + }, (item: AlarmItem) => JSON.stringify(item)) } .padding({ left: DimensionUtil.getVp($r('app.float.alarm_list_content_distance')), diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/AlarmListItem.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/AlarmListItem.ets index 460ed043c95ea816373f9f4acf9529435b78d9a7..cc603f3ed46a681d801e6703b2f1c518397ce002 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/AlarmListItem.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/AlarmListItem.ets @@ -15,13 +15,13 @@ import MainModel from './../../viewmodel/MainViewModel'; import { CommonConstants } from '../../common/constants/CommonConstants'; -import AlarmItem from '../../common/bean/AlarmItemBean'; +import AlarmItem from '../../viewmodel/AlarmItemBean'; import DimensionUtil from '../../common/utils/DimensionUtil'; @Component export default struct AlarmListItem { - private mainModel: MainModel = MainModel.getInstant(); - private alarmItem: AlarmItem; + private mainModel: MainModel = MainModel.instant; + private alarmItem: AlarmItem = new AlarmItem(); build() { Row() { @@ -40,7 +40,7 @@ export default struct AlarmListItem { .CommonTextAttr(DimensionUtil.getFp($r('app.float.alarms_item_dec_font_size')), FontWeight.Normal, { top: DimensionUtil.getVp($r('app.float.alarms_item_dec_margin_top')) }, - $r('app.float.alarms_item_desc_text_opacity')) + $r('app.float.alarms_item_desc_text_opacity')) } .width(CommonConstants.FULL_LENGTH) .alignItems(HorizontalAlign.Start) @@ -64,10 +64,10 @@ export default struct AlarmListItem { } } -@Extend(Text) function CommonTextAttr (fontSize: number, fontWeight: number, margin?, opacity?) { +@Extend(Text) function CommonTextAttr (fontSize: number, fontWeight: number, margin?: Margin, opacity?: Resource) { .fontColor($r('app.color.grey_divider')) .fontSize(fontSize) .fontWeight(fontWeight) - .margin(margin) - .opacity(opacity) + .margin(margin ? margin : '') + .opacity(opacity ? opacity : 1.0) } \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/ClockArea.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/ClockArea.ets index b3b0a7a1a8d3a114dd6f94ca0b5cd36c169b1d08..1411e61de8cc4af0f98039f458d559814b2d20bb 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/ClockArea.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/view/Main/ClockArea.ets @@ -20,16 +20,16 @@ import DimensionUtil from '../../common/utils/DimensionUtil'; @Component export default struct ClockArea { - private mainModel: MainModel; - private drawInterval: any = CommonConstants.DEFAULT_NUMBER_NEGATIVE; + private mainModel: MainModel = MainModel.instant; + private drawInterval: number = CommonConstants.DEFAULT_NUMBER_NEGATIVE; @State showClock: boolean = true; - private canvasSize: number; - private clockRadius: number; + private canvasSize: number = DimensionUtil.getVp($r('app.float.clock_size')); + private clockRadius: number = this.canvasSize / CommonConstants.DEFAULT_DOUBLE - CommonConstants.DEFAULT_DOUBLE; private settings: RenderingContextSettings = new RenderingContextSettings(true); private renderContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); aboutToAppear() { - this.mainModel = MainModel.getInstant(); + this.mainModel = MainModel.instant; this.canvasSize = DimensionUtil.getVp($r('app.float.clock_size')); this.clockRadius = this.canvasSize / CommonConstants.DEFAULT_DOUBLE - CommonConstants.DEFAULT_DOUBLE; } @@ -100,9 +100,9 @@ export default struct ClockArea { } // 绘制时针、分针、秒针 - private drawPointer(degree, pointerImgRes) { + private drawPointer(degree: number, pointerImgRes: string) { this.renderContext.save(); - var theta = (degree + MainConstant.DEFAULT_HORIZONTAL_ANGLE) * Math.PI / MainConstant.DEFAULT_HORIZONTAL_ANGLE; + let theta = (degree + MainConstant.DEFAULT_HORIZONTAL_ANGLE) * Math.PI / MainConstant.DEFAULT_HORIZONTAL_ANGLE; this.renderContext.rotate(theta); this.renderContext.beginPath(); let secondImg = new ImageBitmap(pointerImgRes); diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/bean/AlarmItemBean.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/AlarmItemBean.ets similarity index 97% rename from CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/bean/AlarmItemBean.ets rename to CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/AlarmItemBean.ets index a071be657a15166b4f76cf5fd9931e55dcf1d4c5..375bb3cd106f28ded587e8366741fdc9f47e995a 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/bean/AlarmItemBean.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/AlarmItemBean.ets @@ -52,5 +52,5 @@ import ReminderItem from './ReminderItemBean'; /** * Custom alarm notification id. */ - notificationId: number; + notificationId: number = 0; } \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/bean/AlarmSettingBean.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/AlarmSettingBean.ets similarity index 87% rename from CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/bean/AlarmSettingBean.ets rename to CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/AlarmSettingBean.ets index fbc5e480314000b387c07e4b183a2ab7c7a9e94a..27f8eaf6a6f2b7007369ba5200dd175f1bfde070 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/bean/AlarmSettingBean.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/AlarmSettingBean.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { AlarmSettingType } from '../constants/AlarmSettingType'; +import { AlarmSettingType } from '../common/constants/AlarmSettingType'; /** * Alarm setting bean information. @@ -34,7 +34,7 @@ export default class AlarmSettingBean { */ public sType: AlarmSettingType; - constructor(title, content, sType) { + constructor(title: string, content: string, sType: AlarmSettingType){ this.title = title; this.content = content; this.sType = sType; diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/common/bean/NoteIdBean.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/DayDateBean.ets similarity index 84% rename from Data/NotePadOpenHarmony/entry/src/main/ets/common/bean/NoteIdBean.ets rename to CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/DayDateBean.ets index cabede9964421ba499f5ca993e6275c53b27991b..5ea00a37a082f78f0170db38d6d10102b9736edc 100644 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/common/bean/NoteIdBean.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/DayDateBean.ets @@ -13,6 +13,8 @@ * limitations under the License. */ -export class NoteIdBean { - noteId: string; +export default class DayDataBean { + timeType: number = 0; + delSelect: number = 0; + data: Array = []; } \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/DetailViewModel.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/DetailViewModel.ets index 9fbf5cd42b39484b0d6dccfe34f95ddefe2ce89f..7828ae1fbe6cb32373e5bb6ea35a3e093c2376d3 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/DetailViewModel.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/DetailViewModel.ets @@ -14,16 +14,18 @@ */ import { DetailConstant } from '../common/constants/DetailConstant'; -import { ALARM_KEY, CommonConstants } from '../common/constants/CommonConstants'; -import AlarmItem from '../common/bean/AlarmItemBean'; +import { CommonConstants, WeekDays } from '../common/constants/CommonConstants'; +import AlarmItem from './AlarmItemBean'; import ReminderService from '../model/ReminderService'; import DataTypeUtils from '../common/utils/DataTypeUtils'; +import { GlobalContext } from '../common/utils/GlobalContext'; +import PreferencesHandler from '../model/database/PreferencesHandler'; /** * Detail page view model description */ export default class DetailViewModel { - private static instant; + static instant: DetailViewModel = new DetailViewModel(); private reminderService: ReminderService; private alarms: Array; @@ -37,12 +39,12 @@ export default class DetailViewModel { * * @return instance */ - public static getInstant() { - if (this.instant == null) { - this.instant = new DetailViewModel(); - } - return this.instant; - } + // public static getInstant() { + // if (this.instant == null) { + // this.instant = new DetailViewModel(); + // } + // return this.instant; + // } /** * Conversion alarm repeat day content @@ -51,27 +53,27 @@ export default class DetailViewModel { * @return repeatContent string */ public transAlarmRepeatDayContent(repeatDay: number): string{ - let repeatContent; + let repeatContent: string = CommonConstants.DEFAULT_STRING_MONDAY;; switch (repeatDay) { - case CommonConstants.DEFAULT_NUMBER_MONDAY: + case WeekDays.DEFAULT_NUMBER_MONDAY: repeatContent = CommonConstants.DEFAULT_STRING_MONDAY; break; - case CommonConstants.DEFAULT_NUMBER_TUESDAY: + case WeekDays.DEFAULT_NUMBER_TUESDAY: repeatContent = CommonConstants.DEFAULT_STRING_TUESDAY; break; - case CommonConstants.DEFAULT_NUMBER_WEDNESDAY: + case WeekDays.DEFAULT_NUMBER_WEDNESDAY: repeatContent = CommonConstants.DEFAULT_STRING_WEDNESDAY; break; - case CommonConstants.DEFAULT_NUMBER_THURSDAY: + case WeekDays.DEFAULT_NUMBER_THURSDAY: repeatContent = CommonConstants.DEFAULT_STRING_THURSDAY; break; - case CommonConstants.DEFAULT_NUMBER_FRIDAY: + case WeekDays.DEFAULT_NUMBER_FRIDAY: repeatContent = CommonConstants.DEFAULT_STRING_FRIDAY; break; - case CommonConstants.DEFAULT_NUMBER_SATURDAY: + case WeekDays.DEFAULT_NUMBER_SATURDAY: repeatContent = CommonConstants.DEFAULT_STRING_SATURDAY; break; - case CommonConstants.DEFAULT_NUMBER_SUNDAY: + case WeekDays.DEFAULT_NUMBER_SUNDAY: repeatContent = CommonConstants.DEFAULT_STRING_SUNDAY; break; default: @@ -86,8 +88,8 @@ export default class DetailViewModel { * @param alarmItem AlarmItem */ public setAlarmDefaultTime(alarmItem?: AlarmItem) { - let hour; - let minute; + let hour: number; + let minute: number; if (alarmItem == null) { let date = new Date(); hour = date.getHours(); @@ -123,11 +125,12 @@ export default class DetailViewModel { alarmItem.notificationId = index; this.alarms.push(alarmItem); } - this.reminderService.addReminder(alarmItem, (newId) => { + this.reminderService.addReminder(alarmItem, (newId: number) => { alarmItem.id = newId; alarmItem.isOpen = true; this.alarms[index] = alarmItem; - globalThis.preference.set(ALARM_KEY, JSON.stringify(this.alarms)); + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + preference.set(CommonConstants.ALARM_KEY, JSON.stringify(this.alarms)); }) } @@ -142,7 +145,8 @@ export default class DetailViewModel { if (index !== CommonConstants.DEFAULT_NUMBER_NEGATIVE) { this.alarms.splice(index, CommonConstants.DEFAULT_SINGLE); } - globalThis.preference.set(ALARM_KEY, JSON.stringify(this.alarms)); + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + preference.set(CommonConstants.ALARM_KEY, JSON.stringify(this.alarms)); } private getAlarmTime(aType: number): number{ @@ -159,7 +163,8 @@ export default class DetailViewModel { } private async findAlarmWithId(id: number) { - let data = await globalThis.preference.get(ALARM_KEY); + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + let data = await preference.get(CommonConstants.ALARM_KEY); if (!DataTypeUtils.isNull(data)) { this.alarms = JSON.parse(data); for (let i = 0;i < this.alarms.length; i++) { diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/MainViewModel.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/MainViewModel.ets index 733e304e121f8c172c5a14d11729ba622a4be7ec..52c8076c920bd72cb3640e91d6a971ce11b16b54 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/MainViewModel.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/MainViewModel.ets @@ -15,19 +15,20 @@ import { MainConstant } from '../common/constants/MainConstant'; import ReminderService from '../model/ReminderService'; -import { ALARM_KEY, CommonConstants } from '../common/constants/CommonConstants'; -import AlarmItem from '../common/bean/AlarmItemBean'; +import { CommonConstants, WeekDays } from '../common/constants/CommonConstants'; +import AlarmItem from './AlarmItemBean'; import DataTypeUtils from '../common/utils/DataTypeUtils'; +import { GlobalContext } from '../common/utils/GlobalContext'; +import PreferencesHandler from '../model/database/PreferencesHandler'; +import PreferencesListener from '../model/database/PreferencesListener'; /** * Declare class of main view model. */ export default class MainViewModel { - private static instant; + static instant: MainViewModel = new MainViewModel(); private reminderService: ReminderService; private alarms: Array; - private drawInterval: any = CommonConstants.DEFAULT_NUMBER_NEGATIVE; - private showClock: boolean = true; private constructor() { this.alarms = new Array(); @@ -38,12 +39,12 @@ export default class MainViewModel { /** * Get instant in MainViewModel. */ - public static getInstant() { - if (this.instant == null) { - this.instant = new MainViewModel(); - } - return this.instant; - } + // public static getInstant() { + // if (this.instant == null) { + // this.instant = new MainViewModel(); + // } + // return this.instant; + // } /** * Querying alarm task database tables. @@ -51,7 +52,8 @@ export default class MainViewModel { * @param callback (alarms: Array) => void */ private queryDatabaseAlarms(callback: (alarms: Array) => void) { - globalThis.preference.get(ALARM_KEY).then((data) => { + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + preference.get(CommonConstants.ALARM_KEY).then((data: string) => { if (!DataTypeUtils.isNull(data)) { this.alarms = JSON.parse(data); callback(this.alarms); @@ -67,11 +69,12 @@ export default class MainViewModel { public queryAlarmsTasker(callback: (alarms: Array) => void) { let that = this; that.queryDatabaseAlarms(callback); - globalThis.preference.addPreferencesListener({ + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + preference.addPreferencesListener({ onDataChanged() { that.queryDatabaseAlarms(callback); } - }) + } as PreferencesListener) } /** @@ -132,29 +135,29 @@ export default class MainViewModel { */ public getAlarmRepeatDayContent(repeatDays: Array): string{ let content = MainConstant.DEFAULT_STRING_NULL; - for (var i = 0; i < repeatDays.length; i++) { + for (let i = 0; i < repeatDays.length; i++) { let repeatDay = repeatDays[i]; - let repeatContent; + let repeatContent: string = CommonConstants.DEFAULT_STRING_MONDAY; switch (repeatDay) { - case CommonConstants.DEFAULT_NUMBER_MONDAY: + case WeekDays.DEFAULT_NUMBER_MONDAY: repeatContent = CommonConstants.DEFAULT_STRING_MONDAY; break; - case CommonConstants.DEFAULT_NUMBER_TUESDAY: + case WeekDays.DEFAULT_NUMBER_TUESDAY: repeatContent = CommonConstants.DEFAULT_STRING_TUESDAY; break; - case CommonConstants.DEFAULT_NUMBER_WEDNESDAY: + case WeekDays.DEFAULT_NUMBER_WEDNESDAY: repeatContent = CommonConstants.DEFAULT_STRING_WEDNESDAY; break; - case CommonConstants.DEFAULT_NUMBER_THURSDAY: + case WeekDays.DEFAULT_NUMBER_THURSDAY: repeatContent = CommonConstants.DEFAULT_STRING_THURSDAY; break; - case CommonConstants.DEFAULT_NUMBER_FRIDAY: + case WeekDays.DEFAULT_NUMBER_FRIDAY: repeatContent = CommonConstants.DEFAULT_STRING_FRIDAY; break; - case CommonConstants.DEFAULT_NUMBER_SATURDAY: + case WeekDays.DEFAULT_NUMBER_SATURDAY: repeatContent = CommonConstants.DEFAULT_STRING_SATURDAY; break; - case CommonConstants.DEFAULT_NUMBER_SUNDAY: + case WeekDays.DEFAULT_NUMBER_SUNDAY: repeatContent = CommonConstants.DEFAULT_STRING_SUNDAY; break; default: @@ -180,7 +183,8 @@ export default class MainViewModel { } else { this.reminderService.deleteReminder(this.alarms[i].id); } - globalThis.preference.set(ALARM_KEY, JSON.stringify(this.alarms)); + let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler; + preference.set(CommonConstants.ALARM_KEY, JSON.stringify(this.alarms)); break; } } diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/bean/ReminderItemBean.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/ReminderItemBean.ets similarity index 81% rename from CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/bean/ReminderItemBean.ets rename to CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/ReminderItemBean.ets index c77d2fc30cfcd8bc0f21c43423659cbc6a0f67ef..93debe0ebaa5fd678ca3642c7e1abcca276699cf 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/common/bean/ReminderItemBean.ets +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/viewmodel/ReminderItemBean.ets @@ -16,15 +16,15 @@ import reminderAgent from '@ohos.reminderAgentManager'; export default class ReminderItemBean { - id: number; + id: number = 0; remindType: reminderAgent.ReminderType = reminderAgent.ReminderType.REMINDER_TYPE_ALARM; - name: string; - hour: number; - minute: number; - duration: number; - intervalMinute: number; - intervalTimes: number; + name: string = ''; + hour: number = 0; + minute: number = 0; + duration: number = 0; + intervalMinute: number = 0; + intervalTimes: number = 0; repeatDays: Array = []; - notificationId: number; + notificationId: number = 0; } diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/module.json5 b/CommonEventAndNotification/AlarmClock/entry/src/main/module.json5 index 4e7bddf3a97b6ddf0999a3ac5d3e287086b2ddcf..38c9995fce4b992ee22a366cd1092b8b240f3082 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/module.json5 +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/module.json5 @@ -35,14 +35,7 @@ ], "requestPermissions": [ { - "name": "ohos.permission.PUBLISH_AGENT_REMINDER", - "reason": "$string:reason", - "usedScene": { - "abilities": [ - "EntryAbility" - ], - "when": "inuse" - } + "name": "ohos.permission.PUBLISH_AGENT_REMINDER" } ] } diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/resources/base/element/string.json b/CommonEventAndNotification/AlarmClock/entry/src/main/resources/base/element/string.json index aa5acf073890f7acc0a71ed2a166d47d45e15f0e..b3d9b333286ae69cd8a2b2e194efb9935d21b0b5 100644 --- a/CommonEventAndNotification/AlarmClock/entry/src/main/resources/base/element/string.json +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/resources/base/element/string.json @@ -59,10 +59,6 @@ { "name": "main_page_title_font_family", "value": "HarmonyHeiTi-Bold" - }, - { - "name": "reason", - "value": "通知" } ] } \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/hvigor/hvigor-config.json5 b/CommonEventAndNotification/AlarmClock/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/CommonEventAndNotification/AlarmClock/hvigor/hvigor-config.json5 +++ b/CommonEventAndNotification/AlarmClock/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/Data/FirstStartDemo/README.md b/Data/FirstStartDemo/README.md index 897bbc290a642ef790a164a6065d06aaffd00e5a..0b30c00b406c21726752caa34524709c2ee7879e 100644 --- a/Data/FirstStartDemo/README.md +++ b/Data/FirstStartDemo/README.md @@ -1,19 +1,23 @@ # 应用首次启动(ArkTS) ## 介绍 -本篇Codelab基于自定义弹框、首选项和页面路由router实现了一个模拟应用首次启动的案例。需要完成以下功能: +本篇Codelab基于自定义弹框、首选项和页面路由实现一个模拟应用首次启动的案例。需要完成以下功能: 1. 实现四个页面,启动页、隐私协议页、广告页、应用首页。 2. 页面之间的跳转。 3. 实现自定义隐私协议弹窗,点击协议可查看隐私协议具体内容。 4. 隐私协议状态持久化存储,再次启动时,如果没有保存状态会再次弹出,否则不弹出。 +效果如图所示: + ![](figures/FirstStartDemo.gif) ### 相关概念 - [首选项](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-data-preferences.md) :首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。数据存储形式为键值对,键的类型为字符串型,值的存储数据类型包括数字型、字符型、布尔型以及这3种类型的数组类型。 + - [自定义弹窗](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-methods-custom-dialog-box.md) : 通过CustomDialogController类显示自定义弹窗。 + - [页面路由](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-router.md) :提供通过不同的url访问不同的页面,包括跳转到应用内的指定页面、用应用内的某个页面替换当前页面、返回上一页面或指定的页面等。 @@ -21,13 +25,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87) 版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87) 版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md) 。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -50,7 +54,7 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 @@ -58,6 +62,7 @@ │ │ ├──constants │ │ │ └──CommonConstants.ets // 常量类 │ │ └──utils +│ │ ├──GlobalContext.ets // 项目工具类 │ │ └──Logger.ets // 日志打印工具类 │ ├──entryability │ │ └──EntryAbility.ets // 程序入口类 @@ -111,17 +116,16 @@ build() { .opacity($r('app.float.launcher_text_opacity')) .margin({ top: CommonConstants.LAUNCHER_TEXT_INTRODUCE_MARGIN_TOP }) } - .height(CommonConstants.FULL_HEIGHT) - .width(CommonConstants.FULL_WIDTH) - } +.height(CommonConstants.FULL_HEIGHT) + .width(CommonConstants.FULL_WIDTH) +} } // 健康生活字体公共样式 -@Extend(Text) function healthyLifeTextStyle (fontWeight: number, - textAttribute: number, fontSize: Resource, fontColor: Resource) { - .fontWeight(fontWeight) - .letterSpacing(textAttribute) - .fontSize(fontSize) - .fontColor(fontColor) +@Extend(Text) function healthyLifeTextStyle (fontWeight: number, textAttribute: number, fontSize: Resource, fontColor: Resource) { + .fontWeight(fontWeight) + .letterSpacing(textAttribute) + .fontSize(fontSize) + .fontColor(fontColor) } ``` @@ -136,15 +140,15 @@ build() { // 自定义弹窗 @CustomDialog export default struct CustomDialogComponent { - controller: CustomDialogController; + controller: CustomDialogController = new CustomDialogController({'builder': ''}); // 不同意按钮回调 - cancel: () => void; + cancel: Function = () => {} // 同意按钮回调 - confirm: () => void; + confirm: Function = () => {} build() { Column() { - // 弹窗标题 - Text($r('app.string.dialog_text_title')) + // 弹窗标题 + Text($r('app.string.dialog_text_title')) .width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT) .fontColor($r('app.color.dialog_text_color')) .fontSize($r('app.float.dialog_text_privacy_size')) @@ -163,11 +167,10 @@ export default struct CustomDialogComponent { .fontColor($r('app.color.dialog_text_statement_color')) .fontSize($r('app.float.dialog_common_text_size')) .onClick(() => { - globalThis.isJumpPrivacy = true; router.pushUrl({ url: CommonConstants.PRIVACY_PAGE_URL - }).catch((error) => { - Logger.error(CommonConstants.CUSTOM_DIALOG_TAG, 'CustomDialog pushUrl error ' + JSON.stringify(error)); + }).catch((error: Error) => { + Logger.error(CommonConstants.CUSTOM_DIALOG_TAG, 'CustomDialog pushUrl error ' + JSON.stringify(error)); }); }) // 协议声明 @@ -200,6 +203,9 @@ export default struct CustomDialogComponent { } .margin({ bottom: CommonConstants.DIALOG_ROW_MARGIN_BOTTOM }) } + .width(CommonConstants.DIALOG_WIDTH_PERCENT) + .borderRadius(CommonConstants.DIALOG_BORDER_RADIUS) + .backgroundColor(Color.White) } } @@ -222,12 +228,12 @@ export default struct CustomDialogComponent { onPageShow() { ... // 获取保存数据操作类 - this.getDataPreferences().then((preferences: preferences.Preferences) => { - preferences.get(CommonConstants.PREFERENCES_KEY_PRIVACY, true) - .then((value: preferences.ValueType) => { + this.getDataPreferences(this).then((preferences: preferences.Preferences) => { + preferences.get(CommonConstants.PREFERENCES_KEY_PRIVACY, true).then((value: preferences.ValueType) => { Logger.info(CommonConstants.LAUNCHER_PAGE_TAG, 'onPageShow value: ' + value); if (value) { - let isJumpPrivacy: boolean = globalThis.isJumpPrivacy ?? false; + // let isJumpPrivacy: boolean = globalThis.isJumpPrivacy ?? false; + let isJumpPrivacy: boolean = (GlobalContext.getContext().getObject('isJumpPrivacy') as boolean) ?? false; if (!isJumpPrivacy) { // 自定义协议弹窗 this.dialogController.open(); @@ -241,8 +247,8 @@ onPageShow() { } // 获取数据首选项操作 -getDataPreferences() { - return preferences.getPreferences(this.context, 'myStore'); +getDataPreferences(common: Object) : Promise{ + return preferences.getPreferences(getContext(common), CommonConstants.PREFERENCES_FILE_NAME); } ``` @@ -252,14 +258,14 @@ getDataPreferences() { ```typescript // LauncherPage.ets -onConfirm() { +onConfirm(): void { // 保存隐私协议状态 this.saveIsPrivacy(); ... } -saveIsPrivacy() { - let preferences: Promise = this.getDataPreferences(); +saveIsPrivacy(): void { + let preferences: Promise = this.getDataPreferences(this); preferences.then((result: preferences.Preferences) => { let privacyPut = result.put(CommonConstants.PREFERENCES_KEY_PRIVACY, false); result.flush(); @@ -277,26 +283,30 @@ saveIsPrivacy() { ```typescript // LauncherPage.ets private isJumpToAdvertising: boolean = false; -onConfirm() { +onConfirm() :void{ ... // 跳转到广告页 this.jumpToAdvertisingPage(); } -jumpToAdvertisingPage() { +jumpToAdvertisingPage() :void{ this.timerId = setTimeout(() => { // 设置跳转标识 this.isJumpToAdvertising = true; - router.push({ url: CommonConstants.ADVERTISING_PAGE_URL }) + router.pushUrl({ + url: CommonConstants.ADVERTISING_PAGE_URL + }).catch((error: Error) => { + Logger.error(CommonConstants.LAUNCHER_PAGE_TAG, 'LauncherPage pushUrl error ' + JSON.stringify(error)); + }); }, CommonConstants.LAUNCHER_DELAY_TIME); } -onPageHide() { +onPageHide(): void { if (this.isJumpToAdvertising) { // 清除页面 router.clear(); } - globalThis.isJumpPrivacy = true; + GlobalContext.getContext().setObject('isJumpPrivacy', true); // 清除定时器 clearTimeout(this.timerId); } @@ -309,23 +319,24 @@ onPageHide() { ```typescript // AdvertisingPage.ets @State countDownSeconds: number = CommonConstants.ADVERTISING_COUNT_DOWN_SECONDS; +private timeId: number = 0; onPageShow() { - // 开启2秒倒计时 - this.timeId = setInterval(() => { - if (this.countDownSeconds == 0) { - // 跳转到首页 - this.jumpToAppHomePage(); - } else { - this.countDownSeconds--; - } - }, CommonConstants.ADVERTISING_INTERVAL_TIME); + // 开启2秒倒计时 + this.timeId = setInterval(() => { + if (this.countDownSeconds == 0) { + // 跳转到首页 + this.jumpToAppHomePage(); + } else { + this.countDownSeconds--; + } + }, CommonConstants.ADVERTISING_INTERVAL_TIME); } onPageHide() { - // 清除页面 - router.clear(); - // 清除定时器 - clearInterval(this.timeId); + // 清除页面 + router.clear(); + // 清除定时器 + clearInterval(this.timeId); } build() { @@ -340,16 +351,16 @@ build() { }) ... } - .width(CommonConstants.FULL_WIDTH) - .height(CommonConstants.FULL_HEIGHT) +.width(CommonConstants.FULL_WIDTH) + .height(CommonConstants.FULL_HEIGHT) } -jumpToAppHomePage() { - router.pushUrl({ - url: CommonConstants.APP_HOME_PAGE_URL - }).catch((error) => { - Logger.error(CommonConstants.ADVERTISING_PAGE_TAG, 'AdvertisingPage pushUrl error ' + JSON.stringify(error)); - }); +jumpToAppHomePage(): void { + router.pushUrl({ + url: CommonConstants.APP_HOME_PAGE_URL + }).catch((error) => { + Logger.error(CommonConstants.ADVERTISING_PAGE_TAG, 'AdvertisingPage pushUrl error ' + JSON.stringify(error)); + }); } ``` diff --git a/Data/FirstStartDemo/entry/src/main/ets/common/constants/CommonConstants.ets b/Data/FirstStartDemo/entry/src/main/ets/common/constants/CommonConstants.ets index 727c46523d74dfa9dfc8c624ea3da94c4e5f7ab5..3e0f6d4c1b9377040400ef7a35e3990635f47792 100644 --- a/Data/FirstStartDemo/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/Data/FirstStartDemo/entry/src/main/ets/common/constants/CommonConstants.ets @@ -21,162 +21,130 @@ export default class CommonConstants { * The main ability tag. */ static readonly ENTRY_ABILITY_TAG: string = 'EntryAbility'; - /** * The launcher page tag. */ static readonly LAUNCHER_PAGE_TAG: string = 'LauncherPage'; - /** * The advertsing page tag. */ static readonly ADVERTISING_PAGE_TAG: string = 'AdvertisingPage'; - /** * The custom dialog component tag. */ static readonly CUSTOM_DIALOG_TAG: string = 'CustomDialogComponent'; - /** * Preference saved key. */ static readonly PREFERENCES_KEY_PRIVACY: string = 'isPrivacy'; - /** * Preference saved file name. */ static readonly PREFERENCES_FILE_NAME: string = 'myStore'; - /** * Launcher page count down. */ static readonly LAUNCHER_DELAY_TIME: number = 3000; - /** * Image logo top margin. */ static readonly LAUNCHER_IMAGE_MARGIN_TOP: string = '16.2%'; - /** * Healthy living text spacing. */ static readonly LAUNCHER_LIFE_TEXT_SPACING: number = 0.1; - /** * Healthy living title text top margin. */ static readonly LAUNCHER_TEXT_TITLE_MARGIN_TOP: string = '0.5%'; - /** * Content control height. */ static readonly LAUNCHER_TEXT_INTRODUCE_HEIGHT: string = '2.7%'; - /** * Healthy living instructions. */ static readonly LAUNCHER_TEXT_INTRODUCE_SPACING: number = 3.4; - /** * Healthy living content top margin. */ static readonly LAUNCHER_TEXT_INTRODUCE_MARGIN_TOP: string = '1.3%'; - /** * Interval execution time. */ static readonly ADVERTISING_INTERVAL_TIME: number = 1000; - /** * Advertising page url. */ static readonly ADVERTISING_PAGE_URL: string = 'pages/AdvertisingPage'; - /** * Display countdown seconds. */ static readonly ADVERTISING_COUNT_DOWN_SECONDS: number = 2; - /** * Count down text spacing. */ static readonly ADVERTISING_TITLE_TEXT_LETTER_SPACING: number = 0.05; - /** * Advertising page healthy text spacing. */ static readonly ADVERTISING_HEALTHY_LIFE_TEXT_SPACING: number = 0.1; - /** * Advertising page health description text spacing. */ static readonly ADVERTISING_TEXT_INTRODUCE_LETTER_SPACING: number = 3.4; - /** * Advertising page health description text top margin. */ static readonly ADVERTISING_TEXT_INTRODUCE_MARGIN_TOP: string = '0.4%'; - /** * Column container left margin. */ static readonly ADVERTISING_COLUMN_MARGIN_LEFT: string = '3.1%'; - /** * Row container bottom margin. */ static readonly ADVERTISING_ROW_MARGIN_BOTTOM: string = '3.1%'; - /** * Dialog component width the percentage of the 90. */ static readonly DIALOG_COMPONENT_WIDTH_PERCENT: string = '90%'; - /** * Dialog title text weight. */ static readonly DIALOG_TITLE_FONT_WEIGHT: number = 600; - /** * Dialog width the percentage of the 93.3. */ static readonly DIALOG_WIDTH_PERCENT: string = '93.3%'; - /** * Dialog border radius. */ static readonly DIALOG_BORDER_RADIUS: number = 24; - /** * Dialog component bottom margin, */ static readonly DIALOG_ROW_MARGIN_BOTTOM: string = '3.1%'; - /** * Dialog y-axis offset distance. */ static readonly DIALOG_CONTROLLER_DY_OFFSET: number = -24; - /** * Width the percentage of the 100. */ static readonly FULL_WIDTH: string = '100%'; - /** * Height the percentage of the 100. */ static readonly FULL_HEIGHT: string = '100%'; - /** * Privacy page url. */ static readonly PRIVACY_PAGE_URL: string = 'pages/PrivacyPage'; - /** * App home page url. */ static readonly APP_HOME_PAGE_URL: string = 'pages/AppHomePage'; - /** * Common layout weight. */ diff --git a/Data/FirstStartDemo/entry/src/main/ets/common/utils/GlobalContext.ets b/Data/FirstStartDemo/entry/src/main/ets/common/utils/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..23f5130a61c9e0ac09c5d885cdcaa2c878e0d522 --- /dev/null +++ b/Data/FirstStartDemo/entry/src/main/ets/common/utils/GlobalContext.ets @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { + } + + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/Data/FirstStartDemo/entry/src/main/ets/common/utils/Logger.ets b/Data/FirstStartDemo/entry/src/main/ets/common/utils/Logger.ets index 6c73f6bdd1d859c44aeb1e3c0107c9b920a73779..d25555932fda141899f51d8f50bd13e720f0e679 100644 --- a/Data/FirstStartDemo/entry/src/main/ets/common/utils/Logger.ets +++ b/Data/FirstStartDemo/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: Object[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: Object[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: Object[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: Object[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Data/FirstStartDemo/entry/src/main/ets/entryability/EntryAbility.ets b/Data/FirstStartDemo/entry/src/main/ets/entryability/EntryAbility.ets index 47249aa86cf57538b6a8f4fb8f9aca75a00ebdd5..12bfed69b07dc0630c238a71e7ae5354bcfe8e30 100644 --- a/Data/FirstStartDemo/entry/src/main/ets/entryability/EntryAbility.ets +++ b/Data/FirstStartDemo/entry/src/main/ets/entryability/EntryAbility.ets @@ -16,16 +16,17 @@ import UIAbility from '@ohos.app.ability.UIAbility'; import Logger from '../common/utils/Logger'; import CommonConstants from '../common/constants/CommonConstants'; +import window from '@ohos.window'; /** * Lift cycle management of Ability. */ export default class EntryAbility extends UIAbility { - onCreate(want) { - globalThis.abilityWant = want; - } + // onCreate(want) { + // globalThis.abilityWant = want; + // } - onWindowStageCreate(windowStage) { + onWindowStageCreate(windowStage: window.WindowStage): void { Logger.info(CommonConstants.ENTRY_ABILITY_TAG, 'onWindowStageCreate'); windowStage.loadContent('pages/LauncherPage', (err, data) => { if (err.code) { diff --git a/Data/FirstStartDemo/entry/src/main/ets/pages/AdvertisingPage.ets b/Data/FirstStartDemo/entry/src/main/ets/pages/AdvertisingPage.ets index ecf0b6e691c06915b1cc3ddc85dca2aa05f4254a..750d7e28421ed2121581f1ddddf8ca679a4356b9 100644 --- a/Data/FirstStartDemo/entry/src/main/ets/pages/AdvertisingPage.ets +++ b/Data/FirstStartDemo/entry/src/main/ets/pages/AdvertisingPage.ets @@ -24,7 +24,7 @@ import CommonConstants from '../common/constants/CommonConstants'; @Component struct AdvertisingPage { @State countDownSeconds: number = CommonConstants.ADVERTISING_COUNT_DOWN_SECONDS; - private timeId: number; + private timeId: number = 0; onPageShow() { this.timeId = setInterval(() => { @@ -44,10 +44,10 @@ struct AdvertisingPage { /** * Jump to app home page. */ - jumpToAppHomePage() { + jumpToAppHomePage(): void { router.pushUrl({ url: CommonConstants.APP_HOME_PAGE_URL - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.ADVERTISING_PAGE_TAG, 'AdvertisingPage pushUrl error ' + JSON.stringify(error)); }); } @@ -88,14 +88,14 @@ struct AdvertisingPage { Column() { Text($r('app.string.healthy_life_text')) .bottomTextStyle(FontWeight.Bolder, - CommonConstants.ADVERTISING_HEALTHY_LIFE_TEXT_SPACING, - $r('app.float.advertising_text_title_size'), - $r('app.color.advertising_text_title_color')) + CommonConstants.ADVERTISING_HEALTHY_LIFE_TEXT_SPACING, + $r('app.float.advertising_text_title_size'), + $r('app.color.advertising_text_title_color')) Text($r('app.string.healthy_life_introduce')) .bottomTextStyle(FontWeight.Normal, - CommonConstants.ADVERTISING_TEXT_INTRODUCE_LETTER_SPACING, - $r('app.float.advertising_text_introduce_size'), - $r('app.color.launcher_text_introduce_color')) + CommonConstants.ADVERTISING_TEXT_INTRODUCE_LETTER_SPACING, + $r('app.float.advertising_text_introduce_size'), + $r('app.color.launcher_text_introduce_color')) .opacity($r('app.float.advertising_text_opacity')) .margin({ top: CommonConstants.ADVERTISING_TEXT_INTRODUCE_MARGIN_TOP }) } @@ -112,9 +112,9 @@ struct AdvertisingPage { .height(CommonConstants.FULL_HEIGHT) } } + // Bottom text common style. -@Extend(Text) function bottomTextStyle (fontWeight: number, - textAttribute: number, fontSize: Resource, fontColor: Resource) { +@Extend(Text) function bottomTextStyle (fontWeight: number, textAttribute: number, fontSize: Resource, fontColor: Resource) { .fontWeight(fontWeight) .letterSpacing(textAttribute) .fontSize(fontSize) diff --git a/Data/FirstStartDemo/entry/src/main/ets/pages/LauncherPage.ets b/Data/FirstStartDemo/entry/src/main/ets/pages/LauncherPage.ets index a74bd2579e49f730901c175c0383903ed7eae3f5..9528aa526718b0fc63f681a31b6e32d7201f18e5 100644 --- a/Data/FirstStartDemo/entry/src/main/ets/pages/LauncherPage.ets +++ b/Data/FirstStartDemo/entry/src/main/ets/pages/LauncherPage.ets @@ -19,6 +19,7 @@ import router from '@ohos.router'; import Logger from '../common/utils/Logger'; import CommonConstants from '../common/constants/CommonConstants'; import CustomDialogComponent from '../view/CustomDialogComponent'; +import { GlobalContext } from '../common/utils/GlobalContext'; /** * The LauncherPage is the entry point of the application and shows how to develop the LauncherPage. @@ -28,14 +29,18 @@ import CustomDialogComponent from '../view/CustomDialogComponent'; @Entry @Component struct LauncherPage { - private context: common.UIAbilityContext; + private context?: common.UIAbilityContext; private timerId: number = 0; private isJumpToAdvertising: boolean = false; dialogController: CustomDialogController = new CustomDialogController({ builder: CustomDialogComponent( { - cancel: this.onCancel.bind(this), - confirm: this.onConfirm.bind(this) + cancel: () => { + this.onCancel(); + }, + confirm: () => { + this.onConfirm(); + } }), alignment: DialogAlignment.Bottom, offset: { dx: 0, dy: CommonConstants.DIALOG_CONTROLLER_DY_OFFSET }, @@ -43,50 +48,51 @@ struct LauncherPage { autoCancel: false }); - onCancel() { + onCancel(): void { // Exit the application. - this.context.terminateSelf(); + this.context?.terminateSelf(); } - onConfirm() { + onConfirm(): void { // Save privacy agreement status. this.saveIsPrivacy(); this.jumpToAdvertisingPage(); } - onPageHide() { + onPageHide(): void { if (this.isJumpToAdvertising) { router.clear(); } - globalThis.isJumpPrivacy = true; + // globalThis.isJumpPrivacy = true; + GlobalContext.getContext().setObject('isJumpPrivacy', true); clearTimeout(this.timerId); } /** * Jump to advertising page. */ - jumpToAdvertisingPage() { + jumpToAdvertisingPage(): void { this.timerId = setTimeout(() => { this.isJumpToAdvertising = true; router.pushUrl({ url: CommonConstants.ADVERTISING_PAGE_URL - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.LAUNCHER_PAGE_TAG, 'LauncherPage pushUrl error ' + JSON.stringify(error)); }); }, CommonConstants.LAUNCHER_DELAY_TIME); } - saveIsPrivacy() { - let preferences: Promise = this.getDataPreferences(); + saveIsPrivacy(): void { + let preferences: Promise = this.getDataPreferences(this); preferences.then((result: preferences.Preferences) => { let privacyPut = result.put(CommonConstants.PREFERENCES_KEY_PRIVACY, false); result.flush(); privacyPut.then(() => { Logger.info(CommonConstants.LAUNCHER_PAGE_TAG, 'Put the value of startup Successfully.'); - }).catch((err) => { + }).catch((err: Error) => { Logger.error(CommonConstants.LAUNCHER_PAGE_TAG, 'Put the value of startup Failed, err: ' + err); }); - }).catch((err) => { + }).catch((err: Error) => { Logger.error(CommonConstants.LAUNCHER_PAGE_TAG, 'Get the preferences Failed, err: ' + err); }); } @@ -94,11 +100,12 @@ struct LauncherPage { onPageShow() { this.context = getContext(this) as common.UIAbilityContext; // Get the operation class for saving data. - this.getDataPreferences().then((preferences: preferences.Preferences) => { + this.getDataPreferences(this).then((preferences: preferences.Preferences) => { preferences.get(CommonConstants.PREFERENCES_KEY_PRIVACY, true).then((value: preferences.ValueType) => { Logger.info(CommonConstants.LAUNCHER_PAGE_TAG, 'onPageShow value: ' + value); if (value) { - let isJumpPrivacy: boolean = globalThis.isJumpPrivacy ?? false; + // let isJumpPrivacy: boolean = globalThis.isJumpPrivacy ?? false; + let isJumpPrivacy: boolean = (GlobalContext.getContext().getObject('isJumpPrivacy') as boolean) ?? false; if (!isJumpPrivacy) { this.dialogController.open(); } @@ -112,8 +119,8 @@ struct LauncherPage { /** * Get data preferences action. */ - getDataPreferences() { - return preferences.getPreferences(this.context, CommonConstants.PREFERENCES_FILE_NAME); + getDataPreferences(common: Object): Promise { + return preferences.getPreferences(getContext(common), CommonConstants.PREFERENCES_FILE_NAME); } build() { @@ -148,11 +155,12 @@ struct LauncherPage { } } } + // Healthy living text common styles. -@Extend(Text) function healthyLifeTextStyle (fontWeight: number, - textAttribute: number, fontSize: Resource, fontColor: Resource) { - .fontWeight(fontWeight) - .letterSpacing(textAttribute) - .fontSize(fontSize) - .fontColor(fontColor) +@Extend(Text) +function healthyLifeTextStyle(fontWeight: number, textAttribute: number, fontSize: Resource, fontColor: Resource) { + .fontWeight(fontWeight) + .letterSpacing(textAttribute) + .fontSize(fontSize) + .fontColor(fontColor) } \ No newline at end of file diff --git a/Data/FirstStartDemo/entry/src/main/ets/pages/PrivacyPage.ets b/Data/FirstStartDemo/entry/src/main/ets/pages/PrivacyPage.ets index d523ddf944e0f909838334657b36e4e59d1667d4..662e550627654989bf88d17e2b97c24923b81a35 100644 --- a/Data/FirstStartDemo/entry/src/main/ets/pages/PrivacyPage.ets +++ b/Data/FirstStartDemo/entry/src/main/ets/pages/PrivacyPage.ets @@ -15,6 +15,7 @@ import router from '@ohos.router'; import CommonConstants from '../common/constants/CommonConstants'; +import { GlobalContext } from '../common/utils/GlobalContext'; /** * The privacy agreement page displays the agreement content. @@ -43,7 +44,8 @@ struct PrivacyPage { .textAlign(TextAlign.Center) .fontWeight(FontWeight.Medium) .onClick(() => { - globalThis.isJumpPrivacy = false; + // globalThis.isJumpPrivacy = false; + GlobalContext.getContext().setObject('isJumpPrivacy', false); router.back(); }) .margin({ top: $r('app.float.privacy_bottom_text_margin') }) @@ -53,6 +55,7 @@ struct PrivacyPage { } onBackPress() { - globalThis.isJumpPrivacy = false; + // globalThis.isJumpPrivacy = false; + GlobalContext.getContext().setObject('isJumpPrivacy', false); } } \ No newline at end of file diff --git a/Data/FirstStartDemo/entry/src/main/ets/view/CustomDialogComponent.ets b/Data/FirstStartDemo/entry/src/main/ets/view/CustomDialogComponent.ets index 08569ab7e377132ba0d0e294bdb1c25217f1b29e..2e7ce02331bcd421667d1a6349a869e8e529f8c0 100644 --- a/Data/FirstStartDemo/entry/src/main/ets/view/CustomDialogComponent.ets +++ b/Data/FirstStartDemo/entry/src/main/ets/view/CustomDialogComponent.ets @@ -22,9 +22,11 @@ import CommonConstants from '../common/constants/CommonConstants'; */ @CustomDialog export default struct CustomDialogComponent { - controller: CustomDialogController; - cancel: () => void; - confirm: () => void; + controller: CustomDialogController = new CustomDialogController({ 'builder': '' }); + cancel: Function = () => { + } + confirm: Function = () => { + } build() { Column() { @@ -48,7 +50,7 @@ export default struct CustomDialogComponent { .onClick(() => { router.pushUrl({ url: CommonConstants.PRIVACY_PAGE_URL - }).catch((error) => { + }).catch((error: Error) => { Logger.error(CommonConstants.CUSTOM_DIALOG_TAG, 'CustomDialog pushUrl error ' + JSON.stringify(error)); }); }) @@ -85,7 +87,8 @@ export default struct CustomDialogComponent { } // Common text styles. -@Extend(Text) function fancy () { +@Extend(Text) +function fancy() { .fontColor($r("app.color.dialog_fancy_text_color")) .fontSize($r("app.float.dialog_fancy_text_size")) .textAlign(TextAlign.Center) diff --git a/Data/FirstStartDemo/hvigor/hvigor-config.json5 b/Data/FirstStartDemo/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/Data/FirstStartDemo/hvigor/hvigor-config.json5 +++ b/Data/FirstStartDemo/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/Data/NotePadOpenHarmony/README.md b/Data/NotePadOpenHarmony/README.md index 689c07eb945df50b44f10e582391f921dacb663e..1baa84b94ba353712742edad191ebcfbd30d38f2 100644 --- a/Data/NotePadOpenHarmony/README.md +++ b/Data/NotePadOpenHarmony/README.md @@ -15,13 +15,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -49,9 +49,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──NoteIdBean.ets // 备忘录id类型 -│ │ │ └──NoteInfoBean.ets // 备忘录数据类型 │ │ ├──constants │ │ │ ├──CommonConstants.ets // 常量类 │ │ │ └──StyleConstants.ets // 样式常量类 @@ -65,12 +62,12 @@ │ ├──pages │ │ ├──NoteHomePage.ets // 备忘录主页面(列表页) │ │ └──NotesDetail.ets // 备忘录详情页 -│ ├──viewmodel -│ │ └──NotesInfoViewModel.ets // 备忘录默认数据实体 -│ └──view -│ ├──BottomBar.ets // 备忘录编辑页底部栏 -│ ├──ConfirmDialog.ets // 自定义弹窗 -│ └──MemoItem.ets // 自定义备忘录列表组件 +│ ├──view +│ │ ├──BottomBar.ets // 备忘录编辑页底部栏 +│ │ ├──ConfirmDialog.ets // 自定义弹窗 +│ │ └──MemoItem.ets // 自定义备忘录列表组件 +│ └──viewmodel +│ └──NotesInfoViewModel.ets // 备忘录默认数据实体 └──entry/src/main/resources // 资源文件目录 ``` @@ -87,29 +84,31 @@ import dataStorage from '@ohos.data.preferences'; ... class NotesDataModel { + private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; + /** * 写入备忘录数据. */ async saveDefaultData() { try { - let preferences = await dataStorage.getPreferences(globalThis.context, CommonConstants.PREFERENCE_INSTANCE_NAME); + let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME); let isExist = await preferences.has(CommonConstants.PREFERENCE_NOTE_KEY); if (!isExist) { preferences.put(CommonConstants.PREFERENCE_NOTE_KEY, JSON.stringify(noteIdArray)); preferences.flush(); notesItemArr.forEach((item: NotesInfoBean) => { - let notes = new NotesInfoBean(item); + let notes: NotesInfoBean = item; let res = preferences.put(item.noteId, JSON.stringify(notes)); preferences.flush(); res.then(() => { Logger.info('Put the value successfully.' + item.noteId); - }).catch((err) => { - Logger.error('Put the value failed with err:', err); + }).catch((err: Error) => { + Logger.error(`Put the value failed with err: ${err}`); }) }) } } catch (err) { - Logger.error('Failed to get preferences. code = ', err.code + ', message =' + err.message); + Logger.error(`Failed to get preferences. Error = ${err}`); } } @@ -132,14 +131,14 @@ class NotesDataModel { // NoteHomePage.ets import dataStorage from '@ohos.data.preferences'; ... - @Entry @Component struct NoteHomePage { @State folderType: Resource = $r('app.string.notes_all'); @State allNotes: Array = []; @State selectNotes: Array = this.allNotes.sort(); - + private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; + ... build() { Column() { ... @@ -148,10 +147,11 @@ struct NoteHomePage { ListItem() { MemoItem({ noteItem: item }) } - }, item => JSON.stringify(item)) + }, (item: NotesInfoBean) => JSON.stringify(item)) } .margin({ top: $r('app.float.list_container_margin') }) .height(StyleConstants.NOTE_CONTENT_HEIGHT) + .width(StyleConstants.FULL_WIDTH) } .backgroundColor($r('app.color.page_background')) .height(StyleConstants.FULL_HEIGHT) @@ -164,15 +164,14 @@ struct NoteHomePage { async getAllNotes() { await NotesDataModel.saveDefaultData(); try { - let preferences = await dataStorage.getPreferences(globalThis.context, - CommonConstants.PREFERENCE_INSTANCE_NAME); + let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME); let noteIds = await preferences.get(CommonConstants.PREFERENCE_NOTE_KEY, ''); while (this.allNotes.length >= 1) { this.allNotes.pop(); } JSON.parse(noteIds.toString()).forEach(async (item: NotesInfoBean) => { let note = await preferences.get(item.noteId, ''); - this.allNotes.push(new NotesInfoBean(JSON.parse(note.toString()))); + this.allNotes.push(JSON.parse(note.toString())); }) } catch (err) { Logger.error('Get the value of noteIdArr failed with err:', err); @@ -191,125 +190,86 @@ struct NoteHomePage { ```typescript // NoteHomePage.ets -@Entry -@Component -struct NoteHomePage { - @State folderType: Resource = $r('app.string.notes_all'); - @State allNotes: Array = []; - @State selectNotes: Array = this.allNotes.sort(); - ... - build() { - Column() { - Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { - Column() { - Row() { - ... - Navigator({ target: 'pages/NotesDetail', type: NavigationType.Replace }) { - Row() { - Image($rawfile('ic_title_add.svg')) - ... - } - .margin({ right: $r('app.float.note_add_margin') }) - } - .params({ - notesInfo: { - 'noteId': new Date().getTime().toString(), - 'title': '', - 'folder': FolderType.Personal, - 'content': '', - 'imageArr': [], - 'time': new Date().toTimeString().split(' ')[0], - 'isFavorite': false - }, - operationType: CommonConstants.ADD_NOTE - }) - } - ... - } - ... - } +Navigator({ target: 'pages/NotesDetail', type: NavigationType.Replace }) { + Row() { + Image($rawfile('ic_title_add.svg')) ... - } - .backgroundColor($r('app.color.page_background')) - .height(StyleConstants.FULL_HEIGHT) } - ... + .margin({ right: $r('app.float.note_add_margin') }) } +.params({ + notesInfo: { + 'noteId': new Date().getTime().toString(), + 'title': '', + 'folder': FolderType.Personal, + 'content': '', + 'imageArr': [], + 'time': new Date().toTimeString().split(' ')[0], + 'isFavorite': false + }, + operationType: CommonConstants.ADD_NOTE +}) ``` 进入编辑页NotesDetail.ets后可以输入标题、内容以及选择对应的笔记类型等,确认保存后备忘录数据实时更新。 ```typescript // NotesDetail.ets -@Entry -@Component -struct NotesDetail { - @State isDataChange: boolean = false; - @State @Watch('onChangeCollect') isFavorite: boolean = this.notesInfo.isFavorite; - @State isCollectChange: boolean = false; +build() { ... - build() { - Column() { - ... - Stack({ alignContent: Alignment.Bottom }) { - Scroll(this.scroller) { - Column() { - TextInput({ - ... - }) - ... - .onChange((value: string) => { - if (value !== this.notesInfo.title) { - this.notesInfo.title = value; - this.isDataChange = true; - } - }) - TextArea({ - text: this.notesInfo.content != '' ? this.notesInfo.content : '', - placeholder: this.notesInfo.content != '' ? '' : $r('app.string.note_content_placeholder') - }) - ... - .onChange((value: string) => { - if (value !== this.notesInfo.content) { - this.notesInfo.content = value; - this.isDataChange = true; - } - }) - } - } - ... + TextInput({ + text: this.notesInfo.title != '' ? this.notesInfo.title : '', + placeholder: this.notesInfo.title != '' ? '' : $r('app.string.note_title_placeholder') + }) + ... + .onChange((value: string) => { + if (value !== this.notesInfo.title) { + this.notesInfo.title = value; + this.isDataChanged = true; } - } - .height(StyleConstants.FULL_HEIGHT) - .backgroundColor($r('app.color.white_color')) + }) + ... + TextArea({ + text: this.notesInfo.content !== '' ? this.notesInfo.content : '', + placeholder: this.notesInfo.content !== '' ? '' : $r('app.string.note_content_placeholder') + }) + .onChange((value: string) => { + if (value !== this.notesInfo.content) { + this.notesInfo.content = value; + this.isDataChanged = true; + } + }) + ... +} + +onBackPress() { + if (this.isDataChanged || this.notesFolder !== this.notesInfo.folder || this.isCollectChange) { + this.saveDialogController.open(); + } else { + router.replaceUrl({ + url: 'pages/NoteHomePage' + }); } + return true; +} - async saveNoteIdArray() { - let preferences = await data_preferences.getPreferences(globalThis.context, - CommonConstants.PREFERENCE_INSTANCE_NAME); +// ConfirmDialog.ets +if (this.type === CommonConstants.SAVE_DIALOG) { + this.confirm = async () => { + let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME); + // 保存备忘录数据实时更新 if (this.operationType === CommonConstants.ADD_NOTE) { - this.noteIdArray.push({ 'noteId': this.notesInfo.noteId }); - preferences.put('noteIdArr', JSON.stringify(this.noteIdArray)); + this.noteIdArray.push(new NoteIdBean(this.notesInfo.noteId)); + preferences.put(CommonConstants.PREFERENCE_NOTE_KEY, JSON.stringify(this.noteIdArray)); preferences.flush(); } - let newNotes = new NotesInfoBean(this.notesInfo); + let newNotes = this.notesInfo; await preferences.put(this.notesInfo.noteId, JSON.stringify(newNotes)); await preferences.flush(); router.replaceUrl({ url: 'pages/NoteHomePage' }); } - - onBackPress() { - if (this.isDataChanged || this.notesFolder !== this.notesInfo.folder || this.isCollectChange) { - this.saveDialogController.open(); - } else { - router.replaceUrl({ - url: 'pages/NoteHomePage' - }); - } - return true; - } } ``` @@ -323,103 +283,103 @@ struct NotesDetail { ```typescript // NotesDetail.ets -@Entry -@Component -struct NotesDetail { - @State isDataChange: boolean = false; - @State @Watch('onChangeCollect') isFavorite: boolean = this.notesInfo.isFavorite; - @State isCollectChange: boolean = false; - ... - build() { - Column() { - ... - Stack({ alignContent: Alignment.Bottom }) { - Scroll(this.scroller) { - Column() { - TextInput({ - ... +build() { + Column() { + ... + Stack({ alignContent: Alignment.Bottom }) { + Scroll(this.scroller) { + Column() { + TextInput({ + text: this.notesInfo.title != '' ? this.notesInfo.title : '', + placeholder: this.notesInfo.title != '' ? '' : $r('app.string.note_title_placeholder') + }) + ... + .onChange((value: string) => { + if (value !== this.notesInfo.title) { + this.notesInfo.title = value; + this.isDataChanged = true; + } }) - ... - .onChange((value: string) => { - if (value !== this.notesInfo.title) { - this.notesInfo.title = value; - this.isDataChange = true; - } - }) - TextArea({ - text: this.notesInfo.content != '' ? this.notesInfo.content : '', - placeholder: this.notesInfo.content != '' ? '' : $r('app.string.note_content_placeholder') + ... + TextArea({ + text: this.notesInfo.content !== '' ? this.notesInfo.content : '', + placeholder: this.notesInfo.content !== '' ? '' : $r('app.string.note_content_placeholder') + }) + .onChange((value: string) => { + if (value !== this.notesInfo.content) { + this.notesInfo.content = value; + this.isDataChanged = true; + } }) - ... - .onChange((value: string) => { - if (value !== this.notesInfo.content) { - this.notesInfo.content = value; - this.isDataChange = true; - } - }) - } - } - - BottomBar({ ... - clickCollect: this.clickCollect.bind(this), - clickAddPicture: this.clickAddPicture.bind(this) - }) + } } ... + BottomBar({ + imageArr: $imageArr, + notesInfo: $notesInfo, + operationType: $operationType, + noteIdArray: $noteIdArray, + isDataChanged: $isDataChanged + }) } - .height(StyleConstants.FULL_HEIGHT) - .backgroundColor($r('app.color.white_color')) - } - - clickCollect() { - this.notesInfo.isFavorite = !this.notesInfo.isFavorite; - this.isFavorite = !this.isFavorite; - this.collectImgSrc = this.notesInfo.isFavorite ? - 'ic_bottom_star_selected.svg' : 'ic_bottom_star_normal.svg'; + ... } - - - onChangeCollect() { - this.isCollectChange = !this.isCollectChange; + .height(StyleConstants.FULL_HEIGHT) + .backgroundColor($r('app.color.white_color')) +} +... +onBackPress() { + if (this.isDataChanged || this.notesFolder !== this.notesInfo.folder || this.isCollectChange) { + this.saveDialogController.open(); + } else { + router.replaceUrl({ + url: 'pages/NoteHomePage' + }); } + return true; +} - clickAddPicture() { - this.imageSrc = this.chooseImage(); - if (this.imageSrc === '') { - ... - } else { - ... - this.isDataChanged = true; - } +// BottomBar.ets +// 点击收藏 +this.clickCollect = () => { + this.notesInfo.isFavorite = !this.notesInfo.isFavorite; + this.isFavorite = !this.isFavorite; + this.collectImgSrc = this.notesInfo.isFavorite ? + 'ic_bottom_star_selected.svg' : 'ic_bottom_star_normal.svg'; +} +... +// 点击插入图片 +this.clickAddPicture = () => { + this.imageSrc = this.chooseImage(); + if (this.imageSrc === '') { + prompt.showToast({ + message: 'Not anymore pictures' + }); + } else { + this.imageArr = this.notesInfo.imageArr; + this.imageArr.push(this.imageSrc); + this.isDataChanged = true; } - - async saveNoteIdArray() { - let preferences = await data_preferences.getPreferences(globalThis.context, - CommonConstants.PREFERENCE_INSTANCE_NAME); +} + +// ConfirmDialog.ets +if (this.type === CommonConstants.SAVE_DIALOG) { + this.confirm = async () => { + let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME); if (this.operationType === CommonConstants.ADD_NOTE) { - this.noteIdArray.push({ 'noteId': this.notesInfo.noteId }); - preferences.put('noteIdArr', JSON.stringify(this.noteIdArray)); + this.noteIdArray.push(new NoteIdBean(this.notesInfo.noteId)); + preferences.put(CommonConstants.PREFERENCE_NOTE_KEY, JSON.stringify(this.noteIdArray)); preferences.flush(); } - let newNotes = new NotesInfoBean(this.notesInfo); + // 保存备忘录数据实时更新 + let newNotes = this.notesInfo; await preferences.put(this.notesInfo.noteId, JSON.stringify(newNotes)); await preferences.flush(); router.replaceUrl({ url: 'pages/NoteHomePage' }); } - - onBackPress() { - if (this.isDataChanged || this.notesFolder !== this.notesInfo.folder || this.isCollectChange) { - this.saveDialogController.open(); - } else { - router.replaceUrl({ - url: 'pages/NoteHomePage' - }); - } - return true; - } } ``` @@ -429,69 +389,67 @@ struct NotesDetail { ![](figures/3.gif) -在NotesDetail.ets中添加删除逻辑,删除操作会调用preferences实例的delete方法,将对应noteId的备忘录数据从数据库中删除,最后执行实例的flush方法实现持久化。 +在BottomBar.ets中点击删除按钮,弹出自定义弹窗选择“是否删除”。在ConfirmDialog.ets中添加删除逻辑,删除操作会调用preferences实例的delete方法,将对应noteId的备忘录数据从数据库中删除,最后执行实例的flush方法实现持久化。 ```typescript -// NotesDetail.ets -@Entry -@Component -struct NotesDetail { +// BottomBar.ets +export default struct BottomBar { ... deleteDialogController: CustomDialogController = new CustomDialogController({ builder: ConfirmDialog({ - cancel: this.onCancel, - confirm: this.onAcceptDelete.bind(this), + notesInfo: $notesInfo, + operationType: $operationType, + noteIdArray: $noteIdArray, type: CommonConstants.DELETE_DIALOG }), autoCancel: true, alignment: DialogAlignment.Bottom, offset: { dx: $r('app.float.dialog_offset_x'), dy: $r('app.float.dialog_margin_bottom') } }); - + ... build() { + ... Column() { - Stack({ alignContent: Alignment.Bottom }) { - ... - BottomBar({ - ... - clickDelete: this.clickDelete.bind(this), - ... - }) - } + Image($r('app.media.ic_bottom_delete')) + .width($r('app.float.ic_bottom_picture_size')) + .aspectRatio(1) + Text($r('app.string.delete_note')) + .fontSize($r('app.float.font_size_smallest')) + .margin({ top: $r('app.float.bottom_txt_margin') }) } + .onClick(() => { + this.clickDelete = () => { + if (this.operationType === CommonConstants.MODIFY_NOTE) { + this.deleteDialogController.open(); + } else { + prompt.showToast({ + message: 'The addition operation cannot be deleted' + }); + } + } + this.clickDelete(); + }) ... } + ... +} - clickDelete() { - if (this.operationType === CommonConstants.MODIFY_NOTE) { - this.deleteDialogController.open(); - } else { - prompt.showToast({ - message: 'The addition operation cannot be deleted' - }); - } - } - - async deleteNoteIdArray() { - let preferences = await dataStorage.getPreferences(globalThis.context, - CommonConstants.PREFERENCE_INSTANCE_NAME); +// ConfirmDialog.ets +if (this.type === CommonConstants.SAVE_DIALOG) { + ... +} else { + // 删除备忘录数据 + this.confirm = async () => { + let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME); await preferences.delete(this.notesInfo.noteId); await preferences.flush(); router.replaceUrl({ - url: 'pages/NoteHomePage' - }); - } - - onCancel() { - router.replaceUrl({ - url: 'pages/NoteHomePage' + url: 'pages/NoteHomePage' }); } - - onAcceptDelete() { - this.deleteNoteIdArray(); - } } +this.confirm(); +}) ``` ## 总结 diff --git a/Data/NotePadOpenHarmony/entry/oh-package.json5 b/Data/NotePadOpenHarmony/entry/oh-package.json5 index 19b9234a98d43a4711a0fc32cef604159228d3cd..225946cb11a2c405c8dc81eea89c22f923556638 100644 --- a/Data/NotePadOpenHarmony/entry/oh-package.json5 +++ b/Data/NotePadOpenHarmony/entry/oh-package.json5 @@ -7,4 +7,4 @@ "main": "", "version": "1.0.0", "dependencies": {} -} \ No newline at end of file +} diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/common/bean/NoteInfoBean.ets b/Data/NotePadOpenHarmony/entry/src/main/ets/common/bean/NoteInfoBean.ets deleted file mode 100644 index 4a8eb307a03886e605bafb104c8b9b8569db6138..0000000000000000000000000000000000000000 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/common/bean/NoteInfoBean.ets +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License,Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Folder type enum. - */ -export enum FolderType { - All = 'all', - Work = 'work', - Personal = 'personal' -} - -/** - * NotesInfo item information. - */ -export class NotesInfoBean { - /** - * Note Id. - */ - noteId: string; - - /** - * Note title. - */ - title: string; - - /** - * Folder type. - */ - folder: FolderType; - - /** - * Create time. - */ - time: string; - - /** - * Collect note. - */ - isFavorite: boolean; - - /** - * Note images. - */ - imageArr: string[]; - - /** - * Note content. - */ - content: string; - - /** - * constructor. - */ - constructor(noteObject : NotesInfoBean) { - this.noteId = noteObject.noteId; - this.title = noteObject.title; - this.folder = noteObject.folder; - this.time = noteObject.time; - this.isFavorite = noteObject.isFavorite; - this.imageArr = noteObject.imageArr; - this.content = noteObject.content; - } -} \ No newline at end of file diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/common/utils/Logger.ets b/Data/NotePadOpenHarmony/entry/src/main/ets/common/utils/Logger.ets index d293ccdd3b7abaa791587f5462a5975111556679..ba84ed16fdd7010f9df9876216d05974a5d55132 100644 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/common/utils/Logger.ets +++ b/Data/NotePadOpenHarmony/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/entryability/EntryAbility.ts b/Data/NotePadOpenHarmony/entry/src/main/ets/entryability/EntryAbility.ts index 017d43b2b90980d2c8c2c17c2ff85a59db15adde..b650beca05252352b409063f05470d069efedc48 100644 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/entryability/EntryAbility.ts +++ b/Data/NotePadOpenHarmony/entry/src/main/ets/entryability/EntryAbility.ts @@ -20,7 +20,6 @@ import window from '@ohos.window'; export default class EntryAbility extends UIAbility { onCreate(want, launchParam) { hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); - globalThis.context = this.context; } onDestroy() { diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/model/NotesDataModel.ets b/Data/NotePadOpenHarmony/entry/src/main/ets/model/NotesDataModel.ets index da02e1a32f1e50a398dff2d4ddf987d02c889588..332a7e2743a8bfabeccf70291f8d56f2373c6068 100644 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/model/NotesDataModel.ets +++ b/Data/NotePadOpenHarmony/entry/src/main/ets/model/NotesDataModel.ets @@ -13,36 +13,38 @@ * limitations under the License. */ -import { noteIdArray, notesItemArr } from '../viewmodel/NotesInfoViewModel'; -import { FolderType, NotesInfoBean } from '../common/bean/NoteInfoBean'; +import common from '@ohos.app.ability.common'; import dataStorage from '@ohos.data.preferences'; +import { FolderType, noteIdArray, NotesInfoBean, notesItemArr } from '../viewmodel/NotesInfoViewModel'; import Logger from '../common/utils/Logger'; import CommonConstants from '../common/constants/CommonConstants'; class NotesDataModel { + private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; + /** * Put the data in preferences. */ async saveDefaultData() { try { - let preferences = await dataStorage.getPreferences(globalThis.context, CommonConstants.PREFERENCE_INSTANCE_NAME); + let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME); let isExist = await preferences.has(CommonConstants.PREFERENCE_NOTE_KEY); if (!isExist) { preferences.put(CommonConstants.PREFERENCE_NOTE_KEY, JSON.stringify(noteIdArray)); preferences.flush(); notesItemArr.forEach((item: NotesInfoBean) => { - let notes = new NotesInfoBean(item); + let notes: NotesInfoBean = item; let res = preferences.put(item.noteId, JSON.stringify(notes)); preferences.flush(); res.then(() => { Logger.info('Put the value successfully.' + item.noteId); - }).catch((err) => { - Logger.error('Put the value failed with err:', err); + }).catch((err: Error) => { + Logger.error(`Put the value failed with err: ${err}`); }) }) } } catch (err) { - Logger.error('Failed to get preferences. code = ', err.code + ', message =' + err.message); + Logger.error(`Failed to get preferences. Error = ${err}`); } } diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/pages/NoteHomePage.ets b/Data/NotePadOpenHarmony/entry/src/main/ets/pages/NoteHomePage.ets index c315ef39a0be72505b6065cf6dbae24f2a9b7fea..3962b80cd959885948bd49077aa7c66c6ef0571e 100644 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/pages/NoteHomePage.ets +++ b/Data/NotePadOpenHarmony/entry/src/main/ets/pages/NoteHomePage.ets @@ -13,13 +13,14 @@ * limitations under the License. */ +import common from '@ohos.app.ability.common'; import dataStorage from '@ohos.data.preferences'; -import { FolderType, NotesInfoBean } from '../common/bean/NoteInfoBean'; import StyleConstants from '../common/constants/StyleConstants'; import CommonConstants from '../common/constants/CommonConstants'; import MemoItem from '../view/MemoItem'; import NotesDataModel from '../model/NotesDataModel'; import Logger from '../common/utils/Logger'; +import { FolderType, NotesInfoBean } from '../viewmodel/NotesInfoViewModel'; @Entry @Component @@ -27,6 +28,8 @@ struct NoteHomePage { @State folderType: Resource = $r('app.string.notes_all'); @State allNotes: Array = []; @State selectNotes: Array = this.allNotes.sort(); + private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; + @Builder MyMenu(){ Menu() { MenuItem({ content: $r('app.string.notes_all') }) @@ -104,7 +107,7 @@ struct NoteHomePage { ListItem() { MemoItem({ noteItem: item }) } - }, item => JSON.stringify(item)) + }, (item: NotesInfoBean) => JSON.stringify(item)) } .margin({ top: $r('app.float.list_container_margin') }) .height(StyleConstants.NOTE_CONTENT_HEIGHT) @@ -121,15 +124,14 @@ struct NoteHomePage { async getAllNotes() { await NotesDataModel.saveDefaultData(); try { - let preferences = await dataStorage.getPreferences(globalThis.context, - CommonConstants.PREFERENCE_INSTANCE_NAME); + let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME); let noteIds = await preferences.get(CommonConstants.PREFERENCE_NOTE_KEY, ''); while (this.allNotes.length >= 1) { this.allNotes.pop(); } JSON.parse(noteIds.toString()).forEach(async (item: NotesInfoBean) => { let note = await preferences.get(item.noteId, ''); - this.allNotes.push(new NotesInfoBean(JSON.parse(note.toString()))); + this.allNotes.push(JSON.parse(note.toString())); }) } catch (err) { Logger.error('Get the value of noteIdArr failed with err:', err); diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/pages/NotesDetail.ets b/Data/NotePadOpenHarmony/entry/src/main/ets/pages/NotesDetail.ets index e5604c9fc49239af6af6a6d3e6a6b3bba5bbf918..581122d575202c8e47457d844add0f5dedba7cb2 100644 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/pages/NotesDetail.ets +++ b/Data/NotePadOpenHarmony/entry/src/main/ets/pages/NotesDetail.ets @@ -14,31 +14,24 @@ */ import router from '@ohos.router'; -import prompt from '@system.prompt'; -import dataStorage from '@ohos.data.preferences' import StyleConstants from '../common/constants/StyleConstants'; import CommonConstants from '../common/constants/CommonConstants'; import ConfirmDialog from '../view/ConfirmDialog'; -import { noteIdArray } from '../viewmodel/NotesInfoViewModel'; -import { FolderType, NotesInfoBean } from '../common/bean/NoteInfoBean'; -import { NoteIdBean } from '../common/bean/NoteIdBean'; +import { FolderType, noteIdArray, NoteIdBean, NotesInfoBean } from '../viewmodel/NotesInfoViewModel'; import formatTime from '../common/utils/Format'; import BottomBar from '../view/BottomBar'; @Entry @Component struct NotesDetail { - @State notesInfo: NotesInfoBean = router.getParams()['notesInfo']; - @State operationType: string = router.getParams()['operationType']; - @State imageSrc: string = ''; + @State notesInfo: NotesInfoBean = (router.getParams() as Record)['notesInfo']; + @State operationType: string = (router.getParams() as Record)['operationType']; @State imageArr: string[] = this.notesInfo.imageArr; @State noteIdArray: NoteIdBean[] = noteIdArray; - @State notesFolder: FolderType = this.notesInfo.folder; @State @Watch('onChangeCollect') isFavorite: boolean = this.notesInfo.isFavorite; - @State collectImgSrc: string = this.isFavorite ? 'ic_bottom_star_selected.svg' : 'ic_bottom_star_normal.svg'; + @State notesFolder: FolderType = this.notesInfo.folder; @State isDataChanged: boolean = false; @State isCollectChange: boolean = false; - @State imageUrls: string[] = ['cook_picture.png', 'dinner_food.png', 'drink_coffee.png']; @Builder MyMenu() { Menu() { @@ -55,24 +48,15 @@ struct NotesDetail { scroller: Scroller = new Scroller(); saveDialogController: CustomDialogController = new CustomDialogController({ builder: ConfirmDialog({ - cancel: this.onCancel, - confirm: this.onAcceptSave.bind(this), + notesInfo: $notesInfo, + operationType: $operationType, + noteIdArray: $noteIdArray, type: CommonConstants.SAVE_DIALOG }), autoCancel: true, alignment: DialogAlignment.Bottom, offset: { dx: $r('app.float.dialog_offset_x'), dy: $r('app.float.dialog_margin_bottom') } }); - deleteDialogController: CustomDialogController = new CustomDialogController({ - builder: ConfirmDialog({ - cancel: this.onCancel, - confirm: this.onAcceptDelete.bind(this), - type: CommonConstants.DELETE_DIALOG - }), - autoCancel: true, - alignment: DialogAlignment.Bottom, - offset: { dx: $r('app.float.dialog_offset_x'), dy: $r('app.float.dialog_margin_bottom') } - }); build() { Column() { @@ -165,7 +149,7 @@ struct NotesDetail { .width(StyleConstants.CONTENT_WIDTH) .objectFit(ImageFit.Fill) .margin({ top: $r('app.float.image_Space') }) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } } .scrollable(ScrollDirection.Vertical) @@ -176,10 +160,12 @@ struct NotesDetail { .margin({ bottom: $r('app.float.top_bar_container_height') }) BottomBar({ - collectImgSrc: this.collectImgSrc, - clickCollect: this.clickCollect.bind(this), - clickDelete: this.clickDelete.bind(this), - clickAddPicture: this.clickAddPicture.bind(this) + imageArr: $imageArr, + notesInfo: $notesInfo, + operationType: $operationType, + noteIdArray: $noteIdArray, + isDataChanged: $isDataChanged, + isFavorite: $isFavorite }) } .width(StyleConstants.FULL_WIDTH) @@ -191,96 +177,14 @@ struct NotesDetail { .backgroundColor($r('app.color.white_color')) } - async saveNoteIdArray() { - let preferences = await dataStorage.getPreferences(globalThis.context, - CommonConstants.PREFERENCE_INSTANCE_NAME); - if (this.operationType === CommonConstants.ADD_NOTE) { - this.noteIdArray.push({ 'noteId': this.notesInfo.noteId }); - preferences.put(CommonConstants.PREFERENCE_NOTE_KEY, JSON.stringify(this.noteIdArray)); - preferences.flush(); - } - let newNotes = new NotesInfoBean(this.notesInfo); - await preferences.put(this.notesInfo.noteId, JSON.stringify(newNotes)); - await preferences.flush(); - router.replaceUrl({ - url: 'pages/NoteHomePage' - }); - } - - async deleteNoteIdArray() { - let preferences = await dataStorage.getPreferences(globalThis.context, - CommonConstants.PREFERENCE_INSTANCE_NAME); - await preferences.delete(this.notesInfo.noteId); - await preferences.flush(); - router.replaceUrl({ - url: 'pages/NoteHomePage' - }); - } - onPageShow() { this.notesInfo.time = formatTime(); } - clickCollect() { - this.notesInfo.isFavorite = !this.notesInfo.isFavorite; - this.isFavorite = !this.isFavorite; - this.collectImgSrc = this.notesInfo.isFavorite ? - 'ic_bottom_star_selected.svg' : 'ic_bottom_star_normal.svg'; - } - - clickDelete() { - if (this.operationType === CommonConstants.MODIFY_NOTE) { - this.deleteDialogController.open(); - } else { - prompt.showToast({ - message: 'The addition operation cannot be deleted' - }); - } - } - - clickAddPicture() { - this.imageSrc = this.chooseImage(); - if (this.imageSrc === '') { - prompt.showToast({ - message: 'Not anymore pictures' - }); - } else { - this.imageArr = this.notesInfo.imageArr; - this.imageArr.push(this.imageSrc); - this.isDataChanged = true; - } - } - onChangeCollect() { this.isCollectChange = !this.isCollectChange; } - onCancel() { - router.replaceUrl({ - url: 'pages/NoteHomePage' - }); - } - - onAcceptSave() { - this.saveNoteIdArray(); - } - - onAcceptDelete() { - this.deleteNoteIdArray(); - } - - chooseImage() { - for (let i = 0;i < this.imageUrls.length; i++) { - if (this.imageArr.length === 0) { - return this.imageUrls[i]; - } - if (!this.imageArr.includes(this.imageUrls[i])) { - return this.imageUrls[i]; - } - } - return ''; - } - onBackPress() { if (this.isDataChanged || this.notesFolder !== this.notesInfo.folder || this.isCollectChange) { this.saveDialogController.open(); diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/view/BottomBar.ets b/Data/NotePadOpenHarmony/entry/src/main/ets/view/BottomBar.ets index c7ce424b99ad46ee0effac0b061a717431b56f0b..d07670cce624a395ff02ae78d72e6dff8c8e3b95 100644 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/view/BottomBar.ets +++ b/Data/NotePadOpenHarmony/entry/src/main/ets/view/BottomBar.ets @@ -14,17 +14,39 @@ */ import prompt from '@system.prompt'; +import CommonConstants from '../common/constants/CommonConstants'; import StyleConstants from '../common/constants/StyleConstants'; -import { notesItemArr } from '../viewmodel/NotesInfoViewModel'; -import { NotesInfoBean } from '../common/bean/NoteInfoBean'; +import { NoteIdBean, NotesInfoBean, notesItemArr } from '../viewmodel/NotesInfoViewModel'; +import ConfirmDialog from './ConfirmDialog'; @Component export default struct BottomBar { - @Prop collectImgSrc: string; + @Link notesInfo: NotesInfoBean; + @Link operationType: string; + @Link noteIdArray: NoteIdBean[]; + @Link imageArr: string[]; + @Link isDataChanged: boolean; + @Link isFavorite: boolean; + @State isCollectChange: boolean = false; + @State collectImgSrc: string = this.isFavorite ? 'ic_bottom_star_selected.svg' : 'ic_bottom_star_normal.svg'; + @State imageUrls: string[] = ['cook_picture.png', 'dinner_food.png', 'drink_coffee.png']; @State noteItem: NotesInfoBean = notesItemArr[0]; - clickCollect: () => void; - clickDelete: () => void; - clickAddPicture: () => void; + @State imageSrc: string = ''; + + clickCollect?: () => void; + clickDelete?: () => void; + clickAddPicture?: () => void; + deleteDialogController: CustomDialogController = new CustomDialogController({ + builder: ConfirmDialog({ + notesInfo: $notesInfo, + operationType: $operationType, + noteIdArray: $noteIdArray, + type: CommonConstants.DELETE_DIALOG + }), + autoCancel: true, + alignment: DialogAlignment.Bottom, + offset: { dx: $r('app.float.dialog_offset_x'), dy: $r('app.float.dialog_margin_bottom') } + }); build() { Row() { @@ -50,6 +72,12 @@ export default struct BottomBar { .margin({ top: $r('app.float.bottom_txt_margin') }) } .onClick(() => { + this.clickCollect = () => { + this.notesInfo.isFavorite = !this.notesInfo.isFavorite; + this.isFavorite = !this.isFavorite; + this.collectImgSrc = this.notesInfo.isFavorite ? + 'ic_bottom_star_selected.svg' : 'ic_bottom_star_normal.svg'; + } this.clickCollect(); }) Column() { @@ -61,6 +89,15 @@ export default struct BottomBar { .margin({ top: $r('app.float.bottom_txt_margin') }) } .onClick(() => { + this.clickDelete = () => { + if (this.operationType === CommonConstants.MODIFY_NOTE) { + this.deleteDialogController.open(); + } else { + prompt.showToast({ + message: 'The addition operation cannot be deleted' + }); + } + } this.clickDelete(); }) Column() { @@ -72,6 +109,18 @@ export default struct BottomBar { .margin({ top: $r('app.float.bottom_txt_margin') }) } .onClick(() => { + this.clickAddPicture = () => { + this.imageSrc = this.chooseImage(); + if (this.imageSrc === '') { + prompt.showToast({ + message: 'Not anymore pictures' + }); + } else { + this.imageArr = this.notesInfo.imageArr; + this.imageArr.push(this.imageSrc); + this.isDataChanged = true; + } + } this.clickAddPicture(); }) } @@ -81,4 +130,16 @@ export default struct BottomBar { .alignItems(VerticalAlign.Center) .backgroundColor($r('app.color.white_color')) } + + chooseImage() { + for (let i = 0;i < this.imageUrls.length; i++) { + if (this.imageArr.length === 0) { + return this.imageUrls[i]; + } + if (!this.imageArr.includes(this.imageUrls[i])) { + return this.imageUrls[i]; + } + } + return ''; + } } \ No newline at end of file diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/view/ConfirmDialog.ets b/Data/NotePadOpenHarmony/entry/src/main/ets/view/ConfirmDialog.ets index 06fa9d1a8dffa3b18010d87a04df25975f192397..35986a25262007605ea0463aa18e71398092b6d9 100644 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/view/ConfirmDialog.ets +++ b/Data/NotePadOpenHarmony/entry/src/main/ets/view/ConfirmDialog.ets @@ -13,27 +13,42 @@ * limitations under the License. */ +import router from '@ohos.router'; +import common from '@ohos.app.ability.common'; +import dataStorage from '@ohos.data.preferences'; import StyleConstants from '../common/constants/StyleConstants'; import CommonConstants from '../common/constants/CommonConstants'; +import { NoteIdBean, NotesInfoBean } from '../viewmodel/NotesInfoViewModel'; @CustomDialog export default struct ConfirmDialog { - controller: CustomDialogController; - cancel: () => void; - confirm: () => void; - type: string; + @Link noteIdArray: NoteIdBean[]; + @Link notesInfo: NotesInfoBean; + @Link operationType: string; + controller?: CustomDialogController; + cancel?: () => void; + confirm?: () => void; + type: string = ''; + private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; build() { Column() { - Text(this.type === CommonConstants.SAVE_DIALOG ? - $r('app.string.save_update'):$r('app.string.delete_update')) + Text(this.type === CommonConstants.SAVE_DIALOG ? $r('app.string.save_update'):$r('app.string.delete_update')) .fontSize($r('app.float.font_size_normal')) .height($r('app.float.dialog_title_height')) .margin({ top: $r('app.float.dialog_title_margin_top'), bottom: $r('app.float.dialog_title_margin_bottom') }) Row() { Text($r('app.string.cancel_txt')) .onClick(() => { + if (this.controller === undefined) { + return; + } this.controller.close(); + this.cancel = () => { + router.replaceUrl({ + url: 'pages/NoteHomePage' + }); + } this.cancel(); }) .width($r('app.float.dialog_button_width')) @@ -44,8 +59,36 @@ export default struct ConfirmDialog { Text(this.type === CommonConstants.SAVE_DIALOG ? $r('app.string.confirm_txt') : $r('app.string.delete_txt')) .width($r('app.float.dialog_button_width')) - .onClick(() => { + .onClick(async () => { + if (this.controller === undefined) { + return; + } this.controller.close(); + if (this.type === CommonConstants.SAVE_DIALOG) { + this.confirm = async () => { + let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME); + if (this.operationType === CommonConstants.ADD_NOTE) { + this.noteIdArray.push(new NoteIdBean(this.notesInfo.noteId)); + preferences.put(CommonConstants.PREFERENCE_NOTE_KEY, JSON.stringify(this.noteIdArray)); + preferences.flush(); + } + let newNotes = this.notesInfo; + await preferences.put(this.notesInfo.noteId, JSON.stringify(newNotes)); + await preferences.flush(); + router.replaceUrl({ + url: 'pages/NoteHomePage' + }); + } + } else { + this.confirm = async () => { + let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME); + await preferences.delete(this.notesInfo.noteId); + await preferences.flush(); + router.replaceUrl({ + url: 'pages/NoteHomePage' + }); + } + } this.confirm(); }) .textAlign(TextAlign.Center) @@ -58,4 +101,13 @@ export default struct ConfirmDialog { .width(StyleConstants.DIALOG_CONTENT_WIDTH) .height($r('app.float.dialog_height')) } + + async deleteNoteIdArray(): Promise { + let preferences = await dataStorage.getPreferences(this.context, CommonConstants.PREFERENCE_INSTANCE_NAME); + await preferences.delete(this.notesInfo.noteId); + await preferences.flush(); + router.replaceUrl({ + url: 'pages/NoteHomePage' + }); + } } \ No newline at end of file diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/view/MemoItem.ets b/Data/NotePadOpenHarmony/entry/src/main/ets/view/MemoItem.ets index cc1edc28f1d16f9742e4ce507c69a3e29bc0b565..e3ecebdbaf9928885e0416a2bc5cc45824bdafb1 100644 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/view/MemoItem.ets +++ b/Data/NotePadOpenHarmony/entry/src/main/ets/view/MemoItem.ets @@ -15,8 +15,7 @@ import StyleConstants from '../common/constants/StyleConstants'; import CommonConstants from '../common/constants/CommonConstants'; -import { notesItemArr } from '../viewmodel/NotesInfoViewModel'; -import { FolderType, NotesInfoBean } from '../common/bean/NoteInfoBean'; +import { FolderType, NotesInfoBean, notesItemArr } from '../viewmodel/NotesInfoViewModel'; @Component export default struct MemoItem { diff --git a/Data/NotePadOpenHarmony/entry/src/main/ets/viewmodel/NotesInfoViewModel.ets b/Data/NotePadOpenHarmony/entry/src/main/ets/viewmodel/NotesInfoViewModel.ets index 71040fa0cc3b23d23fcd7e9dcb44faff8245544f..8442f489bc5093d80792acbae9d3e93f8fc9d92d 100644 --- a/Data/NotePadOpenHarmony/entry/src/main/ets/viewmodel/NotesInfoViewModel.ets +++ b/Data/NotePadOpenHarmony/entry/src/main/ets/viewmodel/NotesInfoViewModel.ets @@ -13,71 +13,89 @@ * limitations under the License. */ -import { FolderType, NotesInfoBean } from '../common/bean/NoteInfoBean'; -import { NoteIdBean } from '../common/bean/NoteIdBean'; +export class NoteIdBean { + noteId: string; -export const notesItemArr: NotesInfoBean[] = [ - { - 'noteId': '1646121972443', - 'title': '早晨锻炼身体', - 'folder': FolderType.Personal, - 'content': 'Long run 3 km', - 'imageArr': ['cook_picture.png'], - 'time': '7:30:58', - 'isFavorite': true - }, - { - 'noteId': '1646121972444', - 'title': 'Breakfast', - 'folder': FolderType.Personal, - 'content': 'Milk and bread', - 'imageArr': ['dinner_food.png'], - 'time': '8:00:12', - 'isFavorite': false - }, - { - 'noteId': '1646121972445', - 'title': 'Go to work', - 'folder': FolderType.Work, - 'content': 'Take the 11th bus', - 'imageArr': ['drink_coffee.png'], - 'time': '8:30:36', - 'isFavorite': false - }, - { - 'noteId': '1646121972446', - 'title': 'Lunches', - 'folder': FolderType.Personal, - 'content': 'Sweet and sour ribs potato shreds', - 'imageArr': ['cook_picture.png'], - 'time': '12:20:45', - 'isFavorite': true - }, - { - 'noteId': '1646121972447', - 'title': 'Computer Lessons', - 'folder': FolderType.Work, - 'content': 'Learning HarmonyOS', - 'imageArr': ['dinner_food.png'], - 'time': '3:30:06', - 'isFavorite': true + constructor(noteId: string) { + this.noteId = noteId; } -]; +} + +/** + * Folder type enum. + */ +export enum FolderType { + All = 'all', + Work = 'work', + Personal = 'personal' +} + +/** + * NotesInfo item information. + */ +export class NotesInfoBean { + /** + * Note Id. + */ + noteId: string; + + /** + * Note title. + */ + title: string; + + /** + * Folder type. + */ + folder: FolderType; -export const noteIdArray: NoteIdBean[] = [ - { - 'noteId': '1646121972443' - }, - { - 'noteId': '1646121972444' - }, - { - 'noteId': '1646121972445' - }, - { - 'noteId': '1646121972446' - }, - { - 'noteId': '1646121972447' + /** + * Create time. + */ + time: string; + + /** + * Collect note. + */ + isFavorite: boolean; + + /** + * Note images. + */ + imageArr: string[]; + + /** + * Note content. + */ + content: string; + + /** + * constructor. + */ + constructor(noteId: string, title: string, folder: FolderType, time: string, isFavorite: boolean, imageArr: string[], + content: string) { + this.noteId = noteId; + this.title = title; + this.folder = folder; + this.time = time; + this.isFavorite = isFavorite; + this.imageArr = imageArr; + this.content = content; } -] \ No newline at end of file +} + +export const notesItemArr: NotesInfoBean[] = [ + new NotesInfoBean('1646121972443', '早晨锻炼身体', FolderType.Personal, '7:30:58', true, ['cook_picture.png'], + 'Long run 3 km'), + new NotesInfoBean('1646121972444', 'Breakfast', FolderType.Personal, '8:00:12', false, ['dinner_food.png'], + 'Milk and bread'), + new NotesInfoBean('1646121972445', 'Go to work', FolderType.Work, '8:30:36', false, ['drink_coffee.png'], + 'Take the 11th bus'), + new NotesInfoBean('1646121972446', 'Lunches', FolderType.Personal, '12:20:45', true, ['cook_picture.png'], + 'Sweet and sour ribs potato shreds'), + new NotesInfoBean('1646121972447', 'Computer Lessons', FolderType.Work, '3:30:06', true, ['dinner_food.png'], + 'Learning HarmonyOS') +]; + +export const noteIdArray: NoteIdBean[] = [new NoteIdBean('1646121972443'), new NoteIdBean('1646121972444'), + new NoteIdBean('1646121972445'), new NoteIdBean('1646121972446'), new NoteIdBean('1646121972447')]; \ No newline at end of file diff --git a/Data/NotePadOpenHarmony/hvigor/hvigor-config.json5 b/Data/NotePadOpenHarmony/hvigor/hvigor-config.json5 index dd6d7a66b580d1a50c108144878558f98ae6837f..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/Data/NotePadOpenHarmony/hvigor/hvigor-config.json5 +++ b/Data/NotePadOpenHarmony/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.1.1", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.1.1" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/Data/Preferences/README.md b/Data/Preferences/README.md index 393cde5b9c10066d706ab4986d34ca9d3061d39f..d9e0132de6d85ba0ec8542b644d8af710ab9be19 100644 --- a/Data/Preferences/README.md +++ b/Data/Preferences/README.md @@ -2,13 +2,15 @@ ## 介绍 -本篇Codelab是基于OpenHarmony的首选项能力实现的一个简单示例。实现如下功能: +本篇Codelab是基于HarmonyOS的首选项能力实现的一个简单示例。实现如下功能: 1. 创建首选项数据文件。 2. 将用户输入的水果名称和数量,写入到首选项数据库。 3. 读取首选项数据库中的数据。 4. 删除首选项数据文件。 +最终效果图如下: + ![](figures/zh-cn_image_0000001459130725.gif) ### 相关概念 @@ -21,13 +23,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -50,14 +52,11 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──ButtonItemData.ets // 按钮数据实体类 -│ │ │ └──Fruit.ets // 水果实体类 │ │ ├──constants │ │ │ ├──CommonConstants.ets // 公共常量类 │ │ │ └──StyleConstants.ets // 样式常量类 @@ -69,9 +68,12 @@ │ │ └──PreferenceModel.ets // 首选项相关方法类 │ ├──pages │ │ └──Index.ets // 主界面 -│ └──view -│ ├──ButtonComponent.ets // 自定义Button组件类 -│ └──TextItemComponent.ets // 自定义Text组件类 +│ ├──view +│ │ ├──ButtonComponent.ets // 自定义Button组件类 +│ │ └──TextItemComponent.ets // 自定义Text组件类 +│ └──viewmodel +│ ├──ButtonItemData.ets // 按钮数据类 +│ └──Fruit.ets // 水果数据类 └──entry/src/main/resources // 资源文件目录 ``` @@ -94,16 +96,17 @@ 具体代码如下: ```typescript + // TextItemComponent.ets @Component export default struct TextItemComponent { - private textResource: Resource; // 按钮文本资源 - private placeholderResource: Resource; // placeholder文本资源 - private marginBottom: string; - private marginTop: string; - private textInputType: InputType; // 输入框输入数据类型 - private textFlag: number; // 文本框标记 + private textResource: Resource = $r('app.string.empty'); // 按钮文本资源 + private placeholderResource: Resource = $r('app.string.empty'); // placeholder文本资源 + private marginBottom: string = ''; + private marginTop: string = ''; + private textInputType: InputType = InputType.Normal; // 输入框输入数据类型 + private textFlag: number = 0; // 文本框标记 @Link fruit: Fruit; // 水果数据 - private textInputCallBack: (value: string) => void; // TextInput的回调 + private textInputCallBack = (value: string) => {}; // TextInput的回调 build() { Column() { @@ -150,6 +153,7 @@ 具体代码如下: ```typescript + // ButtonComponent.ets @Component export default struct ButtonComponent { private buttonItemValues: Array = this.getButtonItemValues(); @@ -157,7 +161,7 @@ build() { Column() { - ForEach(this.buttonItemValues, (item) => { + ForEach(this.buttonItemValues, (item: ButtonItemData) => { Button(item.resource, { type: ButtonType.Capsule, stateEffect: true }) .backgroundColor($r('app.color.button_background_color')) .width(StyleConstants.BUTTON_WIDTH) @@ -168,7 +172,7 @@ .onClick(() => { item.clickMethod(); }) - }, item => item.toString()) + }, (item: ButtonItemData) => JSON.stringify(item)) } } } @@ -177,6 +181,7 @@ 4. 在Index.ets主界面中引用TextItemComponent和ButtonComponent子组件,具体代码如下: ```typescript + // Index.ets Column() { // 水果名称输入框 TextItemComponent({ @@ -184,7 +189,7 @@ placeholderResource: $r('app.string.fruit_placeholder'), textFlag: CommonConstants.FRUIT_FLAG, fruit: $fruit, - textInputCallBack: (value) => { + textInputCallBack: (value: string) => { this.fruit.fruitName = value; } }) @@ -195,7 +200,7 @@ placeholderResource: $r('app.string.number_placeholder'), textFlag: CommonConstants.NUMBER_FLAG, fruit: $fruit, - textInputCallBack: (value) => { + textInputCallBack: (value: string) => { this.fruit.fruitNum = value; } }) @@ -218,11 +223,13 @@ Preferences的数据存储在文件中,因此需要指定存储的文件名PREFERENCES\_NAME。再通过Preferences提供的方法进行数据库的相关操作。具体代码如下: ```typescript +// PreferenceModel.ets // 导入dataPreferences模块 import dataPreferences from '@ohos.data.preferences'; let context = getContext(this); -let preference: dataPreferences.Preferences = null; +let preference: dataPreferences.Preferences; +let preferenceTemp: dataPreferences.Preferences; // 调用getPreferences方法读取指定首选项持久化文件,将数据加载到Preferences实例,用于数据操作 async getPreferencesFromStorage() { @@ -239,6 +246,7 @@ async getPreferencesFromStorage() { 获取Preferences实例后,使用Preferences的put方法,将用户输入的水果名称和水果数量数据,保存到缓存的实例中。再通过Preferences的flush方法将Preferences实例异步存储到首选项持久化文件中。具体代码如下: ```typescript +// PreferenceModel.ets async putPreference(fruit: Fruit) { ... try { @@ -257,11 +265,12 @@ async putPreference(fruit: Fruit) { 使用Preferences的get方法读取数据。如果键不存在,则返回默认值。例如获取下面代码中fruit的值,如果fruit的键KEY\_NAME不存在,则会返回空字符串。通过默认值的设置,来避免程序出现异常。具体代码如下: ```typescript +// PreferenceModel.ets async getPreference() { let fruit = ''; ... try { - fruit = await preference.get(CommonConstants.KEY_NAME, ''); + fruit = (await preference.get(CommonConstants.KEY_NAME, '')).toString(); } catch (err) { Logger.error(CommonConstants.TAG, `Failed to get value, Cause: ${err}`); } @@ -274,6 +283,7 @@ async getPreference() { 通过dataPreferences模块的deletePreferences\(context, name\)方法从内存中移除指定文件对应的Preferences单实例。移除Preferences单实例时,应用不允许再使用该实例进行数据操作,否则会出现数据一致性问题。具体代码如下: ```typescript +// PreferenceModel.ets async deletePreferences() { try { await dataPreferences.deletePreferences(context, CommonConstants.PREFERENCES_NAME); diff --git a/Data/Preferences/entry/src/main/ets/common/constants/StyleConstants.ets b/Data/Preferences/entry/src/main/ets/common/constants/StyleConstants.ets index 3825bba5ef18d64665817cf4c6abed37956fab71..65111e8c3514c07d66037195312e92c640567f4d 100644 --- a/Data/Preferences/entry/src/main/ets/common/constants/StyleConstants.ets +++ b/Data/Preferences/entry/src/main/ets/common/constants/StyleConstants.ets @@ -80,7 +80,7 @@ class StyleConstants { /** * Big margin bottom */ - MARGIN_BOTTOM_BIG = '321vp'; + MARGIN_BOTTOM_BIG = '340vp'; /** * The height of button component. diff --git a/Data/Preferences/entry/src/main/ets/common/utils/Logger.ets b/Data/Preferences/entry/src/main/ets/common/utils/Logger.ets index d0ffebf5f034e126edb7f12d70e41bc9ee8dc1e4..46a59671599801ad1d1b99ec86c524ce1a99bb15 100644 --- a/Data/Preferences/entry/src/main/ets/common/utils/Logger.ets +++ b/Data/Preferences/entry/src/main/ets/common/utils/Logger.ets @@ -35,7 +35,7 @@ class Logger { * * @param args Indicates the log parameters. */ - debug(...args: any[]) { + debug(...args: string[]) { hilog.debug(this.domain, this.prefix, this.format, args); } @@ -44,7 +44,7 @@ class Logger { * * @param args Indicates the log parameters. */ - info(...args: any[]) { + info(...args: string[]) { hilog.info(this.domain, this.prefix, this.format, args); } @@ -53,7 +53,7 @@ class Logger { * * @param args Indicates the log parameters. */ - warn(...args: any[]) { + warn(...args: string[]) { hilog.warn(this.domain, this.prefix, this.format, args); } @@ -62,7 +62,7 @@ class Logger { * * @param args Indicates the log parameters. */ - error(...args: any[]) { + error(...args: string[]) { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Data/Preferences/entry/src/main/ets/model/PreferenceModel.ets b/Data/Preferences/entry/src/main/ets/model/PreferenceModel.ets index 46fa1da6a2bafedc19044180430f68ea34ae21e3..9ef93f6c2518847be2dfc2efa61176278af76a90 100644 --- a/Data/Preferences/entry/src/main/ets/model/PreferenceModel.ets +++ b/Data/Preferences/entry/src/main/ets/model/PreferenceModel.ets @@ -17,10 +17,11 @@ import dataPreferences from '@ohos.data.preferences'; import promptAction from '@ohos.promptAction'; import Logger from '../common/utils/Logger'; import CommonConstants from '../common/constants/CommonConstants'; -import Fruit from '../common/bean/Fruit'; +import Fruit from '../viewmodel/Fruit'; let context = getContext(this); -let preference: dataPreferences.Preferences = null; +let preference: dataPreferences.Preferences; +let preferenceTemp: dataPreferences.Preferences; /** * Preference model. @@ -28,7 +29,7 @@ let preference: dataPreferences.Preferences = null; * @param fruitData Fruit data. */ class PreferenceModel { - private fruitData: Fruit; + private fruitData: Fruit = new Fruit(); /** * Read the specified Preferences persistence file and load the data into the Preferences instance. @@ -50,7 +51,7 @@ class PreferenceModel { } catch(err) { Logger.error(CommonConstants.TAG, `Failed to delete preferences, Cause: ${err}`); }; - preference = null; + preference = preferenceTemp; this.showToastMessage($r('app.string.delete_success_msg')); } @@ -60,7 +61,7 @@ class PreferenceModel { * @param fruit Fruit data. */ async putPreference(fruit: Fruit) { - if (preference === null) { + if (!preference) { await this.getPreferencesFromStorage(); } // The fruit name and fruit quantity data entered by the user are saved to the cached Preference instance. @@ -78,11 +79,11 @@ class PreferenceModel { */ async getPreference() { let fruit = ''; - if (preference === null) { + if (!preference) { await this.getPreferencesFromStorage(); } try { - fruit = await preference.get(CommonConstants.KEY_NAME, ''); + fruit = (await preference.get(CommonConstants.KEY_NAME, '')).toString(); } catch (err) { Logger.error(CommonConstants.TAG, `Failed to get value, Cause: ${err}`); } diff --git a/Data/Preferences/entry/src/main/ets/pages/Index.ets b/Data/Preferences/entry/src/main/ets/pages/Index.ets index caf2d9700006d45e870b70393e2087d9e436a9e5..ccde7f6c10ee3b170c9ef98b8b34f2e2a106d211 100644 --- a/Data/Preferences/entry/src/main/ets/pages/Index.ets +++ b/Data/Preferences/entry/src/main/ets/pages/Index.ets @@ -16,7 +16,7 @@ import PreferenceModel from '../model/PreferenceModel'; import ButtonComponent from '../view/ButtonComponent'; import TextItemComponent from '../view/TextItemComponent'; -import Fruit from '../common/bean/Fruit'; +import Fruit from '../viewmodel/Fruit'; import CommonConstants from '../common/constants/CommonConstants'; import StyleConstants from '../common/constants/StyleConstants'; @@ -26,7 +26,7 @@ import StyleConstants from '../common/constants/StyleConstants'; @Entry @Component struct Index { - @State fruit: Fruit = new Fruit('', ''); + @State fruit: Fruit = new Fruit(); build() { Column() { @@ -36,7 +36,7 @@ struct Index { placeholderResource: $r('app.string.fruit_placeholder'), textFlag: CommonConstants.FRUIT_FLAG, fruit: $fruit, - textInputCallBack: (value) => { + textInputCallBack: (value: string) => { this.fruit.fruitName = value; } }) @@ -47,7 +47,7 @@ struct Index { placeholderResource: $r('app.string.number_placeholder'), textFlag: CommonConstants.NUMBER_FLAG, fruit: $fruit, - textInputCallBack: (value) => { + textInputCallBack: (value: string) => { this.fruit.fruitNum = value; } }) @@ -64,8 +64,10 @@ struct Index { // Get the lightweight storage db file from memory. await PreferenceModel.getPreferencesFromStorage(); // Get the key value with the key name fruit from the lightweight storage db file. - PreferenceModel.getFruitData().then(resultData => { - this.fruit = resultData; + PreferenceModel.getFruitData().then((resultData: Fruit) => { + if (resultData) { + this.fruit = resultData; + } }); } } \ No newline at end of file diff --git a/Data/Preferences/entry/src/main/ets/view/ButtonComponent.ets b/Data/Preferences/entry/src/main/ets/view/ButtonComponent.ets index 4b56ff145e0b5d03226f3b46d8354a32691a7155..8020479a30eae8a056287c410938d38889c2b2f0 100644 --- a/Data/Preferences/entry/src/main/ets/view/ButtonComponent.ets +++ b/Data/Preferences/entry/src/main/ets/view/ButtonComponent.ets @@ -14,8 +14,8 @@ */ import PreferenceModel from '../model/PreferenceModel'; -import ButtonItemData from '../common/bean/ButtonItemData'; -import Fruit from '../common/bean/Fruit'; +import ButtonItemData from '../viewmodel/ButtonItemData'; +import Fruit from '../viewmodel/Fruit'; import StyleConstants from '../common/constants/StyleConstants'; /** @@ -28,7 +28,7 @@ export default struct ButtonComponent { build() { Column() { - ForEach(this.buttonItemValues, (item) => { + ForEach(this.buttonItemValues, (item: ButtonItemData) => { Button(item.resource, { type: ButtonType.Capsule, stateEffect: true }) .backgroundColor($r('app.color.button_background_color')) .width(StyleConstants.BUTTON_WIDTH) @@ -39,7 +39,7 @@ export default struct ButtonComponent { .onClick(() => { item.clickMethod(); }) - }, item => JSON.stringify(item)) + }, (item: ButtonItemData) => JSON.stringify(item)) } } @@ -59,8 +59,10 @@ export default struct ButtonComponent { $r('app.string.read_data_btn_text'), () => { // Get data from the preferences database. - PreferenceModel.getFruitData().then(resultData => { - this.fruit = resultData; + PreferenceModel.getFruitData().then((resultData: Fruit) => { + if (resultData) { + this.fruit = resultData; + } }); } ), diff --git a/Data/Preferences/entry/src/main/ets/view/TextItemComponent.ets b/Data/Preferences/entry/src/main/ets/view/TextItemComponent.ets index 1c7745c1c06c78f0051b8275c7cf0f5c44284a01..d767b4ae9af08c3907851a44b7dccc1939a69a55 100644 --- a/Data/Preferences/entry/src/main/ets/view/TextItemComponent.ets +++ b/Data/Preferences/entry/src/main/ets/view/TextItemComponent.ets @@ -15,21 +15,21 @@ import StyleConstants from '../common/constants/StyleConstants'; import CommonConstants from '../common/constants/CommonConstants'; -import Fruit from '../common/bean/Fruit'; +import Fruit from '../viewmodel/Fruit'; /** * Text item component. */ @Component export default struct TextItemComponent { - private textResource: Resource; - private placeholderResource: Resource; - private marginBottom: string; - private marginTop: string; - private textInputType: InputType; - private textFlag: number; + private textResource: Resource = $r('app.string.empty'); + private placeholderResource: Resource = $r('app.string.empty'); + private marginBottom: string = ''; + private marginTop: string = ''; + private textInputType: InputType = InputType.Normal; + private textFlag: number = 0; @Link fruit: Fruit; - private textInputCallBack: (value: string) => void; + private textInputCallBack = (value: string) => {}; aboutToAppear() { if (this.textFlag === CommonConstants.FRUIT_FLAG) { diff --git a/Data/Preferences/entry/src/main/ets/common/bean/ButtonItemData.ets b/Data/Preferences/entry/src/main/ets/viewmodel/ButtonItemData.ets similarity index 100% rename from Data/Preferences/entry/src/main/ets/common/bean/ButtonItemData.ets rename to Data/Preferences/entry/src/main/ets/viewmodel/ButtonItemData.ets diff --git a/Data/Preferences/entry/src/main/ets/common/bean/Fruit.ets b/Data/Preferences/entry/src/main/ets/viewmodel/Fruit.ets similarity index 72% rename from Data/Preferences/entry/src/main/ets/common/bean/Fruit.ets rename to Data/Preferences/entry/src/main/ets/viewmodel/Fruit.ets index 4d97e16a55f74ecd49f4a946539a4bfbf45953b8..2b139d73d36c786b616ae80a34e87120868d29c3 100644 --- a/Data/Preferences/entry/src/main/ets/common/bean/Fruit.ets +++ b/Data/Preferences/entry/src/main/ets/viewmodel/Fruit.ets @@ -23,21 +23,10 @@ export default class Fruit { /** * Fruit name. */ - fruitName: string; + fruitName: string = ''; /** * Fruit num. */ - fruitNum: string; - - /** - * The constructor of Fruit. - * - * @param fruitName Fruit name. - * @param fruitNum Fruit num. - */ - constructor(fruitName: string, fruitNum: string) { - this.fruitName = fruitName; - this.fruitNum = fruitNum; - } + fruitNum: string = ''; } diff --git a/Data/Preferences/entry/src/main/resources/base/element/string.json b/Data/Preferences/entry/src/main/resources/base/element/string.json index e77eb137fde4a271b7add23065bab9f5e2f9e307..18240cee296d39502091b0e7d0e055eaf48b1bdf 100644 --- a/Data/Preferences/entry/src/main/resources/base/element/string.json +++ b/Data/Preferences/entry/src/main/resources/base/element/string.json @@ -59,6 +59,10 @@ { "name": "write_success_msg", "value": "Write data successfully!" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/Data/Preferences/entry/src/main/resources/en_US/element/string.json b/Data/Preferences/entry/src/main/resources/en_US/element/string.json index e77eb137fde4a271b7add23065bab9f5e2f9e307..18240cee296d39502091b0e7d0e055eaf48b1bdf 100644 --- a/Data/Preferences/entry/src/main/resources/en_US/element/string.json +++ b/Data/Preferences/entry/src/main/resources/en_US/element/string.json @@ -59,6 +59,10 @@ { "name": "write_success_msg", "value": "Write data successfully!" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/Data/Preferences/entry/src/main/resources/zh_CN/element/string.json b/Data/Preferences/entry/src/main/resources/zh_CN/element/string.json index fd5e4ed96e72a662fb4c2a1b8685c275b115e6fd..7eda63cd2f94182185d0f14404f906c7026c2862 100644 --- a/Data/Preferences/entry/src/main/resources/zh_CN/element/string.json +++ b/Data/Preferences/entry/src/main/resources/zh_CN/element/string.json @@ -59,6 +59,10 @@ { "name": "write_success_msg", "value": "写入数据成功!" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/Data/Preferences/hvigor/hvigor-config.json5 b/Data/Preferences/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/Data/Preferences/hvigor/hvigor-config.json5 +++ b/Data/Preferences/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } -} +} \ No newline at end of file diff --git a/Data/Rdb/README.md b/Data/Rdb/README.md index ccf77a19bbd958b03fc740e4f55c97e4203d6acc..2b4bfab7a346f68d1e321bc1c806372f9647d91c 100644 --- a/Data/Rdb/README.md +++ b/Data/Rdb/README.md @@ -14,13 +14,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -41,14 +41,11 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──AccountData.ets // 账目类接口 -│ │ │ └──AccountItem.ets // 账目资源类接口 │ │ ├──constants │ │ │ └──CommonConstants.ets // 公共常量 │ │ ├──database @@ -67,7 +64,10 @@ │ ├──view │ │ └──DialogComponent.ets // 自定义弹窗 │ └──viewmodel -│ └──AccountList.ets // 账目类型model +│ ├──AccountData.ets // 账目类接口 +│ ├──AccountItem.ets // 账目资源类接口 +│ ├──AccountList.ets // 账目类型model +│ └──ConstantsInterface.ets // 常量接口 └──entry/src/main/resources // 资源文件夹 ``` @@ -78,7 +78,7 @@ 导入关系型数据库模块: ```typescript -import data_rdb from '@ohos.data.rdb'; +import relationalStore from '@ohos.data.relationalStore'; ``` 关系型数据库提供以下两个基本功能: @@ -88,17 +88,19 @@ import data_rdb from '@ohos.data.rdb'; 首先要获取一个RdbStore实例来操作关系型数据库,代码如下: ```typescript -getRdbStore(callback) { +// Rdb.ets +getRdbStore(callback: Function = () => { +}) { // 如果已经获取到RdbStore则不做操作 - if (this.rdbStore != null) { - Logger.verbose(`${RDB_TAG}`, 'The rdbStore exists.'); - callback(); + if (!callback || typeof callback == 'undefined' || callback == undefined) { + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'getRdbStore() has no callback!'); return; } + // 应用上下文,本Codelab使用API9 Stage模型的Context let context: Context = getContext(this) as Context; - data_rdb.getRdbStore(context, STORE_CONFIG, 1, (err, rdb) => { + relationalStore.getRdbStore(context, CommonConstants.STORE_CONFIG, (err, rdb) => { if (err) { Logger.error(`${RDB_TAG}`, 'gerRdbStore() failed, err: ' + err); return; @@ -116,68 +118,101 @@ getRdbStore(callback) { 关系型数据库接口提供的增、删、改、查操作均有callback和Promise两种异步回调方式,本Codelab使用了callback异步回调,其中插入数据使用了insert\(\)接口,实现代码如下: ```typescript -insertData(data, callback) { - let resFlag: boolean = false; // 用于记录插入是否成功的flag - const valueBucket = data; // 存储键值对的类型,表示要插入到表中的数据行 - this.rdbStore.insert(this.tableName, valueBucket, function (err, ret) { - if (err) { - Logger.error(`${RDB_TAG}`, 'insertData() failed, err: ' + err); - callback(resFlag); - return; - } - callback(!resFlag); - }); +// Rdb.ets +insertData(data: relationalStore.ValuesBucket, callback: Function = () => { +}) { + if (!callback || typeof callback == 'undefined' || callback == undefined) { + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'insertData() has no callback!'); + return; + } + let resFlag: boolean = false; + const valueBucket: relationalStore.ValuesBucket = data; + if (this.rdbStore) { + this.rdbStore.insert(this.tableName, valueBucket, (err, ret) => { + if (err) { + Logger.error(`${CommonConstants.RDB_TAG}`, 'insertData() failed, err: ' + err); + callback(resFlag); + return; + } + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'insertData() finished: ' + ret); + callback(ret); + }); + } } ``` 删除数据使用了delete\(\)接口,实现代码如下: ```typescript -deleteData(predicates, callback) { +// Rdb.ets +deleteData(predicates: relationalStore.RdbPredicates, callback: Function = () => { +}) { + if (!callback || typeof callback == 'undefined' || callback == undefined) { + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'deleteData() has no callback!'); + return; + } let resFlag: boolean = false; - - // predicates表示待删除数据的操作条件 - this.rdbStore.delete(predicates, function (err, ret) { - if (err) { - Logger.error(`${RDB_TAG}`, 'deleteData() failed, err: ' + err); - callback(resFlag); - return; - } - callback(!resFlag); - }); + if (this.rdbStore) { + this.rdbStore.delete(predicates, (err, ret) => { + if (err) { + Logger.error(`${CommonConstants.RDB_TAG}`, 'deleteData() failed, err: ' + err); + callback(resFlag); + return; + } + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'deleteData() finished: ' + ret); + callback(!resFlag); + }); + } } ``` 更新数据使用了update\(\)接口,实现代码如下: ```typescript -updateData(predicates, data, callback) { +// Rdb.ets +updateData(predicates: relationalStore.RdbPredicates, data: relationalStore.ValuesBucket, callback: Function = () => { +}) { + if (!callback || typeof callback == 'undefined' || callback == undefined) { + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'updateDate() has no callback!'); + return; + } let resFlag: boolean = false; - const valueBucket = data; - this.rdbStore.update(valueBucket, predicates, function (err, ret) { - if (err) { - Logger.error(`${RDB_TAG}`, 'updateData() failed, err: ' + err); - callback(resFlag); - return; - } - callback(!resFlag); - }); + const valueBucket: relationalStore.ValuesBucket = data; + if (this.rdbStore) { + this.rdbStore.update(valueBucket, predicates, (err, ret) => { + if (err) { + Logger.error(`${CommonConstants.RDB_TAG}`, 'updateData() failed, err: ' + err); + callback(resFlag); + return; + } + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'updateData() finished: ' + ret); + callback(!resFlag); + }); + } } ``` 查找数据使用了query\(\)接口,实现代码如下: ```typescript -query(predicates, callback){ - // columns表示要查询的列,如果为空则表示查询所有列 - this.rdbStore.query(predicates, this.columns, function (err, resultSet) { - if (err) { - Logger.error(`${RDB_TAG}`, 'query() failed, err: ' + err); - return; - } - callback(resultSet); // 如果查找成功则返回resultSet结果集 - resultSet.close(); // 操作完成后关闭结果集 - }); +// Rdb.ets +query(predicates: relationalStore.RdbPredicates, callback: Function = () => { +}) { + if (!callback || typeof callback == 'undefined' || callback == undefined) { + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'query() has no callback!'); + return; + } + if (this.rdbStore) { + this.rdbStore.query(predicates, this.columns, (err, resultSet) => { + if (err) { + Logger.error(`${CommonConstants.RDB_TAG}`, 'query() failed, err: ' + err); + return; + } + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'query() finished.'); + callback(resultSet); + resultSet.close(); + }); + } } ``` @@ -199,16 +234,17 @@ CREATE TABLE IF NOT EXISTS accountTable( 该表需要封装增、删、改、查接口,代码如下: ```typescript +// AccountTable.ets // 插入数据 -insertData(account: Account, callback) { +insertData(account: AccountData, callback: Function) { // 根据输入数据创建待插入的数据行 - const valueBucket = generateBucket(account); + const valueBucket: relationalStore.ValuesBucket = generateBucket(account); this.accountTable.insertData(valueBucket, callback); } // 删除数据 -deleteData(account: Account, callback) { - let predicates = new data_rdb.RdbPredicates(ACCOUNT_TABLE.tableName); +deleteData(account: AccountData, callback: Function) { + let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName); // 根据id匹配待删除的数据行 predicates.equalTo('id', account.id); @@ -216,9 +252,9 @@ deleteData(account: Account, callback) { } // 修改数据 -updateData(account: Account, callback) { - const valueBucket = generateBucket(account); - let predicates = new data_rdb.RdbPredicates(ACCOUNT_TABLE.tableName); +updateData(account: AccountData, callback: Function) { + const valueBucket: relationalStore.ValuesBucket = generateBucket(account); + let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName); // 根据id匹配待删除的数据行 predicates.equalTo('id', account.id); @@ -226,32 +262,30 @@ updateData(account: Account, callback) { } // 查找数据 -query(amount: number, callback, isAll: boolean = true){ - let predicates = new data_rdb.RdbPredicates(ACCOUNT_TABLE.tableName); - - // 是否查找全部数据 +query(amount: number, callback: Function, isAll: boolean = true) { + let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName); if (!isAll) { - predicates.equalTo('amount', amount); // 根据金额匹配要查找的数据行 + predicates.equalTo('amount', amount); } - this.accountTable.query(predicates, function(resultSet) { - let count = resultSet.rowCount; - - // 查找结果为空则返回空数组,否则返回查找结果数组 + this.accountTable.query(predicates, (resultSet: relationalStore.ResultSet) => { + let count: number = resultSet.rowCount; if (count === 0 || typeof count === 'string') { - Logger.verbose(`${TABLE_TAG}`, 'query no results!'); + console.log(`${CommonConstants.TABLE_TAG}` + 'Query no results!'); callback([]); } else { resultSet.goToFirstRow(); - const result = []; + const result: AccountData[] = []; for (let i = 0; i < count; i++) { - let tmp = new Account(0, 0, '', 0); + let tmp: AccountData = { id: 0, accountType: 0, typeText: '', amount: 0 }; tmp.id = resultSet.getDouble(resultSet.getColumnIndex('id')); - ... // 省略赋值代码 + tmp.accountType = resultSet.getDouble(resultSet.getColumnIndex('accountType')); + tmp.typeText = resultSet.getString(resultSet.getColumnIndex('typeText')); + tmp.amount = resultSet.getDouble(resultSet.getColumnIndex('amount')); result[i] = tmp; resultSet.goToNextRow(); } callback(result); - } + } }); } ``` @@ -265,9 +299,10 @@ query(amount: number, callback, isAll: boolean = true){ 在打开应用时,需要查询数据库中存储的账目并显示在主页面,因此生命周期函数aboutToAppear\(\)应写为: ```typescript +// Mainpage.ets aboutToAppear() { this.AccountTable.getRdbStore(() => { // 获取数据库 - this.AccountTable.query(0, (result) => { // 查询数据库中的全部账目 + this.AccountTable.query(0, (result: AccountData[]) => { // 查询数据库中的全部账目 this.accounts = result; }, true); }); @@ -281,7 +316,8 @@ aboutToAppear() { 可以选中需要删除的账目,点击下方“删除”图标后删除对应账目,对应代码如下: ```typescript -.onClick(() => { +// Mainpage.ets +deleteListItem() { for (let i = 0; i < this.deleteList.length; i++) { // 删除每一项选中的账目并更新页面上的账目清单 let index = this.accounts.indexOf(this.deleteList[i]); this.accounts.splice(index, 1); @@ -289,19 +325,20 @@ aboutToAppear() { } this.deleteList = []; this.isEdit = false; -}) +} ``` 搜索栏在键入文本并回车时,实现搜索功能: ```typescript -.onSubmit((val: string) => { - if (val === '') { // 如果搜索栏为空,查找全部账目 - this.AccountTable.query(0, (result) => { +// Mainpage.ets +.onSubmit((searchValue: string) => { + if (searchValue === '') { // 如果搜索栏为空,查找全部账目 + this.AccountTable.query(0, (result: AccountData[]) => { this.accounts = result; }, true); } else { - this.AccountTable.query(parseInt(val), (result) => { // 查找金额为val的账目 + this.AccountTable.query(Number(searchValue), (result: AccountData[]) => { // 查找金额为val的账目 this.accounts = result; }, false); } @@ -311,9 +348,10 @@ aboutToAppear() { 右下角的“添加”按钮可以打开一个自定义弹窗,并在弹窗里新建账目信息: ```typescript +// Mainpage.ets .onClick(() => { this.isInsert = true; // 插入模式 - this.newAccount = new Account(0, 0, '', 0); + this.newAccount = { id: 0, accountType: 0, typeText: '', amount: 0 }; this.dialogController.open(); }) ``` @@ -321,12 +359,17 @@ aboutToAppear() { 点击账目清单中的某个账目,也可以打开自定义弹窗,并修改账目信息: ```typescript -.onClick(() => { +// Mainpage.ets +selectListItem(item: AccountData) { this.isInsert = false; // 编辑模式 this.index = this.accounts.indexOf(item); - this.newAccount = new Account(item.id, item.accountType, item.typeText, item.amount); - this.dialogController.open(); -}) + this.newAccount = { + id: item.id, + accountType: item.accountType, + typeText: item.typeText, + amount: item.amount + }; +} ``` 自定义弹窗由使用Tabs组件创建的账目类别、使用TextInput组件创建的输入栏和确定按钮组成,如下图所示: @@ -336,10 +379,11 @@ aboutToAppear() { 点击“确定”按钮会调用accept\(\)函数,根据isInsert的值来进行账目的添加或修改,代码如下: ```typescript -accept(isInsert: boolean, newAccount: Account) { +// Mainpage.ets +accept(isInsert: boolean, newAccount: AccountData): void { if (isInsert) { // 插入模式,往数据库插入一个新账目 - Logger.verbose(`${INDEX_TAG}`, 'The account inserted is: ' + JSON.stringify(newAccount)); - this.AccountTable.insertData(newAccount, (id) => { + Logger.verbose(`${CommonConstants.INDEX_TAG}`, 'The account inserted is: ' + JSON.stringify(newAccount)); + this.AccountTable.insertData(newAccount, (id: number) => { newAccount.id = id; this.accounts.push(newAccount); }); diff --git a/Data/Rdb/entry/src/main/ets/common/constants/CommonConstants.ets b/Data/Rdb/entry/src/main/ets/common/constants/CommonConstants.ets index 260f354ad134b43e41dc02d3cb7b379cce620150..80abd3545480c20d00cd86d9a925c6a44ce5c042 100644 --- a/Data/Rdb/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/Data/Rdb/entry/src/main/ets/common/constants/CommonConstants.ets @@ -12,20 +12,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import relationalStore from '@ohos.data.relationalStore'; +import { AccountTable } from '../../viewmodel/ConstantsInterface'; export default class CommonConstants { /** * Rdb database config. */ - static readonly STORE_CONFIG = { name: 'database.db' }; + static readonly STORE_CONFIG: relationalStore.StoreConfig = { + name: 'database.db', + securityLevel: relationalStore.SecurityLevel.S1 + }; /** * Account table config. */ - static readonly ACCOUNT_TABLE = { + static readonly ACCOUNT_TABLE: AccountTable = { tableName: 'accountTable', sqlCreate: 'CREATE TABLE IF NOT EXISTS accountTable(id INTEGER PRIMARY KEY AUTOINCREMENT, accountType INTEGER, ' + - 'typeText TEXT, amount INTEGER)', + 'typeText TEXT, amount INTEGER)', columns: ['id', 'accountType', 'typeText', 'amount'] }; diff --git a/Data/Rdb/entry/src/main/ets/common/database/Rdb.ets b/Data/Rdb/entry/src/main/ets/common/database/Rdb.ets index 0bada312474d6b5e7f7990903a2051cea3677387..cdbf56962851bf61c03d613c9868f556daa75cfa 100644 --- a/Data/Rdb/entry/src/main/ets/common/database/Rdb.ets +++ b/Data/Rdb/entry/src/main/ets/common/database/Rdb.ets @@ -13,12 +13,12 @@ * limitations under the License. */ -import data_rdb from '@ohos.data.rdb'; +import relationalStore from '@ohos.data.relationalStore'; import CommonConstants from '../constants/CommonConstants'; import { Logger } from '../utils/Logger'; export default class Rdb { - private rdbStore: any = null; + private rdbStore: relationalStore.RdbStore | null = null; private tableName: string; private sqlCreateTable: string; private columns: Array; @@ -29,7 +29,8 @@ export default class Rdb { this.columns = columns; } - getRdbStore(callback) { + getRdbStore(callback: Function = () => { + }) { if (!callback || typeof callback == 'undefined' || callback == undefined) { Logger.verbose(`${CommonConstants.RDB_TAG}`, 'getRdbStore() has no callback!'); return; @@ -39,8 +40,8 @@ export default class Rdb { callback(); return } - let context = getContext(this); - data_rdb.getRdbStore(context, CommonConstants.STORE_CONFIG, 1, (err, rdb) => { + let context: Context = getContext(this) as Context; + relationalStore.getRdbStore(context, CommonConstants.STORE_CONFIG, (err, rdb) => { if (err) { Logger.error(`${CommonConstants.RDB_TAG}`, 'gerRdbStore() failed, err: ' + err); return; @@ -52,72 +53,84 @@ export default class Rdb { }); } - insertData(data, callback) { + insertData(data: relationalStore.ValuesBucket, callback: Function = () => { + }) { if (!callback || typeof callback == 'undefined' || callback == undefined) { Logger.verbose(`${CommonConstants.RDB_TAG}`, 'insertData() has no callback!'); return; } let resFlag: boolean = false; - const valueBucket = data; - this.rdbStore.insert(this.tableName, valueBucket, function (err, ret) { - if (err) { - Logger.error(`${CommonConstants.RDB_TAG}`, 'insertData() failed, err: ' + err); - callback(resFlag); - return; - } - Logger.verbose(`${CommonConstants.RDB_TAG}`, 'insertData() finished: ' + ret); - callback(ret); - }); + const valueBucket: relationalStore.ValuesBucket = data; + if (this.rdbStore) { + this.rdbStore.insert(this.tableName, valueBucket, (err, ret) => { + if (err) { + Logger.error(`${CommonConstants.RDB_TAG}`, 'insertData() failed, err: ' + err); + callback(resFlag); + return; + } + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'insertData() finished: ' + ret); + callback(ret); + }); + } } - deleteData(predicates, callback) { + deleteData(predicates: relationalStore.RdbPredicates, callback: Function = () => { + }) { if (!callback || typeof callback == 'undefined' || callback == undefined) { Logger.verbose(`${CommonConstants.RDB_TAG}`, 'deleteData() has no callback!'); return; } let resFlag: boolean = false; - this.rdbStore.delete(predicates, function (err, ret) { - if (err) { - Logger.error(`${CommonConstants.RDB_TAG}`, 'deleteData() failed, err: ' + err); - callback(resFlag); - return; - } - Logger.verbose(`${CommonConstants.RDB_TAG}`, 'deleteData() finished: ' + ret); - callback(!resFlag); - }); + if (this.rdbStore) { + this.rdbStore.delete(predicates, (err, ret) => { + if (err) { + Logger.error(`${CommonConstants.RDB_TAG}`, 'deleteData() failed, err: ' + err); + callback(resFlag); + return; + } + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'deleteData() finished: ' + ret); + callback(!resFlag); + }); + } } - updateData(predicates, data, callback) { + updateData(predicates: relationalStore.RdbPredicates, data: relationalStore.ValuesBucket, callback: Function = () => { + }) { if (!callback || typeof callback == 'undefined' || callback == undefined) { Logger.verbose(`${CommonConstants.RDB_TAG}`, 'updateDate() has no callback!'); return; } let resFlag: boolean = false; - const valueBucket = data; - this.rdbStore.update(valueBucket, predicates, function (err, ret) { - if (err) { - Logger.error(`${CommonConstants.RDB_TAG}`, 'updateData() failed, err: ' + err); - callback(resFlag); - return; - } - Logger.verbose(`${CommonConstants.RDB_TAG}`, 'updateData() finished: ' + ret); - callback(!resFlag); - }); + const valueBucket: relationalStore.ValuesBucket = data; + if (this.rdbStore) { + this.rdbStore.update(valueBucket, predicates, (err, ret) => { + if (err) { + Logger.error(`${CommonConstants.RDB_TAG}`, 'updateData() failed, err: ' + err); + callback(resFlag); + return; + } + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'updateData() finished: ' + ret); + callback(!resFlag); + }); + } } - query(predicates, callback) { + query(predicates: relationalStore.RdbPredicates, callback: Function = () => { + }) { if (!callback || typeof callback == 'undefined' || callback == undefined) { Logger.verbose(`${CommonConstants.RDB_TAG}`, 'query() has no callback!'); return; } - this.rdbStore.query(predicates, this.columns, function (err, resultSet) { - if (err) { - Logger.error(`${CommonConstants.RDB_TAG}`, 'query() failed, err: ' + err); - return; - } - Logger.verbose(`${CommonConstants.RDB_TAG}`, 'query() finished.'); - callback(resultSet); - resultSet.close(); - }); + if (this.rdbStore) { + this.rdbStore.query(predicates, this.columns, (err, resultSet) => { + if (err) { + Logger.error(`${CommonConstants.RDB_TAG}`, 'query() failed, err: ' + err); + return; + } + Logger.verbose(`${CommonConstants.RDB_TAG}`, 'query() finished.'); + callback(resultSet); + resultSet.close(); + }); + } } } \ No newline at end of file diff --git a/Data/Rdb/entry/src/main/ets/common/database/tables/AccountTable.ets b/Data/Rdb/entry/src/main/ets/common/database/tables/AccountTable.ets index 1575b05dc2bea6bbdda7e10db56cf143d259b9cc..4f40b00aa9bd08505d893c026b0e2584a841d6d3 100644 --- a/Data/Rdb/entry/src/main/ets/common/database/tables/AccountTable.ets +++ b/Data/Rdb/entry/src/main/ets/common/database/tables/AccountTable.ets @@ -13,9 +13,9 @@ * limitations under the License. */ -import data_rdb from '@ohos.data.rdb'; +import relationalStore from '@ohos.data.relationalStore'; import Rdb from '../rdb'; -import AccountData from '../../bean/AccountData'; +import AccountData from '../../../viewmodel/AccountData'; import CommonConstants from '../../constants/CommonConstants'; export default class AccountTable { @@ -31,36 +31,36 @@ export default class AccountTable { } insertData(account: AccountData, callback: Function) { - const valueBucket = generateBucket(account); + const valueBucket: relationalStore.ValuesBucket = generateBucket(account); this.accountTable.insertData(valueBucket, callback); } deleteData(account: AccountData, callback: Function) { - let predicates = new data_rdb.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName); + let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName); predicates.equalTo('id', account.id); this.accountTable.deleteData(predicates, callback); } updateData(account: AccountData, callback: Function) { - const valueBucket = generateBucket(account); - let predicates = new data_rdb.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName); + const valueBucket: relationalStore.ValuesBucket = generateBucket(account); + let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName); predicates.equalTo('id', account.id); this.accountTable.updateData(predicates, valueBucket, callback); } query(amount: number, callback: Function, isAll: boolean = true) { - let predicates = new data_rdb.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName); + let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName); if (!isAll) { predicates.equalTo('amount', amount); } - this.accountTable.query(predicates, function (resultSet) { - let count = resultSet.rowCount; + this.accountTable.query(predicates, (resultSet: relationalStore.ResultSet) => { + let count: number = resultSet.rowCount; if (count === 0 || typeof count === 'string') { console.log(`${CommonConstants.TABLE_TAG}` + 'Query no results!'); callback([]); } else { resultSet.goToFirstRow(); - const result = []; + const result: AccountData[] = []; for (let i = 0; i < count; i++) { let tmp: AccountData = { id: 0, accountType: 0, typeText: '', amount: 0 }; tmp.id = resultSet.getDouble(resultSet.getColumnIndex('id')); @@ -76,12 +76,10 @@ export default class AccountTable { } } -function generateBucket(account: AccountData) { - let obj = {}; - CommonConstants.ACCOUNT_TABLE.columns.forEach((item) => { - if (item != 'id') { - obj[item] = account[item]; - } - }); +function generateBucket(account: AccountData): relationalStore.ValuesBucket { + let obj: relationalStore.ValuesBucket = {}; + obj.accountType = account.accountType + obj.typeText = account.typeText + obj.amount = account.amount return obj; } \ No newline at end of file diff --git a/Data/Rdb/entry/src/main/ets/pages/MainPage.ets b/Data/Rdb/entry/src/main/ets/pages/MainPage.ets index c4549772bd1c9c6d5ff45cb4e1347b37f3c50ad4..f5fe988e4c97662e0ae4b0cfbf078240f596555e 100644 --- a/Data/Rdb/entry/src/main/ets/pages/MainPage.ets +++ b/Data/Rdb/entry/src/main/ets/pages/MainPage.ets @@ -14,7 +14,7 @@ */ import AccountTable from '../common/database/tables/AccountTable'; -import AccountData from '../common/bean/AccountData'; +import AccountData from '../viewmodel/AccountData'; import CommonConstants from '../common/constants/CommonConstants'; import { ImageList } from '../viewmodel/AccountList'; import { DialogComponent } from '../view/DialogComponent'; @@ -29,21 +29,24 @@ struct MainPage { @State isInsert: boolean = false; @State newAccount: AccountData = { id: 0, accountType: 0, typeText: '', amount: 0 }; @State index: number = -1; - private AccountTable = new AccountTable(); private deleteList: Array = []; searchController: SearchController = new SearchController(); dialogController: CustomDialogController = new CustomDialogController({ - builder: DialogComponent({ isInsert: this.isInsert, newAccount: this.newAccount, confirm: this.accept.bind(this) }), + builder: DialogComponent({ + isInsert: this.isInsert, + newAccount: this.newAccount, + confirm: (isInsert: boolean, newAccount: AccountData) => this.accept(isInsert, newAccount) + }), customStyle: true, alignment: DialogAlignment.Bottom }); - accept(isInsert: boolean, newAccount: AccountData) { + accept(isInsert: boolean, newAccount: AccountData): void { if (isInsert) { Logger.verbose(`${CommonConstants.INDEX_TAG}`, 'The account inserted is: ' + JSON.stringify(newAccount)); - this.AccountTable.insertData(newAccount, (id) => { + this.AccountTable.insertData(newAccount, (id: number) => { newAccount.id = id; this.accounts.push(newAccount); }); @@ -59,7 +62,7 @@ struct MainPage { aboutToAppear() { this.AccountTable.getRdbStore(() => { - this.AccountTable.query(0, (result) => { + this.AccountTable.query(0, (result: AccountData[]) => { this.accounts = result; }, true); }); @@ -108,7 +111,11 @@ struct MainPage { .margin({ top: $r('app.float.edge_size_M'), bottom: $r('app.float.edge_size_MM') }) Row() { - Search({ value: this.searchText, placeholder: CommonConstants.SEARCH_TEXT, controller: this.searchController }) + Search({ + value: this.searchText, + placeholder: CommonConstants.SEARCH_TEXT, + controller: this.searchController + }) .width(CommonConstants.FULL_WIDTH) .borderRadius($r('app.float.radius_size_M')) .borderWidth($r('app.float.border_size_S')) @@ -121,11 +128,11 @@ struct MainPage { }) .onSubmit((searchValue: string) => { if (searchValue === '') { - this.AccountTable.query(0, (result) => { + this.AccountTable.query(0, (result: AccountData[]) => { this.accounts = result; }, true); } else { - this.AccountTable.query(parseInt(searchValue), (result) => { + this.AccountTable.query(Number(searchValue), (result: AccountData[]) => { this.accounts = result; }, false); } @@ -153,9 +160,9 @@ struct MainPage { .layoutWeight(1) if (!this.isEdit) { - Text(item.accountType === 0 ? '-' + item.amount.toString(): '+' + item.amount.toString()) + Text(item.accountType === 0 ? '-' + item.amount.toString() : '+' + item.amount.toString()) .fontSize($r('app.float.font_size_M')) - .fontColor(item.accountType === 0 ? $r('app.color.pay_color'): $r('app.color.main_color')) + .fontColor(item.accountType === 0 ? $r('app.color.pay_color') : $r('app.color.main_color')) .align(Alignment.End) .flexGrow(CommonConstants.FULL_SIZE) } else { @@ -208,7 +215,7 @@ struct MainPage { .position({ x: CommonConstants.EDIT_POSITION_X, y: CommonConstants.EDIT_POSITION_Y }) .onClick(() => { this.isInsert = true; - this.newAccount = { id: 0, accountType:0, typeText: '', amount: 0 }; + this.newAccount = { id: 0, accountType: 0, typeText: '', amount: 0 }; this.dialogController.open(); }) } @@ -220,7 +227,7 @@ struct MainPage { .width($r('app.float.component_size_MP')) .height($r('app.float.component_size_MP')) .backgroundColor($r('app.color.background_color')) - .markAnchor({ x: $r('app.float.mark_anchor'), y: CommonConstants.MINIMUM_SIZE}) + .markAnchor({ x: $r('app.float.mark_anchor'), y: CommonConstants.MINIMUM_SIZE }) .position({ x: CommonConstants.DELETE_POSITION_X, y: CommonConstants.DELETE_POSITION_Y }) .onClick(() => { this.deleteListItem(); diff --git a/Data/Rdb/entry/src/main/ets/view/DialogComponent.ets b/Data/Rdb/entry/src/main/ets/view/DialogComponent.ets index b4d35c5492c97197b4a65e96acf3d4795c262571..f397b0d5364339621ee35f80adc2619f957844ca 100644 --- a/Data/Rdb/entry/src/main/ets/view/DialogComponent.ets +++ b/Data/Rdb/entry/src/main/ets/view/DialogComponent.ets @@ -14,17 +14,17 @@ */ import prompt from '@ohos.promptAction'; -import AccountData from '../common/bean/AccountData'; -import AccountItem from '../common/bean/AccountItem'; +import AccountData from '../viewmodel/AccountData'; +import AccountItem from '../viewmodel/AccountItem'; import { PayList, EarnList } from '../viewmodel/AccountList'; import CommonConstants from '../common/constants/CommonConstants'; @CustomDialog export struct DialogComponent { - private controller: CustomDialogController; - private isInsert: boolean; - private newAccount: AccountData; - private confirm: (isInsert: boolean, newAccount: AccountData) => void + controller?: CustomDialogController; + @Link isInsert: boolean; + @Link newAccount: AccountData; + confirm?: (isInsert: boolean, newAccount: AccountData) => void private scroller: Scroller = new Scroller(); private inputAmount = ''; @State payList: Array = PayList; @@ -33,7 +33,8 @@ export struct DialogComponent { @State curIndex: number = 0; @State curType: string = ''; - @Builder TabBuilder(index: number) { + @Builder + TabBuilder(index: number) { Column() { Text(index === 0 ? $r('app.string.pay_text') : $r('app.string.income_text')) .fontSize($r('app.float.font_size_M')) @@ -42,7 +43,11 @@ export struct DialogComponent { .width($r('app.float.component_size_MP')) .padding({ top: $r('app.float.edge_size_LM'), bottom: $r('app.float.edge_size_S') }) .margin({ bottom: $r('app.float.edge_size_S') }) - .border(this.curIndex === index ? { width: { bottom: $r('app.float.border_size_M') }, color: $r('app.color.main_color') } : { color: Color.White }) + .border(this.curIndex === index ? { + width: { + bottom: $r('app.float.border_size_M') }, + color: $r('app.color.main_color') + } : { color: Color.White }) } aboutToAppear() { @@ -63,7 +68,7 @@ export struct DialogComponent { .width($r('app.float.component_size_L')) .height($r('app.float.component_size_S')) .onClick(() => { - this.controller.close(); + this.controller?.close(); }) Tabs({ barPosition: BarPosition.Start, index: this.curIndex }) { @@ -180,11 +185,12 @@ export struct DialogComponent { if (this.newAccount.typeText === '' || this.curIndex !== this.newAccount.accountType) { prompt.showToast({ message: CommonConstants.TOAST_TEXT_1, bottom: CommonConstants.PROMPT_BOTTOM }); } else { - let matchValue = this.inputAmount.match(/[1-9][0-9]*/); - if (matchValue !== null && matchValue[0] === this.inputAmount){ - this.newAccount.amount = parseInt(this.inputAmount); - this.confirm(this.isInsert, this.newAccount); - this.controller.close(); + let regex: RegExp = new RegExp("[1-9][0-9]*"); + let matchValue: Array | null = this.inputAmount.match(regex); + if (matchValue !== null && matchValue[0] === this.inputAmount) { + this.newAccount.amount = Number(this.inputAmount); + this.confirm && this.confirm(this.isInsert, this.newAccount); + this.controller?.close(); } else { prompt.showToast({ message: CommonConstants.TOAST_TEXT_2, bottom: CommonConstants.PROMPT_BOTTOM }); } diff --git a/Data/Rdb/entry/src/main/ets/common/bean/AccountData.ets b/Data/Rdb/entry/src/main/ets/viewmodel/AccountData.ets similarity index 100% rename from Data/Rdb/entry/src/main/ets/common/bean/AccountData.ets rename to Data/Rdb/entry/src/main/ets/viewmodel/AccountData.ets diff --git a/Data/Rdb/entry/src/main/ets/common/bean/AccountItem.ets b/Data/Rdb/entry/src/main/ets/viewmodel/AccountItem.ets similarity index 100% rename from Data/Rdb/entry/src/main/ets/common/bean/AccountItem.ets rename to Data/Rdb/entry/src/main/ets/viewmodel/AccountItem.ets diff --git a/Data/Rdb/entry/src/main/ets/viewmodel/AccountList.ets b/Data/Rdb/entry/src/main/ets/viewmodel/AccountList.ets index 8e68ba36d3a11701b97165406b1cdfb8fd14e1fb..6b53c040e9e2f3ce452768bce162e44a1d416aea 100644 --- a/Data/Rdb/entry/src/main/ets/viewmodel/AccountList.ets +++ b/Data/Rdb/entry/src/main/ets/viewmodel/AccountList.ets @@ -1,4 +1,4 @@ -import AccountItem from '../common/bean/AccountItem'; +import AccountItem from './AccountItem'; export const PayList: Array = [ { @@ -54,7 +54,7 @@ export const EarnList: Array = [ } ] -export const ImageList = { +export const ImageList: Record = { '吃饭': $rawfile('foods.png'), '零食': $rawfile('snacks.png'), '汽车加油': $rawfile('fuel.png'), diff --git a/Data/Rdb/entry/src/main/ets/viewmodel/ConstantsInterface.ets b/Data/Rdb/entry/src/main/ets/viewmodel/ConstantsInterface.ets new file mode 100644 index 0000000000000000000000000000000000000000..955bcd2596c381ec3d6d3278c652040076bd56c0 --- /dev/null +++ b/Data/Rdb/entry/src/main/ets/viewmodel/ConstantsInterface.ets @@ -0,0 +1,21 @@ + +/* + * Copyright (c) 2022 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. + */ + +export interface AccountTable { + tableName: string; + sqlCreate: string; + columns: string[]; +} \ No newline at end of file diff --git a/Data/Rdb/hvigor/hvigor-config.json5 b/Data/Rdb/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/Data/Rdb/hvigor/hvigor-config.json5 +++ b/Data/Rdb/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/Data/SetAppFontSize/README.md b/Data/SetAppFontSize/README.md index e4e7b3d1f268fd1dfc0f2708af82b3fb1efc7a54..e4ca31c01efaa3aec7f864b03e15d2b60dd42422 100644 --- a/Data/SetAppFontSize/README.md +++ b/Data/SetAppFontSize/README.md @@ -18,13 +18,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -45,21 +45,18 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` -├──entry/src/main/ets // 代码区 +├──entry/src/main/ets // ArkTS代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──ChatData.ets // 聊天列表数据类 -│ │ │ ├──ItemDirection.ets // 聊天数据位置 -│ │ │ └──SettingData.ets // 设置列表数据类 │ │ ├──constants │ │ │ ├──CommonConstants.ets // 公共常量类 -│ │ │ └─StyleConstants.ets // 属性常量类 +│ │ │ └──StyleConstants.ets // 属性常量类 │ │ ├──database │ │ │ └──PreferencesUtil.ets // 首选项数据操作工具类 │ │ └──utils +│ │ ├──GlobalContext.ets // 全局上下文工具类 │ │ └──Logger.ets // 日志工具类 │ ├──entryability │ │ └──EntryAbility.ets // 程序入口类 @@ -71,9 +68,12 @@ │ │ ├──SettingItemComponent.ets // 主页面列表Item组件 │ │ └──TitleBarComponent.ets // 页面标题栏组件 │ └──viewmodel +│ ├──ChatData.ets // 聊天列表数据类 │ ├──HomeViewModel.ets // 主页面数据模型 +│ ├──ItemDirection.ets // 聊天数据位置 +│ └──SettingData.ets // 设置列表数据类 │ └──SetViewModel.ets // 字体大小调节页面数据模型 -└──entry/src/main/resources // 资源文件目录 +└──entry/src/main/resources // 资源文件目录 ``` ## 保存默认大小 @@ -81,37 +81,37 @@ 应用初始化时,为了保证页面中文本的正常显示。在entryAbility生命周期onCreate方法处,添加一个命名为“myPreferences”的首选项表。在表中添加一个名为“appFontSize”的字段,保存默认字体大小。代码如下所示: ```typescript +// PreferencesUtil.ets // 导入首选项数据库 import dataPreferences from '@ohos.data.preferences'; -// 先将Promise保存到全局 -globalThis.getFontPreferences = (() => { - let preferences: Promise = dataPreferences.getPreferences(context, PREFERENCES_NAME); - return preferences; -}); -``` - -```typescript -// 保存默认字体大小 -saveDefaultFontSize(fontSize: number) { - globalThis.getFontPreferences().then((preferences) => { - // 拿到preferences实例后,先判断是否存在该字段 - preferences.has(KEY_APP_FONT_SIZE).then(async (isExist) => { - Logger.info(TAG, 'preferences has changeFontSize is ' + isExist); - // 如果不存在,调用保存方法 - if (!isExist) { - Logger.info(TAG, 'saveSize do not has exit...'); - // 将字体大小写入到preferences实例 - await preferences.put(KEY_APP_FONT_SIZE, fontSize); - // 将preferences实例数据进行持久化 - preferences.flush(); - } - }).catch((err) => { - Logger.error(TAG, 'Has the value failed with err: ' + err); +export class PreferencesUtil { + // 先将Promise保存到全局 + createFontPreferences(context: Context) { + let fontPreferences: Function = (() => { + let preferences: Promise = dataPreferences.getPreferences(context, + PREFERENCES_NAME); + return preferences; }); - }).catch((err) => { - Logger.error(TAG, 'Get the preferences failed, err: ' + err); - }); + GlobalContext.getContext().setObject('getFontPreferences', fontPreferences); + } + // 保存默认字体大小 + saveDefaultFontSize(fontSize: number) { + let getFontPreferences: Function = GlobalContext.getContext().getObject('getFontPreferences') as Function; + getFontPreferences().then((preferences: dataPreferences.Preferences) => { + preferences.has(KEY_APP_FONT_SIZE).then(async (isExist: boolean) => { + Logger.info(TAG, 'preferences has changeFontSize is ' + isExist); + if (!isExist) { + await preferences.put(KEY_APP_FONT_SIZE, fontSize); + preferences.flush(); + } + }).catch((err: Error) => { + Logger.error(TAG, 'Has the value failed with err: ' + err); + }); + }).catch((err: Error) => { + Logger.error(TAG, 'Get the preferences failed, err: ' + err); + }); + } } ``` @@ -130,16 +130,14 @@ onPageShow() { }) } ... -Text('设置字体大小') - .fontSize(this.changeFontSize + 'fp') ``` ```typescript // PreferencesUtil.ets工具类 async getChangeFontSize() { let fontSize: number = 0; - const preferences = await globalThis.getFontPreferences(); - fontSize = await preferences.get(KEY_APP_FONT_SIZE, fontSize); + let getFontPreferences: Function = GlobalContext.getContext().getObject('getFontPreferences') as Function; + fontSize = await (await getFontPreferences()).get(KEY_APP_FONT_SIZE, fontSize); return fontSize; } ``` @@ -151,17 +149,23 @@ async getChangeFontSize() { ```typescript // SetFontSizePage.ets Slider({ - value: this.changeFontSize === CommonConstants.SET_SIZE_HUGE - ? CommonConstants.SET_SLIDER_MAX : this.changeFontSize, + value: this.changeFontSize === CommonConstants.SET_SIZE_HUGE ? + CommonConstants.SET_SLIDER_MAX : this.changeFontSize, min: CommonConstants.SET_SLIDER_MIN, max: CommonConstants.SET_SLIDER_MAX, step: CommonConstants.SET_SLIDER_STEP, style: SliderStyle.InSet }) ... - .onChange((value: number) => { + .onChange(async (value: number) => { + if (this.changeFontSize === 0) { + this.changeFontSize = await PreferencesUtil.getChangeFontSize(); + this.fontSizeText = SetViewModel.getTextByFontSize(value); + return; + } // 获取改变后的字体大小 - this.changeFontSize = value === CommonConstants.SET_SLIDER_MAX ? CommonConstants.SET_SIZE_HUGE : value; + this.changeFontSize = (value === CommonConstants.SET_SLIDER_MAX ? + CommonConstants.SET_SIZE_HUGE : value); // 获取字体大小的文本 this.fontSizeText = SetViewModel.getTextByFontSize(this.changeFontSize); // 保存数据 @@ -172,11 +176,12 @@ Slider({ ```typescript // PreferencesUtil.ets工具类 saveChangeFontSize(fontSize: number) { - globalThis.getFontPreferences().then(async (preferences) => { + let getFontPreferences: Function = GlobalContext.getContext().getObject('getFontPreferences') as Function; + getFontPreferences().then(async (preferences: dataPreferences.Preferences) => { await preferences.put(KEY_APP_FONT_SIZE, fontSize); preferences.flush(); - }).catch((err) => { - Logger.error(TAG, 'Get the preferences failed, err: ' + err); + }).catch((err: Error) => { + Logger.error(TAG, 'put the preferences failed, err: ' + err); }); } ``` diff --git a/Data/SetAppFontSize/entry/oh-package.json5 b/Data/SetAppFontSize/entry/oh-package.json5 index bb53a3dbc95d69001a611f7b8d2cb919ec099bf4..a7afd4ec1017198e9d8017e9f28e8e1d786a9e39 100644 --- a/Data/SetAppFontSize/entry/oh-package.json5 +++ b/Data/SetAppFontSize/entry/oh-package.json5 @@ -6,4 +6,4 @@ "repository": {}, "version": "1.0.0", "dependencies": {} -} \ No newline at end of file +} diff --git a/Data/SetAppFontSize/entry/src/main/ets/common/database/PreferencesUtil.ets b/Data/SetAppFontSize/entry/src/main/ets/common/database/PreferencesUtil.ets index f478b18aae5b1a777295cb15182e51a3f6f4c884..c1fdff2dc4beff543c822c4898a89a9aee976d99 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/common/database/PreferencesUtil.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/common/database/PreferencesUtil.ets @@ -14,6 +14,7 @@ */ import dataPreferences from '@ohos.data.preferences'; +import { GlobalContext } from '../utils/GlobalContext'; import Logger from '../utils/Logger'; const TAG = '[PreferencesUtil]'; @@ -24,51 +25,56 @@ const KEY_APP_FONT_SIZE = 'appFontSize'; * The PreferencesUtil provides preferences of create, save and query. */ export class PreferencesUtil { - createFontPreferences(context) { - globalThis.getFontPreferences = (() => { - let preferences: Promise = dataPreferences.getPreferences(context, PREFERENCES_NAME); + createFontPreferences(context: Context) { + let fontPreferences: Function = (() => { + let preferences: Promise = dataPreferences.getPreferences(context, + PREFERENCES_NAME); return preferences; }); + GlobalContext.getContext().setObject('getFontPreferences', fontPreferences); } saveDefaultFontSize(fontSize: number) { - globalThis.getFontPreferences().then((preferences) => { - preferences.has(KEY_APP_FONT_SIZE).then(async (isExist) => { + let getFontPreferences: Function = GlobalContext.getContext().getObject('getFontPreferences') as Function; + getFontPreferences().then((preferences: dataPreferences.Preferences) => { + preferences.has(KEY_APP_FONT_SIZE).then(async (isExist: boolean) => { Logger.info(TAG, 'preferences has changeFontSize is ' + isExist); if (!isExist) { await preferences.put(KEY_APP_FONT_SIZE, fontSize); preferences.flush(); } - }).catch((err) => { + }).catch((err: Error) => { Logger.error(TAG, 'Has the value failed with err: ' + err); }); - }).catch((err) => { + }).catch((err: Error) => { Logger.error(TAG, 'Get the preferences failed, err: ' + err); }); } saveChangeFontSize(fontSize: number) { - globalThis.getFontPreferences().then(async (preferences) => { + let getFontPreferences: Function = GlobalContext.getContext().getObject('getFontPreferences') as Function; + getFontPreferences().then(async (preferences: dataPreferences.Preferences) => { await preferences.put(KEY_APP_FONT_SIZE, fontSize); preferences.flush(); - }).catch((err) => { + }).catch((err: Error) => { Logger.error(TAG, 'put the preferences failed, err: ' + err); }); } async getChangeFontSize() { let fontSize: number = 0; - const preferences = await globalThis.getFontPreferences(); - fontSize = await preferences.get(KEY_APP_FONT_SIZE, fontSize); + let getFontPreferences: Function = GlobalContext.getContext().getObject('getFontPreferences') as Function; + fontSize = await (await getFontPreferences()).get(KEY_APP_FONT_SIZE, fontSize); return fontSize; } - - async deleteChangeFontSize() { - const preferences: dataPreferences.Preferences = await globalThis.getFontPreferences(); + + async deleteChangeFontSize() { + let getFontPreferences: Function = GlobalContext.getContext().getObject('getFontPreferences') as Function; + const preferences: dataPreferences.Preferences = await getFontPreferences(); let deleteValue = preferences.delete(KEY_APP_FONT_SIZE); deleteValue.then(() => { Logger.info(TAG, 'Succeeded in deleting the key appFontSize.'); - }).catch((err) => { + }).catch((err: Error) => { Logger.error(TAG, 'Failed to delete the key appFontSize. Cause: ' + err); }); } diff --git a/Data/SetAppFontSize/entry/src/main/ets/common/utils/GlobalContext.ets b/Data/SetAppFontSize/entry/src/main/ets/common/utils/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..677db0cb7cce13a483f076991499a50d7fcdae94 --- /dev/null +++ b/Data/SetAppFontSize/entry/src/main/ets/common/utils/GlobalContext.ets @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { } + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/Data/SetAppFontSize/entry/src/main/ets/common/utils/Logger.ets b/Data/SetAppFontSize/entry/src/main/ets/common/utils/Logger.ets index 8a65756dda90c9777e16323a89e73c4f1e324c2c..65f9ad7690d2e7f0a68d7373f46098554ffb3494 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/common/utils/Logger.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/common/utils/Logger.ets @@ -28,23 +28,23 @@ export class Logger { this.domain = 0xFF00; } - debug(...args: any[]) { + debug(...args: string[]) { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]) { + info(...args: string[]) { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]) { + warn(...args: string[]) { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]) { + error(...args: string[]) { hilog.error(this.domain, this.prefix, this.format, args); } - fatal(...args: any[]) { + fatal(...args: string[]) { hilog.fatal(this.domain, this.prefix, this.format, args); } diff --git a/Data/SetAppFontSize/entry/src/main/ets/entryability/EntryAbility.ets b/Data/SetAppFontSize/entry/src/main/ets/entryability/EntryAbility.ets index 096993b25163234e565327f6ebfd97819e0e4d88..5604256aa19fb20c21e8a813db126556c8a0a763 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/entryability/EntryAbility.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/entryability/EntryAbility.ets @@ -17,6 +17,10 @@ import UIAbility from '@ohos.app.ability.UIAbility' import CommonConstants from '../common/constants/CommonConstants'; import Logger from '../common/utils/Logger'; import PreferencesUtil from '../common/database/Preferencesutil'; +import Want from '@ohos.app.ability.Want'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; +import window from '@ohos.window'; +import { GlobalContext } from '../common/utils/GlobalContext'; const TAG = '[entryAbility]'; @@ -24,9 +28,9 @@ const TAG = '[entryAbility]'; * Lift cycle management of Ability. */ export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { Logger.info(TAG, 'onCreate'); - globalThis.abilityWant = want; + GlobalContext.getContext().setObject('abilityWant', want); PreferencesUtil.createFontPreferences(this.context); // 设置字体默认大小 @@ -37,7 +41,7 @@ export default class EntryAbility extends UIAbility { Logger.info(TAG, 'onDestroy'); } - onWindowStageCreate(windowStage) { + onWindowStageCreate(windowStage: window.WindowStage) { // Main window is created, set main page for this ability Logger.info(TAG, 'onWindowStageCreate'); diff --git a/Data/SetAppFontSize/entry/src/main/ets/pages/HomePage.ets b/Data/SetAppFontSize/entry/src/main/ets/pages/HomePage.ets index 6a13d399eed8a3d805cc2734e6f8a85f2312a9cf..6ee2db1a3a6f22ab57cf16b4be7381a8137611b4 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/pages/HomePage.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/pages/HomePage.ets @@ -21,6 +21,7 @@ import CommonConstants from '../common/constants/CommonConstants'; import StyleConstants from '../common/constants/StyleConstants'; import Logger from '../common/utils/Logger'; import PreferencesUtil from '../common/database/Preferencesutil'; +import SettingData from '../viewmodel/SettingData'; const TAG = '[HomePage]'; @@ -31,7 +32,7 @@ const TAG = '[HomePage]'; @Component struct HomePage { private settingArr = HomeViewModel.initSettingData(); - @State changeFontSize: number = 0; + @State changeFontSize: number = CommonConstants.SET_SIZE_NORMAL; onPageShow() { PreferencesUtil.getChangeFontSize().then((value) => { @@ -74,19 +75,20 @@ struct HomePage { @Builder SettingItems() { List() { - ForEach(this.settingArr.slice(CommonConstants.START_INDEX, CommonConstants.END_INDEX), (item, index) => { + ForEach(this.settingArr.slice(CommonConstants.START_INDEX, CommonConstants.END_INDEX), + (item: SettingData, index?: number) => { ListItem() { SettingItemComponent({ setting: item, changeFontSize: this.changeFontSize, itemClick: () => { if (index === CommonConstants.SET_FONT_INDEX) { router.pushUrl({ url: CommonConstants.SET_URL - }).catch((error) => { + }).catch((error: Error) => { Logger.info(TAG, 'HomePage push error' + JSON.stringify(error)); }); } } }) } - }, item => item.settingName.id.toString()) + }, (item: SettingData) => JSON.stringify(item)) } .divider({ strokeWidth: $r('app.float.setting_item_divider_width'), diff --git a/Data/SetAppFontSize/entry/src/main/ets/pages/SetFontSizePage.ets b/Data/SetAppFontSize/entry/src/main/ets/pages/SetFontSizePage.ets index 556a20774d406dfccb3e456c6d44bf95d748e61b..ea9f34cc4aafaccda7e3cf12701ac780bfeae36f 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/pages/SetFontSizePage.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/pages/SetFontSizePage.ets @@ -20,6 +20,7 @@ import CommonConstants from '../common/constants/CommonConstants'; import StyleConstants from '../common/constants/StyleConstants'; import Logger from '../common/utils/Logger'; import PreferencesUtil from '../common/database/Preferencesutil'; +import ChatData from '../viewmodel/ChatData'; const TAG = '[SetFontSizePage]'; @@ -49,11 +50,11 @@ struct SetFontSizePage { if (this.changeFontSize > 0) { List() { - ForEach(this.contentArr, item => { + ForEach(this.contentArr, (item: ChatData) => { ListItem() { ChatItemComponent({ item: item, changeFontSize: this.changeFontSize }) } - }, item => item.content.id.toString()) + }, (item: ChatData) => JSON.stringify(item)) } .layoutWeight(StyleConstants.WEIGHT_FULL) } @@ -103,8 +104,14 @@ struct SliderLayout { }) .showSteps(true) .width(StyleConstants.SLIDER_WIDTH_PERCENT) - .onChange((value: number) => { - this.changeFontSize = value === CommonConstants.SET_SLIDER_MAX ? CommonConstants.SET_SIZE_HUGE : value; + .onChange(async (value: number) => { + if (this.changeFontSize === 0) { + this.changeFontSize = await PreferencesUtil.getChangeFontSize(); + this.fontSizeText = SetViewModel.getTextByFontSize(value); + return; + } + this.changeFontSize = (value === CommonConstants.SET_SLIDER_MAX ? + CommonConstants.SET_SIZE_HUGE : value); this.fontSizeText = SetViewModel.getTextByFontSize(this.changeFontSize); PreferencesUtil.saveChangeFontSize(this.changeFontSize); }) diff --git a/Data/SetAppFontSize/entry/src/main/ets/view/ChatItemComponent.ets b/Data/SetAppFontSize/entry/src/main/ets/view/ChatItemComponent.ets index 56d4598f5819be89125337813b0cf2fa045e1965..0c94242107aade3ceb97554905330076b4c32bfd 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/view/ChatItemComponent.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/view/ChatItemComponent.ets @@ -13,8 +13,8 @@ * limitations under the License. */ -import ChatData from '../common/bean/ChatData'; -import { ItemDirection } from '../common/bean/ItemDirection'; +import ChatData from '../viewmodel/ChatData'; +import { ItemDirection } from '../viewmodel/ItemDirection'; import StyleConstants from '../common/constants/StyleConstants'; /** @@ -22,8 +22,8 @@ import StyleConstants from '../common/constants/StyleConstants'; */ @Component export default struct ChatItemComponent { - item: ChatData; - @Prop changeFontSize: number; + item: ChatData = new ChatData(); + @Prop changeFontSize: number = 0; build() { Row() { @@ -49,8 +49,8 @@ export default struct ChatItemComponent { @Component struct ChatContent { - item: ChatData; - @Prop changeFontSize: number; + item: ChatData = new ChatData(); + @Prop changeFontSize: number = 0; @State isLineFeed: boolean = false; build() { diff --git a/Data/SetAppFontSize/entry/src/main/ets/view/SettingItemComponent.ets b/Data/SetAppFontSize/entry/src/main/ets/view/SettingItemComponent.ets index abe460435bd3f2f8ab7f52c697b15c8cbe095814..acbd63fdbfab79cf4a328c6f90adfca73bc0a8ef 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/view/SettingItemComponent.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/view/SettingItemComponent.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import SettingData from '../common/bean/SettingData'; +import SettingData from '../viewmodel/SettingData'; import StyleConstants from '../common/constants/StyleConstants'; /** @@ -21,9 +21,10 @@ import StyleConstants from '../common/constants/StyleConstants'; */ @Component export default struct SettingItemComponent { - setting: SettingData; - @Prop changeFontSize: number; - itemClick: () => void; + setting: SettingData = new SettingData(); + @Prop changeFontSize: number = 0; + itemClick: Function = () => { + }; build() { Row() { diff --git a/Data/SetAppFontSize/entry/src/main/ets/view/TitleBarComponent.ets b/Data/SetAppFontSize/entry/src/main/ets/view/TitleBarComponent.ets index 026ca961205581a354a29312bc3681197bc3fb8d..b8477a0f04dd5d83bed86ea3996eb1fc5f5deb2d 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/view/TitleBarComponent.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/view/TitleBarComponent.ets @@ -22,7 +22,7 @@ import StyleConstants from '../common/constants/StyleConstants'; @Component export default struct TitleBarComponent { isBack: boolean = true; - title: Resource; + title: Resource = $r('app.string.empty'); build() { Row() { diff --git a/Data/SetAppFontSize/entry/src/main/ets/common/bean/ChatData.ets b/Data/SetAppFontSize/entry/src/main/ets/viewmodel/ChatData.ets similarity index 89% rename from Data/SetAppFontSize/entry/src/main/ets/common/bean/ChatData.ets rename to Data/SetAppFontSize/entry/src/main/ets/viewmodel/ChatData.ets index 530e48cda2f7331d880b50da56ac3b36b9f99a63..a7df32be2b64e2ee3340526eada01c8ebcc8a18d 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/common/bean/ChatData.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/viewmodel/ChatData.ets @@ -22,10 +22,10 @@ export default class ChatData { /** * Chat list item direction. */ - itemDirection: ItemDirection; + itemDirection: ItemDirection = ItemDirection.LEFT; /** * Chat list item content. */ - content: Resource; + content: Resource = $r('app.string.empty'); } \ No newline at end of file diff --git a/Data/SetAppFontSize/entry/src/main/ets/viewmodel/HomeViewModel.ets b/Data/SetAppFontSize/entry/src/main/ets/viewmodel/HomeViewModel.ets index a95f77e720b1ee0502af75a12719868a7815fb06..f8c1274122adea108bbe35898d0dd6eb56430ccb 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/viewmodel/HomeViewModel.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/viewmodel/HomeViewModel.ets @@ -13,16 +13,16 @@ * limitations under the License. */ -import SettingData from '../common/bean/SettingData'; +import SettingData from '../viewmodel/SettingData'; /** * Home view model, providing page display data. */ export class HomeViewModel { - settingArr: Array = null; + settingArr: Array = []; initSettingData(): Array { - if (this.settingArr === null) { + if (this.settingArr.length === 0) { this.settingArr = new Array(); let settingData = new SettingData(); settingData.settingName = $r('app.string.home_display_and_brightness'); diff --git a/Data/SetAppFontSize/entry/src/main/ets/common/bean/ItemDirection.ets b/Data/SetAppFontSize/entry/src/main/ets/viewmodel/ItemDirection.ets similarity index 100% rename from Data/SetAppFontSize/entry/src/main/ets/common/bean/ItemDirection.ets rename to Data/SetAppFontSize/entry/src/main/ets/viewmodel/ItemDirection.ets diff --git a/Data/SetAppFontSize/entry/src/main/ets/viewmodel/SetViewModel.ets b/Data/SetAppFontSize/entry/src/main/ets/viewmodel/SetViewModel.ets index 2bd57c17a4375b1521a45c69f386856bd353e6fd..a331444036d9f2581ffeaf23e51f739bdbbb550f 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/viewmodel/SetViewModel.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/viewmodel/SetViewModel.ets @@ -14,17 +14,17 @@ */ import CommonConstants from '../common/constants/CommonConstants'; -import ChatData from '../common/bean/ChatData'; -import { ItemDirection } from '../common/bean/ItemDirection'; +import ChatData from '../viewmodel/ChatData'; +import { ItemDirection } from '../viewmodel/ItemDirection'; /** * Set view model, providing page display data. */ export class SetViewModel { - chatArr: Array = null; + chatArr: Array = []; initChatData(): Array { - if (this.chatArr === null) { + if (this.chatArr.length === 0) { this.chatArr = new Array(); let chatData = new ChatData(); chatData.itemDirection = ItemDirection.RIGHT; diff --git a/Data/SetAppFontSize/entry/src/main/ets/common/bean/SettingData.ets b/Data/SetAppFontSize/entry/src/main/ets/viewmodel/SettingData.ets similarity index 88% rename from Data/SetAppFontSize/entry/src/main/ets/common/bean/SettingData.ets rename to Data/SetAppFontSize/entry/src/main/ets/viewmodel/SettingData.ets index a5bfd86b9f794121e98bd2a248bc50e88645f313..1d102687684ac35fdfcecf7c7a019091e26106c4 100644 --- a/Data/SetAppFontSize/entry/src/main/ets/common/bean/SettingData.ets +++ b/Data/SetAppFontSize/entry/src/main/ets/viewmodel/SettingData.ets @@ -20,10 +20,10 @@ export default class SettingData { /** * Setting list item name. */ - settingName: Resource; + settingName: Resource = $r('app.string.empty'); /** * Setting list item image. */ - settingImage: Resource; + settingImage: Resource = $r('app.string.empty'); } \ No newline at end of file diff --git a/Data/SetAppFontSize/entry/src/main/resources/base/element/string.json b/Data/SetAppFontSize/entry/src/main/resources/base/element/string.json index 59ea02a9ac8dee4b58174257625da02f3666faab..71aeab3ddf643c51989c2e5830537071cad106d5 100644 --- a/Data/SetAppFontSize/entry/src/main/resources/base/element/string.json +++ b/Data/SetAppFontSize/entry/src/main/resources/base/element/string.json @@ -87,6 +87,10 @@ { "name": "set_char_a", "value": "A" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/Data/SetAppFontSize/entry/src/main/resources/en_US/element/string.json b/Data/SetAppFontSize/entry/src/main/resources/en_US/element/string.json index 59ea02a9ac8dee4b58174257625da02f3666faab..71aeab3ddf643c51989c2e5830537071cad106d5 100644 --- a/Data/SetAppFontSize/entry/src/main/resources/en_US/element/string.json +++ b/Data/SetAppFontSize/entry/src/main/resources/en_US/element/string.json @@ -87,6 +87,10 @@ { "name": "set_char_a", "value": "A" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/Data/SetAppFontSize/entry/src/main/resources/zh_CN/element/string.json b/Data/SetAppFontSize/entry/src/main/resources/zh_CN/element/string.json index 9f3c78f034928b68c16c14dfd14cf95b693b6269..0c1a867ad97121ecee7017e101e440ef6d13d684 100644 --- a/Data/SetAppFontSize/entry/src/main/resources/zh_CN/element/string.json +++ b/Data/SetAppFontSize/entry/src/main/resources/zh_CN/element/string.json @@ -87,6 +87,10 @@ { "name": "set_char_a", "value": "A" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/Data/SetAppFontSize/hvigor/hvigor-config.json5 b/Data/SetAppFontSize/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/Data/SetAppFontSize/hvigor/hvigor-config.json5 +++ b/Data/SetAppFontSize/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/Data/SetAppFontSize/oh-package.json5 b/Data/SetAppFontSize/oh-package.json5 index 15e83991a860f494d907ff9c86d69b8dd454194f..fdffc35c7d8a62584e10b921d12e97dd0dac0995 100644 --- a/Data/SetAppFontSize/oh-package.json5 +++ b/Data/SetAppFontSize/oh-package.json5 @@ -8,4 +8,4 @@ "repository": {}, "version": "1.0.0", "dependencies": {} -} \ No newline at end of file +} diff --git a/Distributed/DistributeDraw/README.md b/Distributed/DistributeDraw/README.md index 95fa881bd2e0ef9a2ab6766eb4b0afc8e4bea910..36fb5b9b561ae6d89d237c9b725f2c59c494a1df 100644 --- a/Distributed/DistributeDraw/README.md +++ b/Distributed/DistributeDraw/README.md @@ -4,58 +4,58 @@ 本篇Codelab使用设备管理及分布式键值数据库能力,实现多设备之间手写板应用拉起及同步书写内容的功能。操作流程: -1. 设备连接同一无线网络,安装分布式手写板应用。进入应用,点击允许使用多设备协同,点击主页上查询设备按钮,显示附近设备。 -2. 选择设备确认,若已建立连接,启动对方设备上的手写板应用,否则提示建立连接。输入PIN码建立连接后再次点击查询设备按钮,选择设备提交,启动对方设备应用。 -3. 建立连接前绘制的内容在启动对方设备后同步,此时设备上绘制的内容会在另一端同步绘制。 -4. 点击撤销按钮,两侧设备绘制内容同步撤销。 +1. 设备连接同一无线网络,安装分布式手写板应用。进入应用,点击允许使用多设备协同,点击主页上查询设备按钮,显示附近设备。 +2. 选择设备确认,若已建立连接,启动对方设备上的手写板应用,否则提示建立连接。输入PIN码建立连接后再次点击查询设备按钮,选择设备提交,启动对方设备应用。 +3. 建立连接前绘制的内容在启动对方设备后同步,此时设备上绘制的内容会在另一端同步绘制。 +4. 点击撤销按钮,两侧设备绘制内容同步撤销。 ![](figures/zh-cn_image_0000001569348576.gif) ### 相关概念 -- [设备管理](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-device-manager.md):模块提供分布式设备管理能力。 -- [分布式键值数据库](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-distributedKVStore.md):分布式键值数据库为应用程序提供不同设备间数据库的分布式协同能力。 +- [设备管理](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-device-manager.md):模块提供分布式设备管理能力。 +- [分布式键值数据库](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-distributedKVStore.md):分布式键值数据库为应用程序提供不同设备间数据库的分布式协同能力。 ### 相关权限 本篇Codelab使用了设备管理及分布式键值数据库能力,需要手动替换full-SDK,并在配置文件module.json5文件requestPermissions属性中添加如下权限: -- [分布式设备认证组网权限](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissionaccess_service_dm):ohos.permission.ACCESS\_SERVICE\_DM。 -- [设备间的数据交换权限](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissiondistributed_datasync):ohos.permission.DISTRIBUTED\_DATASYNC。 +- [分布式设备认证组网权限](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissionaccess_service_dm):ohos.permission.ACCESS\_SERVICE\_DM。 +- [设备间的数据交换权限](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissiondistributed_datasync):ohos.permission.DISTRIBUTED\_DATASYNC。 ### 约束与限制 -1. 本篇Codelab部分能力依赖于系统API,需下载full-SDK并替换DevEco Studio自动下载的public-SDK。具体操作可参考指南[《如何替换full-SDK》](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/faqs/full-sdk-switch-guide.md)。 -2. 本篇Codelab使用的部分API仅系统应用可用,需要提升应用等级。具体可参考指南[《访问控制授权申请指导》](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-overview.md#%E5%BA%94%E7%94%A8apl%E7%AD%89%E7%BA%A7%E8%AF%B4%E6%98%8E)。 +1. 本篇Codelab部分能力依赖于系统API,需下载full-SDK并替换DevEco Studio自动下载的public-SDK。具体操作可参考指南[《如何替换full-SDK》](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/faqs/full-sdk-switch-guide.md)。 +2. 本篇Codelab使用的部分API仅系统应用可用,需要提升应用等级。具体可参考指南[《访问控制授权申请指导》](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-overview.md#%E5%BA%94%E7%94%A8apl%E7%AD%89%E7%BA%A7%E8%AF%B4%E6%98%8E)。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 10及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 4.0 Beta2。 +- OpenHarmony SDK版本:API version 10。 ### 硬件要求 -- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:4.0 Beta1及以上版本。 +- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 +- OpenHarmony系统:4.0 Release。 ### 环境搭建 完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: -1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以4.0 Beta1版本为例: +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以4.0 Release版本为例: ![](figures/zh-cn_image_0000001621561354.png) -2. 搭建烧录环境。 - 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) - 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) -3. 搭建开发环境。 - 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 - 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建arkts工程)创建工程(模板选择“Empty Ability”)。 - 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建arkts工程)创建工程(模板选择“Empty Ability”)。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 ## 代码结构解读 @@ -64,8 +64,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ └──Position.ets // 绘制位置信息类 │ │ ├──constants │ │ │ └──CommonConstants.ets // 公共常量类 │ │ └──utils @@ -78,7 +76,8 @@ │ ├──view │ │ └──CustomDialogComponent.ets // 自定义弹窗组件类 │ └──viewmodel -│ └──KvStoreModel.ets // 分布式键值数据库管理类 +│ ├──KvStoreModel.ets // 分布式键值数据库管理类 +│ └──Position.ets // 绘制位置信息类 └──entry/src/main/resources // 资源文件目录 ``` @@ -90,7 +89,7 @@ ``` typescript // Index.ets -let storage = LocalStorage.GetShared(); +let storage = LocalStorage.getShared(); @Entry(storage) @Component struct Index { @@ -102,11 +101,13 @@ struct Index { Image($r('app.media.ic_back')) .width($r('app.float.ic_back_width')) .height($r('app.float.ic_back_height')) + ... Blank() // 查找设备按钮 Image($r('app.media.ic_hop')) .width($r('app.float.ic_hop_width')) .height($r('app.float.ic_hop_height')) + ... } .width(CommonConstants.FULL_PERCENT) .height(CommonConstants.TITLE_HEIGHT) @@ -116,7 +117,9 @@ struct Index { Canvas(this.canvasContext) .width(CommonConstants.FULL_PERCENT) .height(CommonConstants.FULL_PERCENT) + ... } + ... .width(CommonConstants.FULL_PERCENT) .layoutWeight(CommonConstants.NUMBER_ONE) } @@ -134,32 +137,33 @@ struct Index { 创建设备管理器。设备管理器创建完成后注册设备上线离线监听,信任设备上线离线时触发。执行获取本地设备信息,获取信任设备列表,初始化展示设备列表等方法。其中deviceManager类需使用full-SDK。 ``` typescript -// RemoteDeviceModel.ets +// RemoteDeviceUtil.ets import deviceManager from '@ohos.distributedHardware.deviceManager'; -class RemoteDeviceModel { +class RemoteDeviceUtil { ... - async createDeviceManager(): Promise { + async createDeviceManager() { ... - await new Promise((resolve, reject) => { + await new Promise((resolve: (value: Object | PromiseLike) => void, reject: ((reason?: RejectError) => void)) => { try { // 创建设备管理器 - deviceManager.createDeviceManager(CommonConstants.BUNDLE_NAME, (error, value) => { - ... - this.myDeviceManager = value; - // 注册信任设备上线离线监听 - this.registerDeviceStateListener(); - // 获取本地设备信息 - this.getLocalDeviceInfo(); - // 获取信任设备列表 - this.getTrustedDeviceList(); - // 初始化展示设备列表 - this.initDeviceList(); - resolve(); + deviceManager.createDeviceManager(CommonConstants.BUNDLE_NAME, + (error, value: deviceManager.DeviceManager) => { + ... + this.myDeviceManager = value; + // 注册信任设备上线离线监听 + this.registerDeviceStateListener(); + // 获取本地设备信息 + this.getLocalDeviceInfo(); + // 获取信任设备列表 + this.getTrustedDeviceList(); + // 初始化展示设备列表 + this.initDeviceList(); + resolve(value); }); } catch (error) { Logger.error('RemoteDeviceModel', - `createDeviceManager failed, error code=${error.code}, msg=${JSON.stringify(error.message)}`); + `createDeviceManager failed, error=${JSON.stringify(error)}`); } }); } @@ -170,8 +174,8 @@ class RemoteDeviceModel { 注册设备状态监听。已验证设备上线或有新设备验证通过时状态类型为ONLINE,将设备添加至信任设备列表。设备离线时状态类型为OFFLINE,将设备从信任列表中移除。 ``` typescript -// RemoteDeviceModel.ets -class RemoteDeviceModel { +// RemoteDeviceUtil.ets +class RemoteDeviceUtil { ... // 注册设备状态改变监听 registerDeviceStateListener(): void { @@ -196,7 +200,7 @@ class RemoteDeviceModel { }); } catch (error) { Logger.error('RemoteDeviceModel', - `registerDeviceStateListener on('deviceStateChange') failed, code=${error.code}, msg=${error.message}`); + `registerDeviceStateListener on('deviceStateChange') failed, error=${JSON.stringify(error)}`); } } @@ -229,9 +233,21 @@ class RemoteDeviceModel { ![](figures/zh-cn_image_0000001635987786.png) ``` typescript -// RemoteDeviceModel.ets -class RemoteDeviceModel { +// RemoteDeviceUtil.ets +class RemoteDeviceUtil { ... + // 处理新发现的设备 + deviceFound(data: DeviceInfoInterface): void { + for (let i: number = 0; i < this.discoverList.length; i++) { + if (this.discoverList[i].deviceId === data.device.deviceId) { + Logger.info('RemoteDeviceModel', `deviceFound device exist=${JSON.stringify(data)}`); + return; + } + } + this.discoverList[this.discoverList.length] = data.device; + this.addToDeviceList(data.device); + } + startDeviceDiscovery(): void { ... try { @@ -242,24 +258,21 @@ class RemoteDeviceModel { this.deviceFound(data); }); ... + let info: deviceManager.SubscribeInfo = { + subscribeId: this.subscribeId, + mode: CommonConstants.SUBSCRIBE_MODE, + medium: CommonConstants.SUBSCRIBE_MEDIUM, + freq: CommonConstants.SUBSCRIBE_FREQ, + isSameAccount: false, + isWakeRemote: true, + capability: CommonConstants.SUBSCRIBE_CAPABILITY + }; // 发现周边设备 this.myDeviceManager.startDeviceDiscovery(info); } catch (error) { Logger.error('RemoteDeviceModel', - `startDeviceDiscovery failed code=${error.code}, msg=${JSON.stringify(error.message)}`); - } - } - - // 处理新发现的设备 - deviceFound(data): void { - for (let i: number = 0; i < this.discoverList.length; i++) { - if (this.discoverList[i].deviceId === data.device.deviceId) { - Logger.info('RemoteDeviceModel', `deviceFound device exist=${JSON.stringify(data)}`); - return; - } + `startDeviceDiscovery failed error=${JSON.stringify(error)}`); } - this.discoverList[this.discoverList.length] = data.device; - this.addToDeviceList(data.device); } // 停止发现设备 @@ -270,13 +283,15 @@ class RemoteDeviceModel { this.myDeviceManager.stopDeviceDiscovery(this.subscribeId); // 注销监听任务 this.myDeviceManager.off('deviceFound'); + this.myDeviceManager.off('discoverFail'); } catch (error) { Logger.error('RemoteDeviceModel', - `stopDeviceDiscovery failed code=${error.code}, msg=${JSON.stringify(error.message)}`); + `stopDeviceDiscovery failed error=${JSON.stringify(error)}`); } } ... } + ``` 选择弹窗内的设备项提交后,执行设备验证。 @@ -285,11 +300,15 @@ class RemoteDeviceModel { 2. 若设备不是信任设备,执行authenticateDevice()方法启动验证。此时连接设备提示是否接受,接收连接后连接设备展示PIN码,本地设备输入PIN码确认后连接成功。再次点击查询设备按钮,选择已连接设备,点击确认启动连接设备上的应用。 ``` typescript -// RemoteDeviceModel.ets -class RemoteDeviceModel { +// RemoteDeviceUtil.ets +class RemoteDeviceUtil { ... // 设备验证 - authenticateDevice(context: common.UIAbilityContext, device: deviceManager.DeviceInfo, positionList: Position[]): void { + authenticateDevice( + context: common.UIAbilityContext, + device: deviceManager.DeviceInfo, + positionList: Position[] + ): void { // 设备为信任设备,启动连接设备上的应用 let tmpList = this.trustedDeviceList.filter((item: deviceManager.DeviceInfo) => device.deviceId === item.deviceId); if (tmpList.length > 0) { @@ -299,12 +318,12 @@ class RemoteDeviceModel { ... try { // 执行设备认证,启动验证相关弹窗,接受信任,显示PIN码,输入PIN码等 - this.myDeviceManager.authenticateDevice(device, authParam, (err, data) => { + this.myDeviceManager.authenticateDevice(device, authParam, (err) => { ... }) } catch (error) { Logger.error('RemoteDeviceModel', - `authenticateDevice failed code=${error.code}, msg=${JSON.stringify(error.message)}`); + `authenticateDevice failed error=${JSON.stringify(error)}`); } } @@ -314,8 +333,8 @@ class RemoteDeviceModel { // 启动连接设备上的应用 context.startAbility(wantValue).then(() => { Logger.info('RemoteDeviceModel', `startAbility finished wantValue=${JSON.stringify(wantValue)}`); - }).catch((error) => { - Logger.error('RemoteDeviceModel', `startAbility failed,code=${error.code},msg=${JSON.stringify(error.message)}`); + }).catch((error: Error) => { + Logger.error('RemoteDeviceModel', `startAbility failed, error=${JSON.stringify(error)}`); }) } ... @@ -327,8 +346,8 @@ class RemoteDeviceModel { 程序关闭时,注销设备状态监听任务,并释放DeviceManager实例。 ``` typescript -// RemoteDeviceModel.ets -class RemoteDeviceModel { +// RemoteDeviceUtil.ets +class RemoteDeviceUtil { ... // 注销监听任务 unregisterDeviceListCallback(): void { @@ -340,7 +359,7 @@ class RemoteDeviceModel { this.myDeviceManager.release(); } catch (err) { Logger.error('RemoteDeviceModel', - `unregisterDeviceListCallback stopDeviceDiscovery failed, code=${err.code}, msg=${err.message}`); + `unregisterDeviceListCallback stopDeviceDiscovery failed, error=${JSON.stringify(err)}`); } } ... @@ -363,17 +382,20 @@ struct Index { ... Row() { Canvas(this.canvasContext) + ... } .onTouch((event: TouchEvent) => { this.onTouchEvent(event); }) + ... } + ... } // 绘制事件 onTouchEvent(event: TouchEvent): void { - let positionX:number = event.touches[0].x; - let positionY:number = event.touches[0].y; + let positionX: number = event.touches[0].x; + let positionY: number = event.touches[0].y; switch (event.type) { // 手指按下 case TouchType.Down: { @@ -381,7 +403,7 @@ struct Index { this.canvasContext.lineWidth = CommonConstants.CANVAS_LINE_WIDTH; this.canvasContext.lineJoin = CommonConstants.CANVAS_LINE_JOIN; this.canvasContext.moveTo(positionX, positionY); - this.pushData(false, false, positionX, positionY); + this.pushData(true, false, positionX, positionY); break; } // 手指移动 @@ -403,7 +425,7 @@ struct Index { } } - pushData(isFirstPosition: boolean, isEndPosition, positionX: number, positionY: number): void { + pushData(isFirstPosition: boolean, isEndPosition: boolean, positionX: number, positionY: number): void { let position = new Position(isFirstPosition, isEndPosition, positionX, positionY); // 存入位置信息列表 this.positionList.push(position); @@ -412,6 +434,7 @@ struct Index { this.kvStoreModel.put(CommonConstants.CHANGE_POSITION, JSON.stringify(this.positionList)); } } + ... } ``` @@ -425,7 +448,9 @@ let storage = LocalStorage.getShared(); @Entry(storage) @Component struct Index { + ... @LocalStorageProp('positionList') positionList: Position[] = []; + ... build() { Column() { Row() { @@ -444,29 +469,13 @@ struct Index { ... } - // 撤回上一笔绘制 - goBack() { - if (this.positionList.length === 0) { - return; - } - // 移除位置信息直到位置起始位置 - for (let i: number = this.positionList.length - 1; i >= 0; i--) { - if (this.positionList[i].isFirstPosition) { - this.positionList.pop(); - break; - } else { - this.positionList.pop(); - } - } - this.redraw(); - this.kvStoreModel.put(CommonConstants.CHANGE_POSITION, JSON.stringify(this.positionList)); - } - - redraw() { + ... + redraw(): void { // 删除画布内的绘制内容 this.canvasContext.clearRect(0, 0, this.canvasContext.width, this.canvasContext.height); // 使用当前记录的位置信息,重新绘制 this.positionList.forEach((position) => { + ... if (position.isFirstPosition) { this.canvasContext.beginPath(); this.canvasContext.lineWidth = CommonConstants.CANVAS_LINE_WIDTH; @@ -480,6 +489,24 @@ struct Index { } }); } + + + // 撤回上一笔绘制 + goBack(): void { + if (this.positionList.length === 0) { + return; + } + // 移除位置信息直到位置起始位置 + for (let i: number = this.positionList.length - 1; i >= 0; i--) { + let position: Position | undefined = this.positionList.pop(); + if (position !== undefined && position.isFirstPosition) { + break; + } + } + this.redraw(); + this.kvStoreModel.put(CommonConstants.CHANGE_POSITION, JSON.stringify(this.positionList)); + } + ... } ``` @@ -491,19 +518,23 @@ struct Index { ``` typescript // Index.ets +... import KvStoreModel from '../viewmodel/KvStoreModel'; +... let storage = LocalStorage.getShared(); @Entry(storage) @Component struct Index { + ... private kvStoreModel: KvStoreModel = new KvStoreModel(); ... aboutToAppear() { + ... this.createKVStore(); } + ... createKVStore(): void { - this.context = getContext(this) as common.UIAbilityContext; // 创建分布式键值数据库 this.kvStoreModel.createKvStore(this.context, (data: distributedKVStore.ChangeNotification) => { // 使用分布式键值数据库内的内容重置位置信息列表 @@ -527,16 +558,20 @@ struct Index { ``` typescript // KvStoreModel.ets export default class KvStoreModel { - kvStore: distributedKVStore.SingleKVStore; ... - createKvStore(context: common.UIAbilityContext, callback: (data: distributedKVStore.ChangeNotification) => void): void { + kvStore?: distributedKVStore.SingleKVStore; + ... + createKvStore( + context: common.UIAbilityContext, + callback: (data: distributedKVStore.ChangeNotification) => void + ): void { ... try { // 创建一个KVManager对象实例,用于管理数据库对象 this.kvManager = distributedKVStore.createKVManager(config); } catch (error) { Logger.error('KvStoreModel', - `createKvStore createKVManager failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `createKvStore createKVManager failed, err=${JSON.stringify(error)}`); return; } @@ -544,6 +579,7 @@ export default class KvStoreModel { let options: distributedKVStore.Options = { ... kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION + ... }; // 获取分布式键值数据库 @@ -551,12 +587,16 @@ export default class KvStoreModel { ... this.kvStore = store; // 开启同步 - this.kvStore.enableSync(true); - // 订阅数据变更通知 + this.kvStore.enableSync(true).then(() => { + Logger.info('KvStoreModel', 'createKvStore enableSync success'); + }).catch((error: Error) => { + Logger.error('KvStoreModel', + `createKvStore enableSync fail, error=${JSON.stringify(error)}`); + }); this.setDataChangeListener(callback); - }).catch((error) => { + }).catch((error: Error) => { Logger.error('getKVStore', - `createKvStore getKVStore failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `createKvStore getKVStore failed, error=${JSON.stringify(error)}`); }) } ... @@ -568,7 +608,8 @@ export default class KvStoreModel { ``` typescript // KvStoreModel.ets export default class KvStoreModel { - kvStore: distributedKVStore.SingleKVStore; + ... + kvStore?: distributedKVStore.SingleKVStore; ... setDataChangeListener(callback: (data: distributedKVStore.ChangeNotification) => void): void { ... @@ -582,7 +623,7 @@ export default class KvStoreModel { }); } catch (error) { Logger.error('KvStoreModel', - `setDataChangeListener on('dataChange') failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `setDataChangeListener on('dataChange') failed, err=${JSON.stringify(error)}`); } } ... @@ -593,11 +634,14 @@ export default class KvStoreModel { ``` typescript // Index.ets +... import KvStoreModel from '../viewmodel/KvStoreModel'; +... let storage = LocalStorage.getShared(); @Entry(storage) @Component struct Index { + ... private kvStoreModel: KvStoreModel = new KvStoreModel(); ... aboutToDisappear() { @@ -608,7 +652,8 @@ struct Index { // KvStoreModel.ets export default class KvStoreModel { - kvStore: distributedKVStore.SingleKVStore; + ... + kvStore?: distributedKVStore.SingleKVStore; ... removeDataChangeListener(): void { ... @@ -617,20 +662,20 @@ export default class KvStoreModel { this.kvStore.off('dataChange'); } catch (error) { Logger.error('KvStoreModel', - `removeDataChangeListener off('dataChange') failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `removeDataChangeListener off('dataChange') failed, err=${JSON.stringify(error)}`); } } - ...} + ... +} ``` ## 总结 您已经完成了本次Codelab的学习,并了解到以下知识点: -1. 申请分布式相关权限的流程。 -2. 建立分布式连接的方法。 -3. Canvas组件的使用。 -4. 分布式键值数据库的使用。 +1. 申请分布式相关权限的流程。 +2. 建立分布式连接的方法。 +3. Canvas组件的使用。 +4. 分布式键值数据库的使用。 ![](figures/zh-cn_image_0000001635972445.gif) - diff --git a/Distributed/DistributeDraw/entry/src/main/ets/common/constants/CommonConstants.ets b/Distributed/DistributeDraw/entry/src/main/ets/common/constants/CommonConstants.ets index 1b2bcd6c218928149092dba4ea19f9ac3a4768b9..8bf771618606c42def62e6ff4af85afcad65d756 100644 --- a/Distributed/DistributeDraw/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/Distributed/DistributeDraw/entry/src/main/ets/common/constants/CommonConstants.ets @@ -13,6 +13,20 @@ * limitations under the License. */ +import deviceManager from '@ohos.distributedHardware.deviceManager'; + +export interface DeviceInfoInterface { + subscribeId: number, + device: deviceManager.DeviceInfo +} + +export interface AuthExtraInfoInterface { + targetPkgName: string, + appName: string, + appDescription: string, + business: string +} + /** * Common constants for all features. */ @@ -21,112 +35,90 @@ export default class CommonConstants { * KvStore key. */ static readonly CHANGE_POSITION: string = 'change_position'; - /** * KvStore id. */ static readonly KVSTORE_ID: string = 'draw_board_kvstore'; - /** * One hundred percent. */ static readonly FULL_PERCENT: string = '100%'; - /** * Icon margin left. */ static readonly ICON_MARGIN_LEFT: string = '6.7%'; - /** * Title height. */ static readonly TITLE_HEIGHT: string = '10%'; - /** * Number one. */ static readonly NUMBER_ONE: number = 1; - /** * Canvas line width. */ static readonly CANVAS_LINE_WIDTH: number = 4; - /** * Canvas line join. */ static readonly CANVAS_LINE_JOIN: 'bevel' | 'miter' | 'round' = 'miter'; - /** * Localhost name. */ static readonly LOCALHOST_NAME: string = '本机'; - /** * Font weight. */ static readonly FONT_WEIGHT_500: number = 500; - /** * Invalid Index. */ static readonly INVALID_INDEX: number = -1; - /** * Device name width. */ static readonly DEVICE_NAME_WIDTH: string = '78%'; - /** * Select icon width. */ static readonly SELECT_ICON_WIDTH: string = '8%'; - /** * Subscribe ID range. */ static readonly SUBSCRIBE_ID_RANGE: number = 65536; - /** * Ability name. */ static readonly ABILITY_NAME: string = 'EntryAbility'; - /** * Subscribe mode. */ static readonly SUBSCRIBE_MODE: number = 0xAA; - /** * Subscribe medium. */ static readonly SUBSCRIBE_MEDIUM: number = 0; - /** * Subscribe freq. */ static readonly SUBSCRIBE_FREQ: number = 2; - /** * Subscribe capability. */ static readonly SUBSCRIBE_CAPABILITY: number = 0; - /** * Auth type. */ static readonly AUTH_TYPE: number = 1; - /** * App description. */ static readonly APP_DESCRIPTION: string = 'Distribute Draw Ability'; - /** * Business type. */ static readonly BUSINESS_TYPE: string = '0'; - /** * Bundle name. */ diff --git a/Distributed/DistributeDraw/entry/src/main/ets/common/utils/Logger.ets b/Distributed/DistributeDraw/entry/src/main/ets/common/utils/Logger.ets index 01d1fce855fcbb89243a084cd414470bf24e1ec4..415aefa4d6021fdafa281758c05eea2f02a27721 100644 --- a/Distributed/DistributeDraw/entry/src/main/ets/common/utils/Logger.ets +++ b/Distributed/DistributeDraw/entry/src/main/ets/common/utils/Logger.ets @@ -42,19 +42,19 @@ export class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Distributed/DistributeDraw/entry/src/main/ets/common/utils/RemoteDeviceUtil.ets b/Distributed/DistributeDraw/entry/src/main/ets/common/utils/RemoteDeviceUtil.ets index 04fc2453d46139a688900fd3606ebfe1063a7258..f0c59b32a907deb58b755b12434062195e9c0c61 100644 --- a/Distributed/DistributeDraw/entry/src/main/ets/common/utils/RemoteDeviceUtil.ets +++ b/Distributed/DistributeDraw/entry/src/main/ets/common/utils/RemoteDeviceUtil.ets @@ -17,15 +17,21 @@ import deviceManager from '@ohos.distributedHardware.deviceManager'; import common from '@ohos.app.ability.common'; import Want from '@ohos.app.ability.Want'; import CommonConstants from '../constants/CommonConstants'; -import Position from '../bean/Position'; +import { DeviceInfoInterface, AuthExtraInfoInterface } from '../constants/CommonConstants'; +import Position from '../../viewmodel/Position'; import Logger from './Logger'; -class RemoteDeviceModel { - private static dmInstance: RemoteDeviceModel = null; - private myDeviceManager: deviceManager.DeviceManager = null; +interface RejectError { + code: number; + message: string; +} + +class RemoteDeviceUtil { + private static dmInstance: RemoteDeviceUtil | undefined = undefined; + private myDeviceManager?: deviceManager.DeviceManager; + private localDevice?: deviceManager.DeviceInfo; private deviceList: deviceManager.DeviceInfo[] = []; private trustedDeviceList: deviceManager.DeviceInfo[] = []; - private localDevice: deviceManager.DeviceInfo = null; private discoverList: deviceManager.DeviceInfo[] = []; private subscribeId: number = Math.floor(CommonConstants.SUBSCRIBE_ID_RANGE * Math.random()); @@ -34,42 +40,43 @@ class RemoteDeviceModel { * * @returns Class instance. */ - static getInstance(): RemoteDeviceModel { - if (this.dmInstance === null) { - this.dmInstance = new RemoteDeviceModel(); + static getInstance(): RemoteDeviceUtil { + if (RemoteDeviceUtil.dmInstance === undefined) { + RemoteDeviceUtil.dmInstance = new RemoteDeviceUtil(); } - return this.dmInstance; + return RemoteDeviceUtil.dmInstance; } /** * Create a device manager. */ async createDeviceManager() { - if (this.myDeviceManager !== null) { + if (this.myDeviceManager !== undefined) { Logger.info('RemoteDeviceModel', 'createDeviceManager myDeviceManager exist'); return; } - await new Promise((resolve, reject) => { + await new Promise((resolve: (value: Object | PromiseLike) => void, reject: ((reason?: RejectError) => void)) => { try { - deviceManager.createDeviceManager(CommonConstants.BUNDLE_NAME, (error, value) => { - if (error) { - reject(error); - Logger.error('RemoteDeviceModel', - `createDeviceManager failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); - return; - } - this.myDeviceManager = value; - // Registered trusted device online and offline listening. - this.registerDeviceStateListener(); - this.getLocalDeviceInfo(); - this.getTrustedDeviceList(); - this.initDeviceList(); - resolve(value); - }); + deviceManager.createDeviceManager(CommonConstants.BUNDLE_NAME, + (error, value: deviceManager.DeviceManager) => { + if (error) { + reject(error); + Logger.error('RemoteDeviceModel', + `createDeviceManager failed, error=${JSON.stringify(error)}`); + return; + } + this.myDeviceManager = value; + // Registered trusted device online and offline listening. + this.registerDeviceStateListener(); + this.getLocalDeviceInfo(); + this.getTrustedDeviceList(); + this.initDeviceList(); + resolve(value); + }); } catch (error) { Logger.error('RemoteDeviceModel', - `createDeviceManager failed, error code=${error.code}, msg=${JSON.stringify(error.message)}`); + `createDeviceManager failed, error=${JSON.stringify(error)}`); } }); } @@ -78,7 +85,7 @@ class RemoteDeviceModel { * Obtains local device information. */ getLocalDeviceInfo(): void { - if (this.myDeviceManager === null) { + if (this.myDeviceManager === undefined) { Logger.error('RemoteDeviceModel', 'getLocalDeviceInfo deviceManager has not initialized'); return; } @@ -88,7 +95,7 @@ class RemoteDeviceModel { this.localDevice.deviceName = CommonConstants.LOCALHOST_NAME; } catch (error) { Logger.error('RemoteDeviceModel', - `getLocalDeviceInfo failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `getLocalDeviceInfo failed, error=${JSON.stringify(error)}`); } } @@ -96,7 +103,7 @@ class RemoteDeviceModel { * Obtain the list of trusted devices. */ getTrustedDeviceList(): void { - if (this.myDeviceManager === null) { + if (this.myDeviceManager === undefined) { Logger.error('RemoteDeviceModel', 'getTrustedDeviceList deviceManager has not initialized'); return; } @@ -105,7 +112,7 @@ class RemoteDeviceModel { this.trustedDeviceList = this.myDeviceManager.getTrustedDeviceListSync(); } catch (error) { Logger.error('RemoteDeviceModel', - `getTrustedDeviceList failed code=${error.code}, msg=${JSON.stringify(error.message)}`); + `getTrustedDeviceList failed error=${JSON.stringify(error)}`); } } @@ -114,7 +121,9 @@ class RemoteDeviceModel { */ initDeviceList(): void { this.deviceList = []; - this.addToDeviceList(this.localDevice) + if (this.localDevice !== undefined) { + this.addToDeviceList(this.localDevice) + } this.trustedDeviceList.forEach((item: deviceManager.DeviceInfo) => { this.addToDeviceList(item); }) @@ -124,7 +133,7 @@ class RemoteDeviceModel { * Register the device status listener. */ registerDeviceStateListener(): void { - if (this.myDeviceManager === null) { + if (this.myDeviceManager === undefined) { Logger.error('RemoteDeviceModel', 'registerDeviceStateListener deviceManager has not initialized'); return; } @@ -151,7 +160,7 @@ class RemoteDeviceModel { }); } catch (error) { Logger.error('RemoteDeviceModel', - `registerDeviceStateListener on('deviceStateChange') failed, code=${error.code}, msg=${error.message}`); + `registerDeviceStateListener on('deviceStateChange') failed, error=${JSON.stringify(error)}`); } } @@ -186,7 +195,7 @@ class RemoteDeviceModel { * Disabling the listening event. */ unregisterDeviceListCallback(): void { - if (this.myDeviceManager === null) { + if (this.myDeviceManager === undefined) { Logger.error('RemoteDeviceModel', 'unregisterDeviceListCallback deviceManager has not initialized'); return; } @@ -196,7 +205,7 @@ class RemoteDeviceModel { this.myDeviceManager.release(); } catch (err) { Logger.error('RemoteDeviceModel', - `unregisterDeviceListCallback stopDeviceDiscovery failed, code=${err.code}, msg=${err.message}`); + `unregisterDeviceListCallback stopDeviceDiscovery failed, error=${JSON.stringify(err)}`); } } @@ -218,23 +227,23 @@ class RemoteDeviceModel { return; } - if (this.myDeviceManager === null) { + if (this.myDeviceManager === undefined) { Logger.error('RemoteDeviceModel', 'authenticateDevice deviceManager has not initialized'); return; } - let extraInfo = { - 'targetPkgName': context.abilityInfo.bundleName, - 'appName': context.abilityInfo.applicationInfo.name, - 'appDescription': CommonConstants.APP_DESCRIPTION, - 'business': CommonConstants.BUSINESS_TYPE + let extraInfo: AuthExtraInfoInterface = { + targetPkgName: context.abilityInfo.bundleName, + appName: context.abilityInfo.applicationInfo.name, + appDescription: CommonConstants.APP_DESCRIPTION, + business: CommonConstants.BUSINESS_TYPE }; let authParam: deviceManager.AuthParam = { 'authType': CommonConstants.AUTH_TYPE, 'extraInfo': extraInfo }; try { - this.myDeviceManager.authenticateDevice(device, authParam, (err, data) => { + this.myDeviceManager.authenticateDevice(device, authParam, (err) => { if (err) { Logger.error('RemoteDeviceModel', `authenticateDevice error code=${err.code}, msg=${JSON.stringify(err.message)}`); @@ -243,7 +252,7 @@ class RemoteDeviceModel { }) } catch (error) { Logger.error('RemoteDeviceModel', - `authenticateDevice failed code=${error.code}, msg=${JSON.stringify(error.message)}`); + `authenticateDevice failed error=${JSON.stringify(error)}`); } } @@ -266,8 +275,8 @@ class RemoteDeviceModel { context.startAbility(wantValue).then(() => { Logger.info('RemoteDeviceModel', `startAbility finished wantValue=${JSON.stringify(wantValue)}`); - }).catch((error) => { - Logger.error('RemoteDeviceModel', `startAbility failed,code=${error.code},msg=${JSON.stringify(error.message)}`); + }).catch((error: Error) => { + Logger.error('RemoteDeviceModel', `startAbility failed, error=${JSON.stringify(error)}`); }) } @@ -276,7 +285,7 @@ class RemoteDeviceModel { * * @param data Device information. */ - deviceFound(data): void { + deviceFound(data: DeviceInfoInterface): void { for (let i: number = 0; i < this.discoverList.length; i++) { if (this.discoverList[i].deviceId === data.device.deviceId) { Logger.info('RemoteDeviceModel', `deviceFound device exist=${JSON.stringify(data)}`); @@ -293,7 +302,7 @@ class RemoteDeviceModel { startDeviceDiscovery(): void { this.discoverList = []; this.initDeviceList(); - if (this.myDeviceManager === null) { + if (this.myDeviceManager === undefined) { Logger.error('RemoteDeviceModel', 'startDeviceDiscovery deviceManager has not initialized'); return; } @@ -326,7 +335,7 @@ class RemoteDeviceModel { this.myDeviceManager.startDeviceDiscovery(info); } catch (error) { Logger.error('RemoteDeviceModel', - `startDeviceDiscovery failed code=${error.code}, msg=${JSON.stringify(error.message)}`); + `startDeviceDiscovery failed error=${JSON.stringify(error)}`); } } @@ -334,7 +343,7 @@ class RemoteDeviceModel { * Stop discovering devices. */ stopDeviceDiscovery(): void { - if (this.myDeviceManager === null) { + if (this.myDeviceManager === undefined) { Logger.error('RemoteDeviceModel', 'stopDeviceDiscovery deviceManager has not initialized'); return; } @@ -345,7 +354,7 @@ class RemoteDeviceModel { this.myDeviceManager.off('discoverFail'); } catch (error) { Logger.error('RemoteDeviceModel', - `stopDeviceDiscovery failed code=${error.code}, msg=${JSON.stringify(error.message)}`); + `stopDeviceDiscovery failed error=${JSON.stringify(error)}`); } } @@ -386,4 +395,4 @@ class RemoteDeviceModel { } } -export default RemoteDeviceModel.getInstance(); \ No newline at end of file +export default RemoteDeviceUtil.getInstance(); \ No newline at end of file diff --git a/Distributed/DistributeDraw/entry/src/main/ets/entryability/EntryAbility.ets b/Distributed/DistributeDraw/entry/src/main/ets/entryability/EntryAbility.ets index a983c7e7ea377cd98d1d46288b3fd568b284cbf7..e7e29be024c320f2a611a9f2eeb9bed98b64bb8c 100644 --- a/Distributed/DistributeDraw/entry/src/main/ets/entryability/EntryAbility.ets +++ b/Distributed/DistributeDraw/entry/src/main/ets/entryability/EntryAbility.ets @@ -19,19 +19,19 @@ import Want from '@ohos.app.ability.Want'; import window from '@ohos.window'; import bundleManager from '@ohos.bundle.bundleManager'; import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; +import common from '@ohos.app.ability.common'; import Logger from '../common/utils/Logger'; import remoteDeviceModel from '../common/utils/RemoteDeviceUtil'; -import Position from '../common/bean/Position'; +import Position from '../viewmodel/Position'; const permissions: Array = ['ohos.permission.DISTRIBUTED_DATASYNC']; export default class EntryAbility extends UIAbility { storage: LocalStorage = new LocalStorage(); - want: Want; + want?: Want; onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { this.want = want; - globalThis.context = this.context; Logger.info('EntryAbility', `onCreate want=${JSON.stringify(this.want)}, launchParam=${JSON.stringify(launchParam)}`); remoteDeviceModel.createDeviceManager(); @@ -57,12 +57,12 @@ export default class EntryAbility extends UIAbility { onWindowStageCreate(windowStage: window.WindowStage) { Logger.info('EntryAbility', 'onWindowStageCreate start'); - if (this.want?.parameters?.positionList) { + if (this?.want?.parameters?.positionList) { let positionList: Position[] = JSON.parse((this.want.parameters.positionList) as string); this.storage.setOrCreate('positionList', positionList); } - checkPermissions(); + checkPermissions(this.context); try { windowStage.loadContent('pages/Index', this.storage, (err) => { @@ -74,8 +74,7 @@ export default class EntryAbility extends UIAbility { Logger.info('EntryAbility', 'onWindowStageCreate Succeeded in loading the content'); }); } catch (error) { - Logger.error('EntryAbility', - `onWindowStageCreate failed. code=${error.code}, msg=${JSON.stringify(error.message)}`); + Logger.error('EntryAbility', `onWindowStageCreate failed. err=${JSON.stringify(error)}`); } } } @@ -83,12 +82,12 @@ export default class EntryAbility extends UIAbility { /** * Check the permission status. */ -async function checkPermissions() { +async function checkPermissions(context: common.UIAbilityContext) { let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(); if (grantStatus !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { // Applying for the distributed data synchronization permission. let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); - atManager.requestPermissionsFromUser(globalThis.context, permissions).then((data) => { + atManager.requestPermissionsFromUser(context, permissions).then((data) => { let grantStatus: Array = data.authResults; let length: number = grantStatus.length; for (let i: number = 0; i < length; i++) { @@ -100,9 +99,9 @@ async function checkPermissions() { return; } } - }).catch((err) => { + }).catch((err: Error) => { Logger.error('EntryAbility', - `checkPermissions request permissions failed, code=${err.code}, msg=${JSON.stringify(err.message)}`); + `checkPermissions request permissions failed, err=${JSON.stringify(err)}`); }) } } @@ -114,7 +113,7 @@ async function checkPermissions() { */ async function checkAccessToken() { let atManager = abilityAccessCtrl.createAtManager(); - let tokenId: number; + let tokenId: number = 0; try { let bundleInfo: bundleManager.BundleInfo = await bundleManager .getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); @@ -122,7 +121,7 @@ async function checkAccessToken() { tokenId = appInfo.accessTokenId; } catch (err) { Logger.error('EntryAbility', - `checkAccessToken Failed to get bundle info for self. code is ${err.code}, message is ${err.message}`); + `checkAccessToken Failed to get bundle info for self. err=${JSON.stringify(err)}`); } let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED; @@ -130,7 +129,7 @@ async function checkAccessToken() { grantStatus = await atManager.checkAccessToken(tokenId, 'ohos.permission.DISTRIBUTED_DATASYNC'); } catch (err) { Logger.error('EntryAbility', - `checkAccessToken Failed to check access token. code is ${err.code}, message is ${err.message}`); + `checkAccessToken Failed to check access token. err=${JSON.stringify(err)}`); } return grantStatus; diff --git a/Distributed/DistributeDraw/entry/src/main/ets/pages/Index.ets b/Distributed/DistributeDraw/entry/src/main/ets/pages/Index.ets index 2178f95a2f626610484eafc63e215cbd5cacfc82..fd2618ae9864ee20d3962c9757ecef891a81f64f 100644 --- a/Distributed/DistributeDraw/entry/src/main/ets/pages/Index.ets +++ b/Distributed/DistributeDraw/entry/src/main/ets/pages/Index.ets @@ -17,7 +17,7 @@ import common from '@ohos.app.ability.common'; import distributedKVStore from '@ohos.data.distributedKVStore'; import deviceManager from '@ohos.distributedHardware.deviceManager'; import CommonConstants from '../common/constants/CommonConstants'; -import Position from '../common/bean/Position'; +import Position from '../viewmodel/Position'; import KvStoreModel from '../viewmodel/KvStoreModel'; import remoteDeviceModel from '../common/utils/RemoteDeviceUtil'; import DeviceListDialogComponent from '../view/CustomDialogComponent'; @@ -34,7 +34,7 @@ struct Index { private settings: RenderingContextSettings = new RenderingContextSettings(true); private canvasContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); private kvStoreModel: KvStoreModel = new KvStoreModel(); - private context: common.UIAbilityContext = null; + private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; private dialogController: CustomDialogController = new CustomDialogController({ builder: DeviceListDialogComponent({ startAbility: this.startAbilityContinuation, @@ -119,7 +119,6 @@ struct Index { * Create a distributed key-value database. */ createKVStore(): void { - this.context = getContext(this) as common.UIAbilityContext; this.kvStoreModel.createKvStore(this.context, (data: distributedKVStore.ChangeNotification) => { this.positionList = []; let entries: distributedKVStore.Entry[] = data.insertEntries.length > 0 ? data.insertEntries : data.updateEntries; @@ -166,8 +165,8 @@ struct Index { } for (let i: number = this.positionList.length - 1; i >= 0; i--) { - let position: Position = this.positionList.pop(); - if (position.isFirstPosition) { + let position: Position | undefined = this.positionList.pop(); + if (position !== undefined && position.isFirstPosition) { break; } } @@ -181,8 +180,8 @@ struct Index { * @param event Touch event. */ onTouchEvent(event: TouchEvent): void { - let positionX:number = event.touches[0].x; - let positionY:number = event.touches[0].y; + let positionX: number = event.touches[0].x; + let positionY: number = event.touches[0].y; switch (event.type) { case TouchType.Down: { this.canvasContext.beginPath(); @@ -217,7 +216,7 @@ struct Index { * @param positionX Horizontal coordinate information. * @param positionY Indicates the vertical coordinate information. */ - pushData(isFirstPosition: boolean, isEndPosition, positionX: number, positionY: number): void { + pushData(isFirstPosition: boolean, isEndPosition: boolean, positionX: number, positionY: number): void { let position = new Position(isFirstPosition, isEndPosition, positionX, positionY); this.positionList.push(position); if (position.isEndPosition) { diff --git a/Distributed/DistributeDraw/entry/src/main/ets/view/CustomDialogComponent.ets b/Distributed/DistributeDraw/entry/src/main/ets/view/CustomDialogComponent.ets index 28269369fcec7dd5555116b5f753db6ed753ebb8..a244e7f422f288833a5514c747fb226fa6e1feff 100644 --- a/Distributed/DistributeDraw/entry/src/main/ets/view/CustomDialogComponent.ets +++ b/Distributed/DistributeDraw/entry/src/main/ets/view/CustomDialogComponent.ets @@ -17,9 +17,10 @@ import common from '@ohos.app.ability.common'; import deviceManager from '@ohos.distributedHardware.deviceManager'; import prompt from '@ohos.promptAction'; import CommonConstants from '../common/constants/CommonConstants'; -import Position from '../common/bean/Position'; +import Position from '../viewmodel/Position'; -@Extend(Text) function ButtonTextStyle() { +@Extend(Text) +function ButtonTextStyle() { .fontColor($r('app.color.button_text_color')) .fontSize($r('app.float.button_font_size')) .fontWeight(CommonConstants.FONT_WEIGHT_500) @@ -30,9 +31,10 @@ export default struct DeviceListDialogComponent { @State selectedIndex: number = CommonConstants.INVALID_INDEX; @Link positionList: Position[]; @Link deviceList: deviceManager.DeviceInfo[]; - controller: CustomDialogController = null; - startAbility: (context: common.UIAbilityContext,device: deviceManager.DeviceInfo, positionList: Position[]) => void; - cancel: () => void; + controller?: CustomDialogController; + startAbility: (context: common.UIAbilityContext, device: deviceManager.DeviceInfo, positionList: Position[]) => void + = () => {}; + cancel: () => void = () => {}; build() { Column() { @@ -112,7 +114,7 @@ export default struct DeviceListDialogComponent { } } } - }, (item) => item.deviceId ) + }, (item: deviceManager.DeviceInfo) => item.deviceId) } .width(CommonConstants.FULL_PERCENT) @@ -125,7 +127,9 @@ export default struct DeviceListDialogComponent { .justifyContent(FlexAlign.Center) .height($r('app.float.button_line_height')) .onClick(() => { - this.controller.close(); + if (this.controller !== undefined) { + this.controller.close(); + } this.cancel(); }) @@ -148,7 +152,9 @@ export default struct DeviceListDialogComponent { message: $r('app.string.please_select_device') }); } else { - this.controller.close(); + if (this.controller !== undefined) { + this.controller.close(); + } this.startAbility(getContext(this) as common.UIAbilityContext, this.deviceList[this.selectedIndex], this.positionList); } @@ -170,7 +176,7 @@ export default struct DeviceListDialogComponent { * @param deviceType Device type. * @returns Icon resource. */ - getDeviceTypeIcon(deviceType): Resource { + getDeviceTypeIcon(deviceType: deviceManager.DeviceType): Resource { if ((deviceType === deviceManager.DeviceType.PHONE) || (deviceType === deviceManager.DeviceType.UNKNOWN_TYPE)) { return $r('app.media.ic_public_devices_phone'); } else if (deviceType === deviceManager.DeviceType.TV) { diff --git a/Distributed/DistributeDraw/entry/src/main/ets/viewmodel/KvStoreModel.ets b/Distributed/DistributeDraw/entry/src/main/ets/viewmodel/KvStoreModel.ets index c42e5068f71bf997e7229fb7b65c904889291202..ac4721a7361a80137f3b5ff5d12023fd43b0956f 100644 --- a/Distributed/DistributeDraw/entry/src/main/ets/viewmodel/KvStoreModel.ets +++ b/Distributed/DistributeDraw/entry/src/main/ets/viewmodel/KvStoreModel.ets @@ -19,8 +19,8 @@ import CommonConstants from '../common/constants//CommonConstants'; import Logger from '../common/utils/Logger'; export default class KvStoreModel { - kvManager: distributedKVStore.KVManager = null; - kvStore: distributedKVStore.SingleKVStore = null; + kvManager?: distributedKVStore.KVManager; + kvStore?: distributedKVStore.SingleKVStore; /** * Create a distributed key-value database. @@ -32,7 +32,7 @@ export default class KvStoreModel { context: common.UIAbilityContext, callback: (data: distributedKVStore.ChangeNotification) => void ): void { - if (this.kvStore !== null) { + if (this.kvStore !== undefined) { Logger.info('KvStoreModel', 'createKvStore KVManager is exist'); return; } @@ -45,7 +45,7 @@ export default class KvStoreModel { this.kvManager = distributedKVStore.createKVManager(config); } catch (error) { Logger.error('KvStoreModel', - `createKvStore createKVManager failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `createKvStore createKVManager failed, err=${JSON.stringify(error)}`); return; } @@ -66,14 +66,14 @@ export default class KvStoreModel { this.kvStore = store; this.kvStore.enableSync(true).then(() => { Logger.info('KvStoreModel', 'createKvStore enableSync success'); - }).catch((error) => { + }).catch((error: Error) => { Logger.error('KvStoreModel', - `createKvStore enableSync fail, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `createKvStore enableSync fail, error=${JSON.stringify(error)}`); }); this.setDataChangeListener(callback); - }).catch((error) => { + }).catch((error: Error) => { Logger.error('getKVStore', - `createKvStore getKVStore failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `createKvStore getKVStore failed, error=${JSON.stringify(error)}`); }) } @@ -84,15 +84,15 @@ export default class KvStoreModel { * @param value Store value. */ put(key: string, value: string): void { - if (this.kvStore === null) { + if (this.kvStore === undefined) { return; } this.kvStore.put(key, value).then(() => { Logger.info('KvStoreModel', `kvStore.put key=${key} finished}`); - }).catch((error) => { + }).catch((error: Error) => { Logger.error('KvStoreModel', - `kvStore.put key=${key} failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `kvStore.put key=${key} failed, error=${JSON.stringify(error)}`); }); } @@ -102,7 +102,7 @@ export default class KvStoreModel { * @param callback Callback. */ setDataChangeListener(callback: (data: distributedKVStore.ChangeNotification) => void): void { - if (this.kvStore === null) { + if (this.kvStore === undefined) { Logger.error('KvStoreModel', 'setDataChangeListener kvStore is null'); return; } @@ -116,7 +116,7 @@ export default class KvStoreModel { }); } catch (error) { Logger.error('KvStoreModel', - `setDataChangeListener on('dataChange') failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `setDataChangeListener on('dataChange') failed, err=${JSON.stringify(error)}`); } } @@ -124,7 +124,7 @@ export default class KvStoreModel { * Remove the data change listener. */ removeDataChangeListener(): void { - if (this.kvStore === null) { + if (this.kvStore === undefined) { return; } @@ -132,7 +132,7 @@ export default class KvStoreModel { this.kvStore.off('dataChange'); } catch (error) { Logger.error('KvStoreModel', - `removeDataChangeListener off('dataChange') failed, code=${error.code}, msg=${JSON.stringify(error.message)}`); + `removeDataChangeListener off('dataChange') failed, err=${JSON.stringify(error)}`); } } } \ No newline at end of file diff --git a/Distributed/DistributeDraw/entry/src/main/ets/common/bean/Position.ets b/Distributed/DistributeDraw/entry/src/main/ets/viewmodel/Position.ets similarity index 91% rename from Distributed/DistributeDraw/entry/src/main/ets/common/bean/Position.ets rename to Distributed/DistributeDraw/entry/src/main/ets/viewmodel/Position.ets index 34387ff3ec9ef0f26db98c5e27bd82e175edbcd0..b4b5e631ded11cb5d29a4bf1daf776aaa18ebbac 100644 --- a/Distributed/DistributeDraw/entry/src/main/ets/common/bean/Position.ets +++ b/Distributed/DistributeDraw/entry/src/main/ets/viewmodel/Position.ets @@ -34,7 +34,7 @@ export default class Position { */ positionY: number; - constructor(isFirstPosition: boolean, isEndPosition, positionX: number, positionY: number) { + constructor(isFirstPosition: boolean, isEndPosition: boolean, positionX: number, positionY: number) { this.isFirstPosition = isFirstPosition; this.isEndPosition = isEndPosition; this.positionX = positionX; diff --git a/Distributed/DistributeDraw/figures/zh-cn_image_0000001621561354.png b/Distributed/DistributeDraw/figures/zh-cn_image_0000001621561354.png index 5f5952c218ac04352c724c51093072329037fe42..9ffb47da313e78b1738910300e521b0540ac8a93 100644 Binary files a/Distributed/DistributeDraw/figures/zh-cn_image_0000001621561354.png and b/Distributed/DistributeDraw/figures/zh-cn_image_0000001621561354.png differ diff --git a/Distributed/DistributeDraw/hvigor/hvigor-config.json5 b/Distributed/DistributeDraw/hvigor/hvigor-config.json5 index 28f85c1467c07bcebd848b16b46348ffc6761057..f31dbccda9d78de1a2b9b0a158ef82ce145e88f6 100644 --- a/Distributed/DistributeDraw/hvigor/hvigor-config.json5 +++ b/Distributed/DistributeDraw/hvigor/hvigor-config.json5 @@ -2,5 +2,8 @@ "hvigorVersion": "2.3.0", "dependencies": { "@ohos/hvigor-ohos-plugin": "2.3.0" - } + }, + "execution": {}, + "logging": {}, + "debugging": {} } \ No newline at end of file diff --git a/Distributed/DistributedNewsClient/README.md b/Distributed/DistributedNewsClient/README.md index cf583105ac6ddfd8113f1c334b3f5f3cde1eaf47..9cee8fb43e1b80f182bd9a932ca16c0845eb596d 100644 --- a/Distributed/DistributedNewsClient/README.md +++ b/Distributed/DistributedNewsClient/README.md @@ -36,13 +36,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 10及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 4.0 Beta2。 +- OpenHarmony SDK版本:API version 10。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:4.0 Beta1及以上版本。 +- OpenHarmony系统:4.0 Beta1。 ### 环境搭建 @@ -68,13 +68,10 @@ ```txt ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ └──NewsData.ets // 新闻数据类 │ │ ├──constants │ │ │ └──CommonConstants.ets // 常量类 │ │ └──utils -│ │ ├──Logger.ets // 日志工具类 -│ │ └──PromptUtil.ets // 弹窗工具类 +│ │ └──Logger.ets // 日志工具类 │ ├──entryability │ │ └──EntryAbility.ets // 程序入口类 │ ├──model @@ -105,7 +102,7 @@ export default struct NewsTab { @State currentIndex: number = 0; @State currentBreakpoint: string = CommonConstants.BREAKPOINT_SM; - private newsItems: NewsData[]; + private newsItems: NewsData[] = []; // 自定义页签栏 @Builder TabBuilder(title: Resource, index: number) { @@ -133,7 +130,7 @@ export default struct NewsTab { NewsList({ newsItems: NewsDataModel.getNewsByType(this.newsItems, title) }) } .tabBar(this.TabBuilder(NewsDataModel.getTypeByStr(title), index)) - }, (title, index) => index + JSON.stringify(title)) + }, (title: string, index: number) => index + JSON.stringify(title)) } .barHeight($r('app.float.news_tab_bar_height')) .barWidth(CommonConstants.FULL_COMPONENT) @@ -148,7 +145,7 @@ export default struct NewsTab { // NewsList.ets @Component export default struct NewsList { - private newsItems: NewsData[]; + private newsItems: NewsData[] = []; build() { List() { @@ -186,7 +183,7 @@ export default struct NewsList { } } } - }, (item, index) => index + JSON.stringify(item)) + }, (item: NewsData, index: number) => index + JSON.stringify(item)) } .height(CommonConstants.FULL_COMPONENT) } @@ -262,7 +259,7 @@ build() { .color($r('app.color.detail_divider_color')) .width(CommonConstants.FULL_COMPONENT) - //栅格布局 + // 栅格布局 GridRow({ columns: { sm: CommonConstants.FOUR_COLUMN, @@ -335,7 +332,7 @@ build() { ListItem() { ... } - }, (item, index) => index + JSON.stringify(item)) + }, (item: deviceManager.DeviceInfo) => JSON.stringify(item.deviceId)) } Row() { @@ -354,7 +351,7 @@ build() { ListItem() { ... } - }, (item, index) => index + JSON.stringify(item)) + }, (item: deviceManager.DeviceInfo) => JSON.stringify(item.deviceId)) } Row() { @@ -383,19 +380,20 @@ build() { ```typescript // EntryAbility.ets -onCreate(want) { +onCreate(want: Want) { ... // 创建设备管理器 - RemoteDeviceModel.createDeviceManager(); + RemoteDeviceModel.createDeviceManager(this.context); } // RemoteDeviceModel.ets -async createDeviceManager(): Promise { +async createDeviceManager(context: common.UIAbilityContext): Promise { if (this.deviceManager !== undefined) { return; } - await new Promise((resolve, reject) => { - deviceManager.createDeviceManager(this.context.abilityInfo.bundleName, (err, value) => { + await new Promise((resolve: (value: Object | PromiseLike) => void, reject: + ((reason?: RejectError) => void)) => { + deviceManager.createDeviceManager(context.abilityInfo.bundleName, (err, value) => { if (err) { reject(err); logger.error('createDeviceManager failed.'); @@ -449,12 +447,12 @@ startDeviceDiscovery(): void { }; // 添加设备至发现列表 this.discoverList = []; - AppStorage.SetOrCreate(CommonConstants.DISCOVER_DEVICE_LIST, this.discoverList); + AppStorage.setOrCreate(CommonConstants.DISCOVER_DEVICE_LIST, this.discoverList); try { this.deviceManager.startDeviceDiscovery(info); } catch (err) { - logger.error(`startDeviceDiscovery failed. Code is ${err.code}, message is ${err.message}`); + logger.error(`startDeviceDiscovery failed error = ${JSON.stringify(err)}`); } } ``` @@ -476,11 +474,11 @@ authenticateDevice(device: deviceManager.DeviceInfo, context: common.UIAbilityCo if (this.discoverList[i].deviceId !== device.deviceId) { continue; } - let extraInfo: any = { - 'targetPkgName': context.abilityInfo.bundleName, - 'appName': context.applicationInfo.name, - 'appDescription': context.applicationInfo.description, - 'business': CommonConstants.ZERO + let extraInfo: AuthExtraInfoInterface = { + targetPkgName: context.abilityInfo.bundleName, + appName: context.applicationInfo.name, + appDescription: context.applicationInfo.description, + business: CommonConstants.ZERO }; let authParam: deviceManager.AuthParam = { 'authType': CommonConstants.ONE, @@ -495,7 +493,7 @@ authenticateDevice(device: deviceManager.DeviceInfo, context: common.UIAbilityCo } }) } catch (err) { - logger.error(`authenticateDevice failed. Code is ${err.code}, message is ${err.message}`); + logger.error(`authenticateDevice failed error = ${JSON.stringify(err)}`); } } } @@ -513,13 +511,12 @@ function startAbilityContinuation(deviceId: string, newsId: string, context: com bundleName: context.abilityInfo.bundleName, abilityName: CommonConstants.ABILITY_NAME, parameters: { - 'url': CommonConstants.NEWS_DETAIL_PAGE, - 'newsId': newsId + newsId: newsId } }; // 拉起应用 - globalThis.context.startAbility(want).catch((err) => { - Logger.error(`startAbilityContinuation error. Code is ${err.code}, message is ${err.message}`); + context.startAbility(want).catch((err: Error) => { + Logger.error(`startAbilityContinuation failed error = ${JSON.stringify(err)}`); prompt.showToast({ message: $r('app.string.start_ability_continuation_error') }); @@ -528,15 +525,13 @@ function startAbilityContinuation(deviceId: string, newsId: string, context: com // NewsDetail.ets aboutToAppear() { - const params: any = router.getParams(); - if (params) { - ... - } else { - // 读取跨设备传递的参数信息 - const want = globalThis.newWant; - const newsId = want.parameters.newsId; - this.newsData = this.newsItems.filter(item => (item.newsId === newsId))[0]; + let newsId: string | undefined = AppStorage.get('wantNewsId'); + if (newsId === undefined) { + this.newsData = (router.getParams() as Record)['newsItem']; + return; } + // 读取跨设备传递的参数信息 + this.newsData = this.newsItems.filter((item: NewsData) => (item.newsId === newsId))[0]; } ``` diff --git a/Distributed/DistributedNewsClient/entry/oh-package.json5 b/Distributed/DistributedNewsClient/entry/oh-package.json5 index 225946cb11a2c405c8dc81eea89c22f923556638..f18954a32b5a92fe55665dfcb3b63412a2a45963 100644 --- a/Distributed/DistributedNewsClient/entry/oh-package.json5 +++ b/Distributed/DistributedNewsClient/entry/oh-package.json5 @@ -6,5 +6,6 @@ "description": "Please describe the basic information.", "main": "", "version": "1.0.0", + "dynamicDependencies": {}, "dependencies": {} } diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/common/bean/NewsData.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/common/bean/NewsData.ets deleted file mode 100644 index 3537cdfc836e09ea506a4ce395f4ff16b4636de0..0000000000000000000000000000000000000000 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/common/bean/NewsData.ets +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export class NewsData { - /** - * The Id of news. - */ - newsId: string; - - /** - * The title of news. - */ - title: Resource; - - /** - * The type string of news. - */ - newsTypeStr: string; - - /** - * The type of news. - */ - newsType: Resource; - - /** - * The image url of news. - */ - imgUrl: Resource; - - /** - * The reads of news. - */ - reads: string; - - /** - * The likes of news. - */ - likes: string; - - /** - * The content of news. - */ - content: Resource; - - /** - * The label of news. - */ - label: Resource; - - /** - * The color of label. - */ - redLabel: boolean; - - /** - * The from of news. - */ - from: Resource; - - constructor(newsId: string, title: Resource, newsTypeStr: string, newsType: Resource, imgUrl: Resource, reads: string, - likes: string, content: Resource, label: Resource, redLabel: boolean, from: Resource) { - this.newsId = newsId; - this.title = title; - this.newsTypeStr = newsTypeStr; - this.newsType = newsType; - this.imgUrl = imgUrl; - this.reads = reads; - this.likes = likes; - this.content = content; - this.label = label; - this.redLabel = redLabel; - this.from = from; - } -} \ No newline at end of file diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/common/utils/Logger.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/common/utils/Logger.ets index ae92ac9d97dbe89dc30d6eba2f9a70344275512d..0c6b064d033e0fc0bc25d04e588c443871d6f6d8 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/common/utils/Logger.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/common/utils/Logger.ets @@ -16,29 +16,47 @@ import hilog from '@ohos.hilog'; export class Logger { + /** + * Indicates the log color + */ private domain: number; + + /** + * Indicates the log prefix string. + */ private prefix: string; + + /** + * Indicates the log format string. + */ private format: string = '%{public}s, %{public}s'; - constructor(prefix: string = 'MyApp', domain: number = 0xFF00) { + /** + * Constructor. + * + * @param prefix Identifies the log tag. + * @param domain Indicates the service domain, which is a hexadecimal integer ranging from 0x0 to 0xFFFFF. + */ + constructor(prefix: string = 'DistributeNews', domain: number = 0xFF00) { this.prefix = prefix; this.domain = domain; } - debug(...args: any[]) { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]) { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]) { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]) { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } + export default new Logger(); \ No newline at end of file diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/entryability/EntryAbility.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/entryability/EntryAbility.ets index ea396fcdec3a77d9619181d3c4730f8ecca110bb..23cebfa296f72e839e63242fd41d6bd7f9cc7c82 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/entryability/EntryAbility.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/entryability/EntryAbility.ets @@ -17,19 +17,31 @@ import UIAbility from '@ohos.app.ability.UIAbility'; import window from '@ohos.window'; import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; import bundleManager from '@ohos.bundle.bundleManager'; +import Want from '@ohos.app.ability.Want'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; import RemoteDeviceModel from '../model/RemoteDeviceModel'; import logger from '../common/utils/Logger'; +import common from '@ohos.app.ability.common'; + +const permissions: Array = ['ohos.permission.DISTRIBUTED_DATASYNC']; export default class EntryAbility extends UIAbility { - onNewWant(want, launchParams) { - globalThis.newWant = want; - logger.info(` onNewWant launchParam: ${JSON.stringify(launchParams) ?? ''}`); - this.onWindowStageCreate(globalThis.windowStage); + private want: Want | undefined = undefined; + private windowStage?: window.WindowStage; + + onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam) { + this.want = want; + AppStorage.setOrCreate('wantNewsId', (want.parameters as Record)['newsId']); + logger.info(`onNewWant launchParam: ${JSON.stringify(launchParams) ?? ''}`); + if (this.windowStage === undefined) { + return; + } + this.onWindowStageCreate(this.windowStage); } - onCreate(want) { - globalThis.newWant = want; - globalThis.context = this.context; + onCreate(want: Want) { + this.want = want; + AppStorage.setOrCreate('wantNewsId', (want.parameters as Record)['newsId']); logger.info('Ability onCreate'); RemoteDeviceModel.createDeviceManager(this.context); } @@ -40,28 +52,30 @@ export default class EntryAbility extends UIAbility { } onWindowStageCreate(windowStage: window.WindowStage) { - globalThis.windowStage = windowStage; // Main window is created, set main page for this ability. logger.info('Ability onWindowStageCreate'); + this.windowStage = windowStage; - if (globalThis.newWant?.parameters?.url) { - windowStage.loadContent(globalThis.newWant.parameters.url, (err, data) => { + if (this.want === undefined) { + return; + } + if (this.want.parameters?.newsId) { + windowStage.loadContent('pages/NewsDetail', (err: Error) => { if (err) { - logger.error(`Failed to load the content. Code is ${err.code}, message is ${err.message}`); + logger.error(`Failed to load the content. Cause: + ${JSON.stringify(err)}`); return; } - logger.info(`Succeeded in loading the content. Data: ${JSON.stringify(data) ?? ''}`); + console.info('Succeeded in loading the content.'); }); return; } - windowStage.loadContent('pages/Index', (err, data) => { + windowStage.loadContent('pages/Index', (err: Error) => { if (err) { - logger.error(`Failed to load the content. Cause: Code is ${err.code}, message is ${err.message}`); + logger.error(`Failed to load the content. Cause: ${JSON.stringify(err)}`); return; } - logger.info(`Succeeded in loading the content. Data: ${JSON.stringify(data) ?? ''}`); }); - checkPermissions(); + checkPermissions(this.context); } onWindowStageDestroy() { @@ -80,38 +94,51 @@ export default class EntryAbility extends UIAbility { } } -async function checkPermissions(): Promise { +async function checkPermissions(context: common.UIAbilityContext): Promise { let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(); if (grantStatus !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { // Applying for the distributed data synchronization permission. - let atManager = abilityAccessCtrl.createAtManager(); - let permissions: Array = ['ohos.permission.DISTRIBUTED_DATASYNC']; - try { - atManager.requestPermissionsFromUser(globalThis.context, permissions); - } catch (err) { - logger.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); - } + let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + atManager.requestPermissionsFromUser(context, permissions).then((data) => { + let grantStatus: Array = data.authResults; + let length: number = grantStatus.length; + for (let i: number = 0; i < length; i++) { + if (grantStatus[i] === 0) { + logger.info('EntryAbility', `checkPermissions request permission ${permissions[i]} success`); + } else { + logger.error('EntryAbility', + `checkPermissions request fail permission=${permissions[i]}, grantStatus=${grantStatus[i]}`); + return; + } + } + }).catch((err: Error) => { + logger.error('EntryAbility', + `checkPermissions request permissions failed, err=${JSON.stringify(err)}`); + }) } } async function checkAccessToken() { let atManager = abilityAccessCtrl.createAtManager(); - let grantStatus: abilityAccessCtrl.GrantStatus; - let tokenId: number; + let tokenId: number = 0; try { let bundleInfo: bundleManager.BundleInfo = await bundleManager .getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo; tokenId = appInfo.accessTokenId; } catch (err) { - logger.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`); + logger.error('EntryAbility', + `checkAccessToken Failed to get bundle info for self. err=${JSON.stringify(err)}`); } + let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED; try { grantStatus = await atManager.checkAccessToken(tokenId, 'ohos.permission.DISTRIBUTED_DATASYNC'); } catch (err) { - logger.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`); + logger.error('EntryAbility', + `checkAccessToken Failed to check access token. err=${JSON.stringify(err)}`); } + return grantStatus; } \ No newline at end of file diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/model/RemoteDeviceModel.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/model/RemoteDeviceModel.ets index f106ffe9a9ca58565230dc687f2fddbb476b0d0d..a8958097e91458846c3d5e2758985f5caddc4d97 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/model/RemoteDeviceModel.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/model/RemoteDeviceModel.ets @@ -22,17 +22,34 @@ import logger from '../common/utils/Logger'; // the value is in scope [0, 65535] const SUBSCRIBE_ID = 100; +interface RejectError { + code: number; + message: string; +} + +export interface DeviceInfoInterface { + subscribeId: number, + device: deviceManager.DeviceInfo +} + +export interface AuthExtraInfoInterface { + targetPkgName: string, + appName: string, + appDescription: string, + business: string +} + class RemoteDeviceModel { - private static dmInstance: RemoteDeviceModel = undefined; + private static dmInstance: RemoteDeviceModel | undefined = undefined; private trustedDeviceList: deviceManager.DeviceInfo[] = []; private discoverList: deviceManager.DeviceInfo[] = []; - private deviceManager: deviceManager.DeviceManager; + private deviceManager?: deviceManager.DeviceManager; static getInstance(): RemoteDeviceModel { - if (this.dmInstance === undefined) { - this.dmInstance = new RemoteDeviceModel(); + if (RemoteDeviceModel.dmInstance === undefined) { + RemoteDeviceModel.dmInstance = new RemoteDeviceModel(); } - return this.dmInstance; + return RemoteDeviceModel.dmInstance; } showToast(message: Resource): void { @@ -45,7 +62,8 @@ class RemoteDeviceModel { if (this.deviceManager !== undefined) { return; } - await new Promise((resolve, reject) => { + await new Promise((resolve: (value: Object | PromiseLike) => void, reject: + ((reason?: RejectError) => void)) => { deviceManager.createDeviceManager(context.abilityInfo.bundleName, (err, value) => { if (err) { reject(err); @@ -69,9 +87,9 @@ class RemoteDeviceModel { try { this.trustedDeviceList = this.deviceManager.getTrustedDeviceListSync(); - AppStorage.SetOrCreate(CommonConstants.TRUSTED_DEVICE_LIST, this.trustedDeviceList); + AppStorage.setOrCreate(CommonConstants.TRUSTED_DEVICE_LIST, this.trustedDeviceList); } catch (err) { - logger.error(`getTrustedDeviceList error. Code is ${err.code}, message is ${err.message}`); + logger.error(`getTrustedDeviceList failed error = ${JSON.stringify(err)}`); this.showToast($r('app.string.get_trusted_device_list_failed')); } } @@ -84,7 +102,7 @@ class RemoteDeviceModel { break; } } - AppStorage.SetOrCreate(CommonConstants.TRUSTED_DEVICE_LIST, this.trustedDeviceList); + AppStorage.setOrCreate(CommonConstants.TRUSTED_DEVICE_LIST, this.trustedDeviceList); } deviceStateChangeActionOffline(device: deviceManager.DeviceInfo): void { @@ -95,7 +113,7 @@ class RemoteDeviceModel { } } this.trustedDeviceList = list; - AppStorage.SetOrCreate(CommonConstants.TRUSTED_DEVICE_LIST, this.trustedDeviceList); + AppStorage.setOrCreate(CommonConstants.TRUSTED_DEVICE_LIST, this.trustedDeviceList); } registerDeviceStateListener(): void { @@ -122,14 +140,14 @@ class RemoteDeviceModel { }) } - deviceFound(data): void { + deviceFound(data: DeviceInfoInterface): void { for (let i: number = 0; i < this.discoverList.length; i++) { if (this.discoverList[i].deviceId === data.device.deviceId) { return; } } this.discoverList[this.discoverList.length] = data.device; - AppStorage.SetOrCreate(CommonConstants.DISCOVER_DEVICE_LIST, this.discoverList); + AppStorage.setOrCreate(CommonConstants.DISCOVER_DEVICE_LIST, this.discoverList); } startDeviceDiscovery(): void { @@ -161,12 +179,12 @@ class RemoteDeviceModel { capability: 0 }; this.discoverList = []; - AppStorage.SetOrCreate(CommonConstants.DISCOVER_DEVICE_LIST, this.discoverList); + AppStorage.setOrCreate(CommonConstants.DISCOVER_DEVICE_LIST, this.discoverList); try { this.deviceManager.startDeviceDiscovery(info); } catch (err) { - logger.error(`startDeviceDiscovery failed. Code is ${err.code}, message is ${err.message}`); + logger.error(`startDeviceDiscovery failed error = ${JSON.stringify(err)}`); } } @@ -181,7 +199,7 @@ class RemoteDeviceModel { this.deviceManager.off('deviceFound'); this.deviceManager.off('discoverFail'); } catch (err) { - logger.error(`stopDeviceDiscovery failed. Code is ${err.code}, message is ${err.message}`); + logger.error(`stopDeviceDiscovery failed error = ${JSON.stringify(err)}`); } } @@ -198,7 +216,7 @@ class RemoteDeviceModel { this.trustedDeviceList = []; this.discoverList = []; } catch (err) { - logger.error(`stopDeviceDiscovery failed. Code is ${err.code}, message is ${err.message}` ); + logger.error(`stopDeviceDiscovery failed error = ${JSON.stringify(err)}` ); } } @@ -213,11 +231,11 @@ class RemoteDeviceModel { if (this.discoverList[i].deviceId !== device.deviceId) { continue; } - let extraInfo: any = { - 'targetPkgName': context.abilityInfo.bundleName, - 'appName': context.applicationInfo.name, - 'appDescription': context.applicationInfo.description, - 'business': CommonConstants.ZERO + let extraInfo: AuthExtraInfoInterface = { + targetPkgName: context.abilityInfo.bundleName, + appName: context.applicationInfo.name, + appDescription: context.applicationInfo.description, + business: CommonConstants.ZERO }; let authParam: deviceManager.AuthParam = { 'authType': CommonConstants.ONE, @@ -231,7 +249,7 @@ class RemoteDeviceModel { } }) } catch (err) { - logger.error(`authenticateDevice failed. Code is ${err.code}, message is ${err.message}`); + logger.error(`authenticateDevice failed error = ${JSON.stringify(err)}`); } } } diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/pages/Index.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/pages/Index.ets index 1b746700ef787ca271bbabb37e065d0f483df4a7..8434be1de83663dae6779c13107612bb96e38689 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/pages/Index.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/pages/Index.ets @@ -13,8 +13,7 @@ * limitations under the License. */ -import { NewsData } from '../common/bean/NewsData'; -import { NewsDataModel } from '../viewmodel/NewsDataModel'; +import { NewsData, NewsDataModel } from '../viewmodel/NewsDataModel'; import NewsTab from '../view/NewsTab'; import CommonConstants from '../common/constants/CommonConstants'; diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/pages/NewsDetail.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/pages/NewsDetail.ets index 029d61acefb227deb8f4ed700062b2e3b709f4d8..72fde8c6ff9aa33a5d00436ac4da83bfde00da8c 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/pages/NewsDetail.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/pages/NewsDetail.ets @@ -14,8 +14,7 @@ */ import router from '@ohos.router'; -import { NewsData } from '../common/bean/NewsData'; -import { NewsDataModel } from '../viewmodel/NewsDataModel'; +import { NewsData, NewsDataModel } from '../viewmodel/NewsDataModel'; import CommonConstants from '../common/constants/CommonConstants'; import DetailHeadContent from '../view/DetailHeadContent'; import DetailFooter from '../view/DetailFooter'; @@ -23,7 +22,7 @@ import DetailFooter from '../view/DetailFooter'; @Entry @Component struct NewsDetail { - @Provide newsData: NewsData = null; + @Provide newsData: NewsData | undefined = undefined; private newsItems: NewsData[] = NewsDataModel.getNewsComposition(); build() { @@ -41,13 +40,11 @@ struct NewsDetail { } aboutToAppear() { - const params: any = router.getParams(); - if (params) { - this.newsData = params.newsItem; - } else { - const want = globalThis.newWant; - const newsId = want.parameters.newsId; - this.newsData = this.newsItems.filter(item => (item.newsId === newsId))[0]; + let newsId: string | undefined = AppStorage.get('wantNewsId'); + if (newsId === undefined) { + this.newsData = (router.getParams() as Record)['newsItem']; + return; } + this.newsData = this.newsItems.filter((item: NewsData) => (item.newsId === newsId))[0]; } } \ No newline at end of file diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/view/DetailFooter.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/view/DetailFooter.ets index fe456bba656f183145718a57d43e4d75b0937663..3ddda9d37fda7e3a8dd20279f012c356905b0b69 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/view/DetailFooter.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/view/DetailFooter.ets @@ -14,10 +14,12 @@ */ import deviceManager from '@ohos.distributedHardware.deviceManager'; -import { NewsData } from '../common/bean/NewsData'; +import common from '@ohos.app.ability.common'; import CommonConstants from '../common/constants/CommonConstants'; import RemoteDeviceModel from '../model/RemoteDeviceModel'; import { DeviceListDialog } from './DeviceListDialog'; +import Logger from '../common/utils/Logger'; +import { NewsData } from '../viewmodel/NewsDataModel'; @Extend(Image) function imageStyle() { .width($r('app.float.footer_icon_size')) @@ -30,7 +32,8 @@ export default struct DetailFooter { @StorageLink('trustedDeviceList') trustedDeviceList: deviceManager.DeviceInfo[] = []; @Consume newsData: NewsData; @Provide currentBreakpoint: string = CommonConstants.BREAKPOINT_SM; - private dialogController: CustomDialogController; + private dialogController?: CustomDialogController; + private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; build() { Column() { @@ -112,6 +115,10 @@ export default struct DetailFooter { .onClick(() => { // Discover devices. RemoteDeviceModel.startDeviceDiscovery(); + if (this.dialogController === undefined) { + Logger.error(`DialogController is undefined`); + return; + } this.dialogController.open(); }) } @@ -138,7 +145,7 @@ export default struct DetailFooter { builder: DeviceListDialog({ confirm: (device: deviceManager.DeviceInfo) => { // Connect the device. - RemoteDeviceModel.authenticateDevice(device, globalThis.context); + RemoteDeviceModel.authenticateDevice(device, this.context); RemoteDeviceModel.stopDeviceDiscovery(); } }), diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/view/DetailHeadContent.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/view/DetailHeadContent.ets index 54826b98df9765df236cd96ac3c7cd11f84537e1..df1b2c5ecd705161ef22cc7b952d633e276b92f7 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/view/DetailHeadContent.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/view/DetailHeadContent.ets @@ -15,7 +15,7 @@ import router from '@ohos.router'; import CommonConstants from '../common/constants/CommonConstants'; -import { NewsData } from '../common/bean/NewsData'; +import { NewsData } from '../viewmodel/NewsDataModel'; @Extend(Text) function textStyle() { .fontSize($r('app.float.small_font_size')) diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/view/DeviceListDialog.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/view/DeviceListDialog.ets index 5490dc87b414b7c112d9c06fc201d237eab7c038..38ed506629114103fbc50e7a5e46f86eaa0f3e46 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/view/DeviceListDialog.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/view/DeviceListDialog.ets @@ -18,9 +18,9 @@ import Want from '@ohos.app.ability.Want'; import prompt from '@ohos.promptAction'; import common from '@ohos.app.ability.common'; import CommonConstants from '../common/constants/CommonConstants'; -import { NewsData } from '../common/bean/NewsData'; import RemoteDeviceModel from '../model/RemoteDeviceModel'; import Logger from '../common/utils/Logger'; +import { NewsData } from '../viewmodel/NewsDataModel'; @Extend(Text) function textStyle() { .fontColor($r('app.color.dialog_button_font')) @@ -29,22 +29,17 @@ import Logger from '../common/utils/Logger'; } @CustomDialog - export struct DeviceListDialog { @StorageLink('discoverDeviceList') discoverDeviceList: deviceManager.DeviceInfo[] = []; @StorageLink('trustedDeviceList') trustedDeviceList: deviceManager.DeviceInfo[] = []; @Consume newsData: NewsData; - private selectedDevice: deviceManager.DeviceInfo; - private confirm: (device: deviceManager.DeviceInfo) => void; - private isTrusted: boolean; - private controller: CustomDialogController; - private context: common.UIAbilityContext; - - aboutToAppear() { - this.context = getContext(this) as common.UIAbilityContext; - } + private selectedDevice?: deviceManager.DeviceInfo; + private confirm?: (device: deviceManager.DeviceInfo) => void; + private isTrusted?: boolean; + private controller?: CustomDialogController; + private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; - getDeviceTypeIcon(deviceType): Resource { + getDeviceTypeIcon(deviceType: deviceManager.DeviceType): Resource { if (deviceType === deviceManager.DeviceType.TABLET) { return $r('app.media.ic_pad'); } else if (deviceType === deviceManager.DeviceType.PHONE) { @@ -107,8 +102,8 @@ export struct DeviceListDialog { this.selectedDevice = item; this.isTrusted = true; } else { - this.selectedDevice = null; - this.isTrusted = null; + this.selectedDevice = undefined; + this.isTrusted = undefined; } }) } @@ -134,7 +129,7 @@ export struct DeviceListDialog { }) .width(CommonConstants.FULL_COMPONENT) } - }, item => item.deviceId) + }, (item: deviceManager.DeviceInfo) => JSON.stringify(item.deviceId)) } Row() { @@ -185,8 +180,8 @@ export struct DeviceListDialog { this.selectedDevice = item; this.isTrusted = false; } else { - this.selectedDevice = null; - this.isTrusted = null; + this.selectedDevice = undefined; + this.isTrusted = undefined; } }) .margin({ left: $r('app.float.radio_margin_left') }) @@ -213,7 +208,7 @@ export struct DeviceListDialog { }) .width(CommonConstants.FULL_COMPONENT) } - }, item => item.deviceId) + }, (item: deviceManager.DeviceInfo) => JSON.stringify(item.deviceId)) } Row() { @@ -222,6 +217,10 @@ export struct DeviceListDialog { .textStyle() .onClick(() => { RemoteDeviceModel.stopDeviceDiscovery(); + if (this.controller === undefined) { + Logger.error(`Controller is undefined`); + return; + } this.controller.close(); }) } @@ -239,7 +238,7 @@ export struct DeviceListDialog { Text($r('app.string.ok')) .textStyle() .onClick(() => { - if ((this.selectedDevice === null)) { + if ((this.selectedDevice === undefined)) { prompt.showToast({ message: $r('app.string.please_select_device') }); @@ -247,11 +246,23 @@ export struct DeviceListDialog { } if (this.isTrusted === false) { // Connect the device. + if (this.confirm === undefined) { + Logger.error(`Confirm is undefined`); + return; + } this.confirm(this.selectedDevice); + if (this.controller === undefined) { + Logger.error(`Controller is undefined`); + return; + } this.controller.close(); } else { // Start the app. startAbilityContinuation(this.selectedDevice.networkId, this.newsData.newsId, this.context); + if (this.controller === undefined) { + Logger.error(`Controller is undefined`); + return; + } this.controller.close(); } }) @@ -281,12 +292,11 @@ function startAbilityContinuation(deviceId: string, newsId: string, context: com bundleName: context.abilityInfo.bundleName, abilityName: CommonConstants.ABILITY_NAME, parameters: { - 'url': CommonConstants.NEWS_DETAIL_PAGE, - 'newsId': newsId + newsId: newsId } }; - globalThis.context.startAbility(want).catch((err) => { - Logger.error(`startAbilityContinuation error. Code is ${err.code}, message is ${err.message}`); + context.startAbility(want).catch((err: Error) => { + Logger.error(`startAbilityContinuation failed error = ${JSON.stringify(err)}`); prompt.showToast({ message: $r('app.string.start_ability_continuation_error') }); diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/view/NewsList.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/view/NewsList.ets index f08342cbcd5b214cd8214cc82aea863044b564be..c369377378cb41648d721e08bc29512e5f008377 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/view/NewsList.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/view/NewsList.ets @@ -15,12 +15,12 @@ import router from '@ohos.router'; import CommonConstants from '../common/constants/CommonConstants'; -import { NewsData } from '../common/bean/NewsData'; import Logger from '../common/utils/Logger'; +import { NewsData } from '../viewmodel/NewsDataModel'; @Component export default struct NewsList { - private newsItems: NewsData[]; + private newsItems: NewsData[] = []; build() { List() { @@ -57,7 +57,7 @@ export default struct NewsList { } } } - }, (item, index) => index + JSON.stringify(item)) + }, (item: NewsData, index: number) => index + JSON.stringify(item)) } .height(CommonConstants.FULL_COMPONENT) } @@ -65,53 +65,55 @@ export default struct NewsList { @Component struct NewsItem { - private newsItem: NewsData; - private isLast: boolean; + private newsItem?: NewsData; + private isLast: boolean = false; build() { Column() { - Row() { - Column() { - Row() { - Text(this.newsItem.title) - .fontSize($r('app.float.middle_font_size')) - .height($r('app.float.news_item_title_height')) - .maxLines(CommonConstants.NEWS_MAX_LINES) - .textOverflow({ overflow: TextOverflow.Ellipsis }) - .align(Alignment.Top) - } - .alignItems(VerticalAlign.Top) - .margin({ bottom: $r('app.float.list_title_margin_bottom') }) - .height($r('app.float.news_item_title_height')) - .width(CommonConstants.FULL_COMPONENT) + if (this.newsItem !== undefined) { + Row() { + Column() { + Row() { + Text(this.newsItem.title) + .fontSize($r('app.float.middle_font_size')) + .height($r('app.float.news_item_title_height')) + .maxLines(CommonConstants.NEWS_MAX_LINES) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .align(Alignment.Top) + } + .alignItems(VerticalAlign.Top) + .margin({ bottom: $r('app.float.list_title_margin_bottom') }) + .height($r('app.float.news_item_title_height')) + .width(CommonConstants.FULL_COMPONENT) - Row() { - Text(this.newsItem.label) - .fontSize($r('app.float.small_font_size')) - .fontColor(this.newsItem.redLabel ? Color.Red : $r('app.color.font_color_gray')) - .fontWeight(FontWeight.Normal) - .margin({ right: $r('app.float.news_label_margin_right') }) - Text(this.newsItem.from) - .fontSize($r('app.float.small_font_size')) - .fontColor($r('app.color.font_color_gray')) - .fontWeight(FontWeight.Normal) + Row() { + Text(this.newsItem === undefined ? '' : this.newsItem.label) + .fontSize($r('app.float.small_font_size')) + .fontColor(this.newsItem.redLabel ? Color.Red : $r('app.color.font_color_gray')) + .fontWeight(FontWeight.Normal) + .margin({ right: $r('app.float.news_label_margin_right') }) + Text(this.newsItem.from) + .fontSize($r('app.float.small_font_size')) + .fontColor($r('app.color.font_color_gray')) + .fontWeight(FontWeight.Normal) + } + .padding({ bottom: $r('app.float.list_label_padding_bottom') }) + .width(CommonConstants.FULL_COMPONENT) } - .padding({ bottom: $r('app.float.list_label_padding_bottom') }) - .width(CommonConstants.FULL_COMPONENT) - } - .justifyContent(FlexAlign.Start) - .padding({ right: $r('app.float.news_item_padding_right') }) - .height(CommonConstants.FULL_COMPONENT) - .layoutWeight(CommonConstants.ONE) + .justifyContent(FlexAlign.Start) + .padding({ right: $r('app.float.news_item_padding_right') }) + .height(CommonConstants.FULL_COMPONENT) + .layoutWeight(CommonConstants.ONE) - Image(this.newsItem.imgUrl) - .height($r('app.float.news_item_image_height')) - .width($r('app.float.news_item_image_width')) - .borderRadius($r('app.float.list_image_border_radius')) + Image(this.newsItem.imgUrl) + .height($r('app.float.news_item_image_height')) + .width($r('app.float.news_item_image_width')) + .borderRadius($r('app.float.list_image_border_radius')) + } + .padding({ top: $r('app.float.list_row_padding_top') }) + .width(CommonConstants.FULL_COMPONENT) + .alignItems(VerticalAlign.Top) } - .padding({ top: $r('app.float.list_row_padding_top') }) - .width(CommonConstants.FULL_COMPONENT) - .alignItems(VerticalAlign.Top) Divider() .color($r('app.color.detail_divider_color')) @@ -130,8 +132,8 @@ struct NewsItem { params: { newsItem: this.newsItem } - }).catch((err) => { - Logger.error(`router pushUrl failed. Code is ${err.code}, message is ${err.message}`); + }).catch((err: Error) => { + Logger.error(`router pushUrl failed error = ${err}`); }) }) } diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/view/NewsTab.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/view/NewsTab.ets index 63af125db7d3c52d2ce00852ac8c22b5c8258a14..f07e08aa327f298284f51b9d48766bb5a64bebb5 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/view/NewsTab.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/view/NewsTab.ets @@ -15,14 +15,13 @@ import NewsList from './NewsList'; import CommonConstants from '../common/constants/CommonConstants'; -import { NewsData } from '../common/bean/NewsData'; -import { NewsDataModel } from '../viewmodel/NewsDataModel'; +import { NewsData, NewsDataModel } from '../viewmodel/NewsDataModel'; @Component export default struct NewsTab { @State currentIndex: number = 0; @State currentBreakpoint: string = CommonConstants.BREAKPOINT_SM; - private newsItems: NewsData[]; + private newsItems: NewsData[] = []; @Builder TabBuilder(title: Resource, index: number) { Row() { @@ -74,7 +73,7 @@ export default struct NewsTab { NewsList({ newsItems: NewsDataModel.getNewsByType(this.newsItems, title) }) } .tabBar(this.TabBuilder(NewsDataModel.getTypeByStr(title), index)) - }, (title, index) => index + JSON.stringify(title)) + }, (title: string, index: number) => index + JSON.stringify(title)) } .barHeight($r('app.float.news_tab_bar_height')) .barWidth(CommonConstants.FULL_COMPONENT) diff --git a/Distributed/DistributedNewsClient/entry/src/main/ets/viewmodel/NewsDataModel.ets b/Distributed/DistributedNewsClient/entry/src/main/ets/viewmodel/NewsDataModel.ets index f62077d3b7483d34534554892f27bb03c2cc723e..57dddeabd0164efa266b62a89a59f036e016a1cf 100644 --- a/Distributed/DistributedNewsClient/entry/src/main/ets/viewmodel/NewsDataModel.ets +++ b/Distributed/DistributedNewsClient/entry/src/main/ets/viewmodel/NewsDataModel.ets @@ -14,7 +14,6 @@ */ import CommonConstants from '../common/constants/CommonConstants'; -import { NewsData } from '../common/bean/NewsData'; export class NewsDataModel { static getNewsByType(news: NewsData[], type: string): NewsData[] { @@ -24,8 +23,8 @@ export class NewsDataModel { return news.filter(item => (item.newsTypeStr === type)); } - static getTypeByStr(type: string): Resource { - let newsType: Resource; + static getTypeByStr(type: string): Resource | undefined { + let newsType: Resource | undefined = undefined; switch (type) { case CommonConstants.ALL_TITLE[0]: newsType = $r('app.string.tabs_all'); @@ -59,13 +58,13 @@ export class NewsDataModel { for (let i: number = 0; i < CommonConstants.NEWS_ID.length; i++) { let newsId: string = CommonConstants.NEWS_ID[i]; let newsTypeStr: string = CommonConstants.ALL_TITLE[i % CommonConstants.TITLES_NUMBER + 1]; - let newsType: Resource = this.getTypeByStr(newsTypeStr); - let title: Resource; - let content: Resource; - let imgUrl: Resource; - let label: Resource; - let redLabel: boolean; - let from: Resource; + let newsType: Resource | undefined = NewsDataModel.getTypeByStr(newsTypeStr); + let title: Resource | undefined = undefined; + let content: Resource | undefined = undefined; + let imgUrl: Resource | undefined = undefined; + let label: Resource | undefined = undefined; + let redLabel: boolean = false; + let from: Resource | undefined = undefined; switch (i % CommonConstants.IMAGES_NUMBER) { case 0: imgUrl = $r('app.media.ic_news_image1'); @@ -83,13 +82,11 @@ export class NewsDataModel { imgUrl = $r('app.media.ic_news_image3'); label = $r('app.string.news_label_recommend'); from = $r('app.string.xx_com'); - redLabel = false; break; case 3: imgUrl = $r('app.media.ic_news_image4'); label = $r('app.string.news_label_recommend'); from = $r('app.string.news_client'); - redLabel = false; break; default: break; @@ -183,4 +180,77 @@ export class NewsDataModel { } return newsComposition; } +} + +export class NewsData { + /** + * The Id of news. + */ + newsId: string; + + /** + * The title of news. + */ + title: Resource | undefined; + + /** + * The type string of news. + */ + newsTypeStr: string; + + /** + * The type of news. + */ + newsType: Resource | undefined; + + /** + * The image url of news. + */ + imgUrl: Resource | undefined; + + /** + * The reads of news. + */ + reads: string | undefined; + + /** + * The likes of news. + */ + likes: string | undefined; + + /** + * The content of news. + */ + content: Resource | undefined; + + /** + * The label of news. + */ + label: Resource | undefined; + + /** + * The color of label. + */ + redLabel: boolean; + + /** + * The from of news. + */ + from: Resource | undefined; + + constructor(newsId: string, title: Resource | undefined, newsTypeStr: string, newsType: Resource | undefined, + imgUrl: Resource | undefined, reads: string, likes: string, content: Resource | undefined, + label: Resource | undefined, redLabel: boolean, from: Resource | undefined) { + this.newsId = newsId; + this.title = title; + this.newsTypeStr = newsTypeStr; + this.newsType = newsType; + this.imgUrl = imgUrl; + this.reads = reads; + this.likes = likes; + this.content = content; + this.label = label; + this.redLabel = redLabel; + this.from = from; + } } \ No newline at end of file diff --git a/Distributed/DistributedNewsClient/hvigor/hvigor-config.json5 b/Distributed/DistributedNewsClient/hvigor/hvigor-config.json5 index 28f85c1467c07bcebd848b16b46348ffc6761057..2150edce73efa10d16e01d839dec13734ab2dd55 100644 --- a/Distributed/DistributedNewsClient/hvigor/hvigor-config.json5 +++ b/Distributed/DistributedNewsClient/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.3.0", + "hvigorVersion": "3.0.4-s", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.3.0" + "@ohos/hvigor-ohos-plugin": "3.0.4-s" } } \ No newline at end of file diff --git a/Distributed/DistributedNewsClient/hvigor/hvigor-wrapper.js b/Distributed/DistributedNewsClient/hvigor/hvigor-wrapper.js index 994f22987bd0739b9faa07c966b066c2d9218602..372eae8eb4a124095936f9cd78df5c6756746f3f 100644 --- a/Distributed/DistributedNewsClient/hvigor/hvigor-wrapper.js +++ b/Distributed/DistributedNewsClient/hvigor/hvigor-wrapper.js @@ -1,2 +1 @@ -"use strict";var e=require("fs"),t=require("path"),n=require("os"),r=require("crypto"),u=require("child_process"),o=require("constants"),i=require("stream"),s=require("util"),c=require("assert"),a=require("tty"),l=require("zlib"),f=require("net");function d(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var D=d(e),p=d(t),E=d(n),m=d(r),h=d(u),y=d(o),C=d(i),F=d(s),g=d(c),A=d(a),v=d(l),S=d(f),w="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},O={},b={},_={},B=w&&w.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(_,"__esModule",{value:!0}),_.isMac=_.isLinux=_.isWindows=void 0;const P=B(E.default),k="Windows_NT",x="Linux",N="Darwin";_.isWindows=function(){return P.default.type()===k},_.isLinux=function(){return P.default.type()===x},_.isMac=function(){return P.default.type()===N};var I={},T=w&&w.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var u=Object.getOwnPropertyDescriptor(t,n);u&&!("get"in u?!t.__esModule:u.writable||u.configurable)||(u={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,u)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),R=w&&w.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),M=w&&w.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&T(t,e,n);return R(t,e),t};Object.defineProperty(I,"__esModule",{value:!0}),I.hash=void 0;const L=M(m.default);I.hash=function(e,t="md5"){return L.createHash(t).update(e,"utf-8").digest("hex")},function(e){var t=w&&w.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var u=Object.getOwnPropertyDescriptor(t,n);u&&!("get"in u?!t.__esModule:u.writable||u.configurable)||(u={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,u)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),n=w&&w.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),r=w&&w.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(null!=e)for(var u in e)"default"!==u&&Object.prototype.hasOwnProperty.call(e,u)&&t(r,e,u);return n(r,e),r};Object.defineProperty(e,"__esModule",{value:!0}),e.HVIGOR_BOOT_JS_FILE_PATH=e.HVIGOR_PROJECT_DEPENDENCY_PACKAGE_JSON_PATH=e.HVIGOR_PROJECT_DEPENDENCIES_HOME=e.HVIGOR_PROJECT_WRAPPER_HOME=e.HVIGOR_PROJECT_NAME=e.HVIGOR_PROJECT_ROOT_DIR=e.HVIGOR_PROJECT_CACHES_HOME=e.HVIGOR_PNPM_STORE_PATH=e.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH=e.HVIGOR_WRAPPER_TOOLS_HOME=e.HVIGOR_USER_HOME=e.DEFAULT_PACKAGE_JSON=e.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME=e.PNPM=e.HVIGOR=e.NPM_TOOL=e.PNPM_TOOL=e.HVIGOR_ENGINE_PACKAGE_NAME=void 0;const u=r(p.default),o=r(E.default),i=_,s=I;e.HVIGOR_ENGINE_PACKAGE_NAME="@ohos/hvigor",e.PNPM_TOOL=(0,i.isWindows)()?"pnpm.cmd":"pnpm",e.NPM_TOOL=(0,i.isWindows)()?"npm.cmd":"npm",e.HVIGOR="hvigor",e.PNPM="pnpm",e.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME="hvigor-config.json5",e.DEFAULT_PACKAGE_JSON="package.json",e.HVIGOR_USER_HOME=u.resolve(o.homedir(),".hvigor"),e.HVIGOR_WRAPPER_TOOLS_HOME=u.resolve(e.HVIGOR_USER_HOME,"wrapper","tools"),e.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH=u.resolve(e.HVIGOR_WRAPPER_TOOLS_HOME,"node_modules",".bin",e.PNPM_TOOL),e.HVIGOR_PNPM_STORE_PATH=u.resolve(e.HVIGOR_USER_HOME,"caches"),e.HVIGOR_PROJECT_CACHES_HOME=u.resolve(e.HVIGOR_USER_HOME,"project_caches"),e.HVIGOR_PROJECT_ROOT_DIR=process.cwd(),e.HVIGOR_PROJECT_NAME=u.basename((0,s.hash)(e.HVIGOR_PROJECT_ROOT_DIR)),e.HVIGOR_PROJECT_WRAPPER_HOME=u.resolve(e.HVIGOR_PROJECT_ROOT_DIR,e.HVIGOR),e.HVIGOR_PROJECT_DEPENDENCIES_HOME=u.resolve(e.HVIGOR_PROJECT_CACHES_HOME,e.HVIGOR_PROJECT_NAME,"workspace"),e.HVIGOR_PROJECT_DEPENDENCY_PACKAGE_JSON_PATH=u.resolve(e.HVIGOR_PROJECT_DEPENDENCIES_HOME,e.DEFAULT_PACKAGE_JSON),e.HVIGOR_BOOT_JS_FILE_PATH=u.resolve(e.HVIGOR_PROJECT_DEPENDENCIES_HOME,"node_modules","@ohos","hvigor","bin","hvigor.js")}(b);var j={},$={};Object.defineProperty($,"__esModule",{value:!0}),$.logInfoPrintConsole=$.logErrorAndExit=void 0,$.logErrorAndExit=function(e){e instanceof Error?console.error(e.message):console.error(e),process.exit(-1)},$.logInfoPrintConsole=function(e){console.log(e)};var H=w&&w.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var u=Object.getOwnPropertyDescriptor(t,n);u&&!("get"in u?!t.__esModule:u.writable||u.configurable)||(u={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,u)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),J=w&&w.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),G=w&&w.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&H(t,e,n);return J(t,e),t},V=w&&w.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(j,"__esModule",{value:!0}),j.isFileExists=j.offlinePluginConversion=j.executeCommand=j.getNpmPath=j.hasNpmPackInPaths=void 0;const U=h.default,W=G(p.default),z=b,K=$,q=V(D.default);j.hasNpmPackInPaths=function(e,t){try{return require.resolve(e,{paths:[...t]}),!0}catch(e){return!1}},j.getNpmPath=function(){const e=process.execPath;return W.join(W.dirname(e),z.NPM_TOOL)},j.executeCommand=function(e,t,n){0!==(0,U.spawnSync)(e,t,n).status&&(0,K.logErrorAndExit)(`Error: ${e} ${t} execute failed.See above for details.`)},j.offlinePluginConversion=function(e,t){return t.startsWith("file:")||t.endsWith(".tgz")?W.resolve(e,z.HVIGOR,t.replace("file:","")):t},j.isFileExists=function(e){return q.default.existsSync(e)&&q.default.statSync(e).isFile()},function(e){var t=w&&w.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var u=Object.getOwnPropertyDescriptor(t,n);u&&!("get"in u?!t.__esModule:u.writable||u.configurable)||(u={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,u)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),n=w&&w.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),r=w&&w.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(null!=e)for(var u in e)"default"!==u&&Object.prototype.hasOwnProperty.call(e,u)&&t(r,e,u);return n(r,e),r},u=w&&w.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(e,"__esModule",{value:!0}),e.executeInstallPnpm=e.isPnpmAvailable=e.environmentHandler=e.checkNpmConifg=e.PNPM_VERSION=void 0;const o=r(D.default),i=b,s=j,c=r(p.default),a=$,l=h.default,f=u(E.default);e.PNPM_VERSION="7.30.0",e.checkNpmConifg=function(){const e=c.resolve(i.HVIGOR_PROJECT_ROOT_DIR,".npmrc"),t=c.resolve(f.default.homedir(),".npmrc");if((0,s.isFileExists)(e)||(0,s.isFileExists)(t))return;const n=(0,s.getNpmPath)(),r=(0,l.spawnSync)(n,["config","get","prefix"],{cwd:i.HVIGOR_PROJECT_ROOT_DIR});if(0!==r.status||!r.stdout)return void(0,a.logErrorAndExit)("Error: The hvigor depends on the npmrc file. Configure the npmrc file first.");const u=c.resolve(`${r.stdout}`.replace(/[\r\n]/gi,""),".npmrc");(0,s.isFileExists)(u)||(0,a.logErrorAndExit)("Error: The hvigor depends on the npmrc file. Configure the npmrc file first.")},e.environmentHandler=function(){process.env["npm_config_update-notifier"]="false"},e.isPnpmAvailable=function(){return!!o.existsSync(i.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH)&&(0,s.hasNpmPackInPaths)("pnpm",[i.HVIGOR_WRAPPER_TOOLS_HOME])},e.executeInstallPnpm=function(){(0,a.logInfoPrintConsole)(`Installing pnpm@${e.PNPM_VERSION}...`);const t=(0,s.getNpmPath)();!function(){const t=c.resolve(i.HVIGOR_WRAPPER_TOOLS_HOME,i.DEFAULT_PACKAGE_JSON);try{o.existsSync(i.HVIGOR_WRAPPER_TOOLS_HOME)||o.mkdirSync(i.HVIGOR_WRAPPER_TOOLS_HOME,{recursive:!0});const n={dependencies:{}};n.dependencies[i.PNPM]=e.PNPM_VERSION,o.writeFileSync(t,JSON.stringify(n))}catch(e){(0,a.logErrorAndExit)(`Error: EPERM: operation not permitted,create ${t} failed.`)}}(),(0,s.executeCommand)(t,["install","pnpm"],{cwd:i.HVIGOR_WRAPPER_TOOLS_HOME,stdio:["inherit","inherit","inherit"],env:process.env}),(0,a.logInfoPrintConsole)("Pnpm install success.")}}(O);var Y={},X={},Z={},Q={};Object.defineProperty(Q,"__esModule",{value:!0}),Q.Unicode=void 0;class ee{}Q.Unicode=ee,ee.Space_Separator=/[\u1680\u2000-\u200A\u202F\u205F\u3000]/,ee.ID_Start=/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]/,ee.ID_Continue=/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u08D4-\u08E1\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u09FC\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9-\u0AFF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C80-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D00-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D54-\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1CD0-\u1CD2\u1CD4-\u1CF9\u1D00-\u1DF9\u1DFB-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE3E\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC00-\uDC4A\uDC50-\uDC59\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDE00-\uDE3E\uDE47\uDE50-\uDE83\uDE86-\uDE99\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC40\uDC50-\uDC59\uDC72-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD47\uDD50-\uDD59]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6\uDD00-\uDD4A\uDD50-\uDD59]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/,Object.defineProperty(Z,"__esModule",{value:!0}),Z.JudgeUtil=void 0;const te=Q;Z.JudgeUtil=class{static isIgnoreChar(e){return"string"==typeof e&&("\t"===e||"\v"===e||"\f"===e||" "===e||" "===e||"\ufeff"===e||"\n"===e||"\r"===e||"\u2028"===e||"\u2029"===e)}static isSpaceSeparator(e){return"string"==typeof e&&te.Unicode.Space_Separator.test(e)}static isIdStartChar(e){return"string"==typeof e&&(e>="a"&&e<="z"||e>="A"&&e<="Z"||"$"===e||"_"===e||te.Unicode.ID_Start.test(e))}static isIdContinueChar(e){return"string"==typeof e&&(e>="a"&&e<="z"||e>="A"&&e<="Z"||e>="0"&&e<="9"||"$"===e||"_"===e||"‌"===e||"‍"===e||te.Unicode.ID_Continue.test(e))}static isDigitWithoutZero(e){return/[1-9]/.test(e)}static isDigit(e){return"string"==typeof e&&/[0-9]/.test(e)}static isHexDigit(e){return"string"==typeof e&&/[0-9A-Fa-f]/.test(e)}};var ne={},re={fromCallback:function(e){return Object.defineProperty((function(...t){if("function"!=typeof t[t.length-1])return new Promise(((n,r)=>{e.call(this,...t,((e,t)=>null!=e?r(e):n(t)))}));e.apply(this,t)}),"name",{value:e.name})},fromPromise:function(e){return Object.defineProperty((function(...t){const n=t[t.length-1];if("function"!=typeof n)return e.apply(this,t);e.apply(this,t.slice(0,-1)).then((e=>n(null,e)),n)}),"name",{value:e.name})}},ue=y.default,oe=process.cwd,ie=null,se=process.env.GRACEFUL_FS_PLATFORM||process.platform;process.cwd=function(){return ie||(ie=oe.call(process)),ie};try{process.cwd()}catch(e){}if("function"==typeof process.chdir){var ce=process.chdir;process.chdir=function(e){ie=null,ce.call(process,e)},Object.setPrototypeOf&&Object.setPrototypeOf(process.chdir,ce)}var ae=function(e){ue.hasOwnProperty("O_SYMLINK")&&process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)&&function(e){e.lchmod=function(t,n,r){e.open(t,ue.O_WRONLY|ue.O_SYMLINK,n,(function(t,u){t?r&&r(t):e.fchmod(u,n,(function(t){e.close(u,(function(e){r&&r(t||e)}))}))}))},e.lchmodSync=function(t,n){var r,u=e.openSync(t,ue.O_WRONLY|ue.O_SYMLINK,n),o=!0;try{r=e.fchmodSync(u,n),o=!1}finally{if(o)try{e.closeSync(u)}catch(e){}else e.closeSync(u)}return r}}(e);e.lutimes||function(e){ue.hasOwnProperty("O_SYMLINK")&&e.futimes?(e.lutimes=function(t,n,r,u){e.open(t,ue.O_SYMLINK,(function(t,o){t?u&&u(t):e.futimes(o,n,r,(function(t){e.close(o,(function(e){u&&u(t||e)}))}))}))},e.lutimesSync=function(t,n,r){var u,o=e.openSync(t,ue.O_SYMLINK),i=!0;try{u=e.futimesSync(o,n,r),i=!1}finally{if(i)try{e.closeSync(o)}catch(e){}else e.closeSync(o)}return u}):e.futimes&&(e.lutimes=function(e,t,n,r){r&&process.nextTick(r)},e.lutimesSync=function(){})}(e);e.chown=r(e.chown),e.fchown=r(e.fchown),e.lchown=r(e.lchown),e.chmod=t(e.chmod),e.fchmod=t(e.fchmod),e.lchmod=t(e.lchmod),e.chownSync=u(e.chownSync),e.fchownSync=u(e.fchownSync),e.lchownSync=u(e.lchownSync),e.chmodSync=n(e.chmodSync),e.fchmodSync=n(e.fchmodSync),e.lchmodSync=n(e.lchmodSync),e.stat=o(e.stat),e.fstat=o(e.fstat),e.lstat=o(e.lstat),e.statSync=i(e.statSync),e.fstatSync=i(e.fstatSync),e.lstatSync=i(e.lstatSync),e.chmod&&!e.lchmod&&(e.lchmod=function(e,t,n){n&&process.nextTick(n)},e.lchmodSync=function(){});e.chown&&!e.lchown&&(e.lchown=function(e,t,n,r){r&&process.nextTick(r)},e.lchownSync=function(){});"win32"===se&&(e.rename="function"!=typeof e.rename?e.rename:function(t){function n(n,r,u){var o=Date.now(),i=0;t(n,r,(function s(c){if(c&&("EACCES"===c.code||"EPERM"===c.code||"EBUSY"===c.code)&&Date.now()-o<6e4)return setTimeout((function(){e.stat(r,(function(e,o){e&&"ENOENT"===e.code?t(n,r,s):u(c)}))}),i),void(i<100&&(i+=10));u&&u(c)}))}return Object.setPrototypeOf&&Object.setPrototypeOf(n,t),n}(e.rename));function t(t){return t?function(n,r,u){return t.call(e,n,r,(function(e){s(e)&&(e=null),u&&u.apply(this,arguments)}))}:t}function n(t){return t?function(n,r){try{return t.call(e,n,r)}catch(e){if(!s(e))throw e}}:t}function r(t){return t?function(n,r,u,o){return t.call(e,n,r,u,(function(e){s(e)&&(e=null),o&&o.apply(this,arguments)}))}:t}function u(t){return t?function(n,r,u){try{return t.call(e,n,r,u)}catch(e){if(!s(e))throw e}}:t}function o(t){return t?function(n,r,u){function o(e,t){t&&(t.uid<0&&(t.uid+=4294967296),t.gid<0&&(t.gid+=4294967296)),u&&u.apply(this,arguments)}return"function"==typeof r&&(u=r,r=null),r?t.call(e,n,r,o):t.call(e,n,o)}:t}function i(t){return t?function(n,r){var u=r?t.call(e,n,r):t.call(e,n);return u&&(u.uid<0&&(u.uid+=4294967296),u.gid<0&&(u.gid+=4294967296)),u}:t}function s(e){return!e||("ENOSYS"===e.code||!(process.getuid&&0===process.getuid()||"EINVAL"!==e.code&&"EPERM"!==e.code))}e.read="function"!=typeof e.read?e.read:function(t){function n(n,r,u,o,i,s){var c;if(s&&"function"==typeof s){var a=0;c=function(l,f,d){if(l&&"EAGAIN"===l.code&&a<10)return a++,t.call(e,n,r,u,o,i,c);s.apply(this,arguments)}}return t.call(e,n,r,u,o,i,c)}return Object.setPrototypeOf&&Object.setPrototypeOf(n,t),n}(e.read),e.readSync="function"!=typeof e.readSync?e.readSync:(c=e.readSync,function(t,n,r,u,o){for(var i=0;;)try{return c.call(e,t,n,r,u,o)}catch(e){if("EAGAIN"===e.code&&i<10){i++;continue}throw e}});var c};var le=C.default.Stream,fe=function(e){return{ReadStream:function t(n,r){if(!(this instanceof t))return new t(n,r);le.call(this);var u=this;this.path=n,this.fd=null,this.readable=!0,this.paused=!1,this.flags="r",this.mode=438,this.bufferSize=65536,r=r||{};for(var o=Object.keys(r),i=0,s=o.length;ithis.end)throw new Error("start must be <= end");this.pos=this.start}if(null!==this.fd)return void process.nextTick((function(){u._read()}));e.open(this.path,this.flags,this.mode,(function(e,t){if(e)return u.emit("error",e),void(u.readable=!1);u.fd=t,u.emit("open",t),u._read()}))},WriteStream:function t(n,r){if(!(this instanceof t))return new t(n,r);le.call(this),this.path=n,this.fd=null,this.writable=!0,this.flags="w",this.encoding="binary",this.mode=438,this.bytesWritten=0,r=r||{};for(var u=Object.keys(r),o=0,i=u.length;o= zero");this.pos=this.start}this.busy=!1,this._queue=[],null===this.fd&&(this._open=e.open,this._queue.push([this._open,this.path,this.flags,this.mode,void 0]),this.flush())}}};var de=function(e){if(null===e||"object"!=typeof e)return e;if(e instanceof Object)var t={__proto__:De(e)};else t=Object.create(null);return Object.getOwnPropertyNames(e).forEach((function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(e,n))})),t},De=Object.getPrototypeOf||function(e){return e.__proto__};var pe,Ee,me=D.default,he=ae,ye=fe,Ce=de,Fe=F.default;function ge(e,t){Object.defineProperty(e,pe,{get:function(){return t}})}"function"==typeof Symbol&&"function"==typeof Symbol.for?(pe=Symbol.for("graceful-fs.queue"),Ee=Symbol.for("graceful-fs.previous")):(pe="___graceful-fs.queue",Ee="___graceful-fs.previous");var Ae=function(){};if(Fe.debuglog?Ae=Fe.debuglog("gfs4"):/\bgfs4\b/i.test(process.env.NODE_DEBUG||"")&&(Ae=function(){var e=Fe.format.apply(Fe,arguments);e="GFS4: "+e.split(/\n/).join("\nGFS4: "),console.error(e)}),!me[pe]){var ve=w[pe]||[];ge(me,ve),me.close=function(e){function t(t,n){return e.call(me,t,(function(e){e||_e(),"function"==typeof n&&n.apply(this,arguments)}))}return Object.defineProperty(t,Ee,{value:e}),t}(me.close),me.closeSync=function(e){function t(t){e.apply(me,arguments),_e()}return Object.defineProperty(t,Ee,{value:e}),t}(me.closeSync),/\bgfs4\b/i.test(process.env.NODE_DEBUG||"")&&process.on("exit",(function(){Ae(me[pe]),g.default.equal(me[pe].length,0)}))}w[pe]||ge(w,me[pe]);var Se,we=Oe(Ce(me));function Oe(e){he(e),e.gracefulify=Oe,e.createReadStream=function(t,n){return new e.ReadStream(t,n)},e.createWriteStream=function(t,n){return new e.WriteStream(t,n)};var t=e.readFile;e.readFile=function(e,n,r){"function"==typeof n&&(r=n,n=null);return function e(n,r,u,o){return t(n,r,(function(t){!t||"EMFILE"!==t.code&&"ENFILE"!==t.code?"function"==typeof u&&u.apply(this,arguments):be([e,[n,r,u],t,o||Date.now(),Date.now()])}))}(e,n,r)};var n=e.writeFile;e.writeFile=function(e,t,r,u){"function"==typeof r&&(u=r,r=null);return function e(t,r,u,o,i){return n(t,r,u,(function(n){!n||"EMFILE"!==n.code&&"ENFILE"!==n.code?"function"==typeof o&&o.apply(this,arguments):be([e,[t,r,u,o],n,i||Date.now(),Date.now()])}))}(e,t,r,u)};var r=e.appendFile;r&&(e.appendFile=function(e,t,n,u){"function"==typeof n&&(u=n,n=null);return function e(t,n,u,o,i){return r(t,n,u,(function(r){!r||"EMFILE"!==r.code&&"ENFILE"!==r.code?"function"==typeof o&&o.apply(this,arguments):be([e,[t,n,u,o],r,i||Date.now(),Date.now()])}))}(e,t,n,u)});var u=e.copyFile;u&&(e.copyFile=function(e,t,n,r){"function"==typeof n&&(r=n,n=0);return function e(t,n,r,o,i){return u(t,n,r,(function(u){!u||"EMFILE"!==u.code&&"ENFILE"!==u.code?"function"==typeof o&&o.apply(this,arguments):be([e,[t,n,r,o],u,i||Date.now(),Date.now()])}))}(e,t,n,r)});var o=e.readdir;e.readdir=function(e,t,n){"function"==typeof t&&(n=t,t=null);var r=i.test(process.version)?function(e,t,n,r){return o(e,u(e,t,n,r))}:function(e,t,n,r){return o(e,t,u(e,t,n,r))};return r(e,t,n);function u(e,t,n,u){return function(o,i){!o||"EMFILE"!==o.code&&"ENFILE"!==o.code?(i&&i.sort&&i.sort(),"function"==typeof n&&n.call(this,o,i)):be([r,[e,t,n],o,u||Date.now(),Date.now()])}}};var i=/^v[0-5]\./;if("v0.8"===process.version.substr(0,4)){var s=ye(e);d=s.ReadStream,D=s.WriteStream}var c=e.ReadStream;c&&(d.prototype=Object.create(c.prototype),d.prototype.open=function(){var e=this;E(e.path,e.flags,e.mode,(function(t,n){t?(e.autoClose&&e.destroy(),e.emit("error",t)):(e.fd=n,e.emit("open",n),e.read())}))});var a=e.WriteStream;a&&(D.prototype=Object.create(a.prototype),D.prototype.open=function(){var e=this;E(e.path,e.flags,e.mode,(function(t,n){t?(e.destroy(),e.emit("error",t)):(e.fd=n,e.emit("open",n))}))}),Object.defineProperty(e,"ReadStream",{get:function(){return d},set:function(e){d=e},enumerable:!0,configurable:!0}),Object.defineProperty(e,"WriteStream",{get:function(){return D},set:function(e){D=e},enumerable:!0,configurable:!0});var l=d;Object.defineProperty(e,"FileReadStream",{get:function(){return l},set:function(e){l=e},enumerable:!0,configurable:!0});var f=D;function d(e,t){return this instanceof d?(c.apply(this,arguments),this):d.apply(Object.create(d.prototype),arguments)}function D(e,t){return this instanceof D?(a.apply(this,arguments),this):D.apply(Object.create(D.prototype),arguments)}Object.defineProperty(e,"FileWriteStream",{get:function(){return f},set:function(e){f=e},enumerable:!0,configurable:!0});var p=e.open;function E(e,t,n,r){return"function"==typeof n&&(r=n,n=null),function e(t,n,r,u,o){return p(t,n,r,(function(i,s){!i||"EMFILE"!==i.code&&"ENFILE"!==i.code?"function"==typeof u&&u.apply(this,arguments):be([e,[t,n,r,u],i,o||Date.now(),Date.now()])}))}(e,t,n,r)}return e.open=E,e}function be(e){Ae("ENQUEUE",e[0].name,e[1]),me[pe].push(e),Be()}function _e(){for(var e=Date.now(),t=0;t2&&(me[pe][t][3]=e,me[pe][t][4]=e);Be()}function Be(){if(clearTimeout(Se),Se=void 0,0!==me[pe].length){var e=me[pe].shift(),t=e[0],n=e[1],r=e[2],u=e[3],o=e[4];if(void 0===u)Ae("RETRY",t.name,n),t.apply(null,n);else if(Date.now()-u>=6e4){Ae("TIMEOUT",t.name,n);var i=n.pop();"function"==typeof i&&i.call(null,r)}else{var s=Date.now()-o,c=Math.max(o-u,1);s>=Math.min(1.2*c,100)?(Ae("RETRY",t.name,n),t.apply(null,n.concat([u]))):me[pe].push(e)}void 0===Se&&(Se=setTimeout(Be,0))}}process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH&&!me.__patched&&(we=Oe(me),me.__patched=!0),function(e){const t=re.fromCallback,n=we,r=["access","appendFile","chmod","chown","close","copyFile","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","lchmod","lchown","link","lstat","mkdir","mkdtemp","open","opendir","readdir","readFile","readlink","realpath","rename","rm","rmdir","stat","symlink","truncate","unlink","utimes","writeFile"].filter((e=>"function"==typeof n[e]));Object.assign(e,n),r.forEach((r=>{e[r]=t(n[r])})),e.realpath.native=t(n.realpath.native),e.exists=function(e,t){return"function"==typeof t?n.exists(e,t):new Promise((t=>n.exists(e,t)))},e.read=function(e,t,r,u,o,i){return"function"==typeof i?n.read(e,t,r,u,o,i):new Promise(((i,s)=>{n.read(e,t,r,u,o,((e,t,n)=>{if(e)return s(e);i({bytesRead:t,buffer:n})}))}))},e.write=function(e,t,...r){return"function"==typeof r[r.length-1]?n.write(e,t,...r):new Promise(((u,o)=>{n.write(e,t,...r,((e,t,n)=>{if(e)return o(e);u({bytesWritten:t,buffer:n})}))}))},"function"==typeof n.writev&&(e.writev=function(e,t,...r){return"function"==typeof r[r.length-1]?n.writev(e,t,...r):new Promise(((u,o)=>{n.writev(e,t,...r,((e,t,n)=>{if(e)return o(e);u({bytesWritten:t,buffers:n})}))}))})}(ne);var Pe={},ke={};const xe=p.default;ke.checkPath=function(e){if("win32"===process.platform){if(/[<>:"|?*]/.test(e.replace(xe.parse(e).root,""))){const t=new Error(`Path contains invalid characters: ${e}`);throw t.code="EINVAL",t}}};const Ne=ne,{checkPath:Ie}=ke,Te=e=>"number"==typeof e?e:{mode:511,...e}.mode;Pe.makeDir=async(e,t)=>(Ie(e),Ne.mkdir(e,{mode:Te(t),recursive:!0})),Pe.makeDirSync=(e,t)=>(Ie(e),Ne.mkdirSync(e,{mode:Te(t),recursive:!0}));const Re=re.fromPromise,{makeDir:Me,makeDirSync:Le}=Pe,je=Re(Me);var $e={mkdirs:je,mkdirsSync:Le,mkdirp:je,mkdirpSync:Le,ensureDir:je,ensureDirSync:Le};const He=re.fromPromise,Je=ne;var Ge={pathExists:He((function(e){return Je.access(e).then((()=>!0)).catch((()=>!1))})),pathExistsSync:Je.existsSync};const Ve=we;var Ue=function(e,t,n,r){Ve.open(e,"r+",((e,u)=>{if(e)return r(e);Ve.futimes(u,t,n,(e=>{Ve.close(u,(t=>{r&&r(e||t)}))}))}))},We=function(e,t,n){const r=Ve.openSync(e,"r+");return Ve.futimesSync(r,t,n),Ve.closeSync(r)};const ze=ne,Ke=p.default,qe=F.default;function Ye(e,t,n){const r=n.dereference?e=>ze.stat(e,{bigint:!0}):e=>ze.lstat(e,{bigint:!0});return Promise.all([r(e),r(t).catch((e=>{if("ENOENT"===e.code)return null;throw e}))]).then((([e,t])=>({srcStat:e,destStat:t})))}function Xe(e,t){return t.ino&&t.dev&&t.ino===e.ino&&t.dev===e.dev}function Ze(e,t){const n=Ke.resolve(e).split(Ke.sep).filter((e=>e)),r=Ke.resolve(t).split(Ke.sep).filter((e=>e));return n.reduce(((e,t,n)=>e&&r[n]===t),!0)}function Qe(e,t,n){return`Cannot ${n} '${e}' to a subdirectory of itself, '${t}'.`}var et={checkPaths:function(e,t,n,r,u){qe.callbackify(Ye)(e,t,r,((r,o)=>{if(r)return u(r);const{srcStat:i,destStat:s}=o;if(s){if(Xe(i,s)){const r=Ke.basename(e),o=Ke.basename(t);return"move"===n&&r!==o&&r.toLowerCase()===o.toLowerCase()?u(null,{srcStat:i,destStat:s,isChangingCase:!0}):u(new Error("Source and destination must not be the same."))}if(i.isDirectory()&&!s.isDirectory())return u(new Error(`Cannot overwrite non-directory '${t}' with directory '${e}'.`));if(!i.isDirectory()&&s.isDirectory())return u(new Error(`Cannot overwrite directory '${t}' with non-directory '${e}'.`))}return i.isDirectory()&&Ze(e,t)?u(new Error(Qe(e,t,n))):u(null,{srcStat:i,destStat:s})}))},checkPathsSync:function(e,t,n,r){const{srcStat:u,destStat:o}=function(e,t,n){let r;const u=n.dereference?e=>ze.statSync(e,{bigint:!0}):e=>ze.lstatSync(e,{bigint:!0}),o=u(e);try{r=u(t)}catch(e){if("ENOENT"===e.code)return{srcStat:o,destStat:null};throw e}return{srcStat:o,destStat:r}}(e,t,r);if(o){if(Xe(u,o)){const r=Ke.basename(e),i=Ke.basename(t);if("move"===n&&r!==i&&r.toLowerCase()===i.toLowerCase())return{srcStat:u,destStat:o,isChangingCase:!0};throw new Error("Source and destination must not be the same.")}if(u.isDirectory()&&!o.isDirectory())throw new Error(`Cannot overwrite non-directory '${t}' with directory '${e}'.`);if(!u.isDirectory()&&o.isDirectory())throw new Error(`Cannot overwrite directory '${t}' with non-directory '${e}'.`)}if(u.isDirectory()&&Ze(e,t))throw new Error(Qe(e,t,n));return{srcStat:u,destStat:o}},checkParentPaths:function e(t,n,r,u,o){const i=Ke.resolve(Ke.dirname(t)),s=Ke.resolve(Ke.dirname(r));if(s===i||s===Ke.parse(s).root)return o();ze.stat(s,{bigint:!0},((i,c)=>i?"ENOENT"===i.code?o():o(i):Xe(n,c)?o(new Error(Qe(t,r,u))):e(t,n,s,u,o)))},checkParentPathsSync:function e(t,n,r,u){const o=Ke.resolve(Ke.dirname(t)),i=Ke.resolve(Ke.dirname(r));if(i===o||i===Ke.parse(i).root)return;let s;try{s=ze.statSync(i,{bigint:!0})}catch(e){if("ENOENT"===e.code)return;throw e}if(Xe(n,s))throw new Error(Qe(t,r,u));return e(t,n,i,u)},isSrcSubdir:Ze,areIdentical:Xe};const tt=we,nt=p.default,rt=$e.mkdirs,ut=Ge.pathExists,ot=Ue,it=et;function st(e,t,n,r,u){const o=nt.dirname(n);ut(o,((i,s)=>i?u(i):s?at(e,t,n,r,u):void rt(o,(o=>o?u(o):at(e,t,n,r,u)))))}function ct(e,t,n,r,u,o){Promise.resolve(u.filter(n,r)).then((i=>i?e(t,n,r,u,o):o()),(e=>o(e)))}function at(e,t,n,r,u){(r.dereference?tt.stat:tt.lstat)(t,((o,i)=>o?u(o):i.isDirectory()?function(e,t,n,r,u,o){return t?Dt(n,r,u,o):function(e,t,n,r,u){tt.mkdir(n,(o=>{if(o)return u(o);Dt(t,n,r,(t=>t?u(t):dt(n,e,u)))}))}(e.mode,n,r,u,o)}(i,e,t,n,r,u):i.isFile()||i.isCharacterDevice()||i.isBlockDevice()?function(e,t,n,r,u,o){return t?function(e,t,n,r,u){if(!r.overwrite)return r.errorOnExist?u(new Error(`'${n}' already exists`)):u();tt.unlink(n,(o=>o?u(o):lt(e,t,n,r,u)))}(e,n,r,u,o):lt(e,n,r,u,o)}(i,e,t,n,r,u):i.isSymbolicLink()?function(e,t,n,r,u){tt.readlink(t,((t,o)=>t?u(t):(r.dereference&&(o=nt.resolve(process.cwd(),o)),e?void tt.readlink(n,((t,i)=>t?"EINVAL"===t.code||"UNKNOWN"===t.code?tt.symlink(o,n,u):u(t):(r.dereference&&(i=nt.resolve(process.cwd(),i)),it.isSrcSubdir(o,i)?u(new Error(`Cannot copy '${o}' to a subdirectory of itself, '${i}'.`)):e.isDirectory()&&it.isSrcSubdir(i,o)?u(new Error(`Cannot overwrite '${i}' with '${o}'.`)):function(e,t,n){tt.unlink(t,(r=>r?n(r):tt.symlink(e,t,n)))}(o,n,u)))):tt.symlink(o,n,u))))}(e,t,n,r,u):i.isSocket()?u(new Error(`Cannot copy a socket file: ${t}`)):i.isFIFO()?u(new Error(`Cannot copy a FIFO pipe: ${t}`)):u(new Error(`Unknown file: ${t}`))))}function lt(e,t,n,r,u){tt.copyFile(t,n,(o=>o?u(o):r.preserveTimestamps?function(e,t,n,r){if(function(e){return 0==(128&e)}(e))return function(e,t,n){return dt(e,128|t,n)}(n,e,(u=>u?r(u):ft(e,t,n,r)));return ft(e,t,n,r)}(e.mode,t,n,u):dt(n,e.mode,u)))}function ft(e,t,n,r){!function(e,t,n){tt.stat(e,((e,r)=>e?n(e):ot(t,r.atime,r.mtime,n)))}(t,n,(t=>t?r(t):dt(n,e,r)))}function dt(e,t,n){return tt.chmod(e,t,n)}function Dt(e,t,n,r){tt.readdir(e,((u,o)=>u?r(u):pt(o,e,t,n,r)))}function pt(e,t,n,r,u){const o=e.pop();return o?function(e,t,n,r,u,o){const i=nt.join(n,t),s=nt.join(r,t);it.checkPaths(i,s,"copy",u,((t,c)=>{if(t)return o(t);const{destStat:a}=c;!function(e,t,n,r,u){r.filter?ct(at,e,t,n,r,u):at(e,t,n,r,u)}(a,i,s,u,(t=>t?o(t):pt(e,n,r,u,o)))}))}(e,o,t,n,r,u):u()}var Et=function(e,t,n,r){"function"!=typeof n||r?"function"==typeof n&&(n={filter:n}):(r=n,n={}),r=r||function(){},(n=n||{}).clobber=!("clobber"in n)||!!n.clobber,n.overwrite="overwrite"in n?!!n.overwrite:n.clobber,n.preserveTimestamps&&"ia32"===process.arch&&console.warn("fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;\n\n see https://github.com/jprichardson/node-fs-extra/issues/269"),it.checkPaths(e,t,"copy",n,((u,o)=>{if(u)return r(u);const{srcStat:i,destStat:s}=o;it.checkParentPaths(e,i,t,"copy",(u=>u?r(u):n.filter?ct(st,s,e,t,n,r):st(s,e,t,n,r)))}))};const mt=we,ht=p.default,yt=$e.mkdirsSync,Ct=We,Ft=et;function gt(e,t,n,r){const u=(r.dereference?mt.statSync:mt.lstatSync)(t);if(u.isDirectory())return function(e,t,n,r,u){return t?St(n,r,u):function(e,t,n,r){return mt.mkdirSync(n),St(t,n,r),vt(n,e)}(e.mode,n,r,u)}(u,e,t,n,r);if(u.isFile()||u.isCharacterDevice()||u.isBlockDevice())return function(e,t,n,r,u){return t?function(e,t,n,r){if(r.overwrite)return mt.unlinkSync(n),At(e,t,n,r);if(r.errorOnExist)throw new Error(`'${n}' already exists`)}(e,n,r,u):At(e,n,r,u)}(u,e,t,n,r);if(u.isSymbolicLink())return function(e,t,n,r){let u=mt.readlinkSync(t);r.dereference&&(u=ht.resolve(process.cwd(),u));if(e){let e;try{e=mt.readlinkSync(n)}catch(e){if("EINVAL"===e.code||"UNKNOWN"===e.code)return mt.symlinkSync(u,n);throw e}if(r.dereference&&(e=ht.resolve(process.cwd(),e)),Ft.isSrcSubdir(u,e))throw new Error(`Cannot copy '${u}' to a subdirectory of itself, '${e}'.`);if(mt.statSync(n).isDirectory()&&Ft.isSrcSubdir(e,u))throw new Error(`Cannot overwrite '${e}' with '${u}'.`);return function(e,t){return mt.unlinkSync(t),mt.symlinkSync(e,t)}(u,n)}return mt.symlinkSync(u,n)}(e,t,n,r);if(u.isSocket())throw new Error(`Cannot copy a socket file: ${t}`);if(u.isFIFO())throw new Error(`Cannot copy a FIFO pipe: ${t}`);throw new Error(`Unknown file: ${t}`)}function At(e,t,n,r){return mt.copyFileSync(t,n),r.preserveTimestamps&&function(e,t,n){(function(e){return 0==(128&e)})(e)&&function(e,t){vt(e,128|t)}(n,e);(function(e,t){const n=mt.statSync(e);Ct(t,n.atime,n.mtime)})(t,n)}(e.mode,t,n),vt(n,e.mode)}function vt(e,t){return mt.chmodSync(e,t)}function St(e,t,n){mt.readdirSync(e).forEach((r=>function(e,t,n,r){const u=ht.join(t,e),o=ht.join(n,e),{destStat:i}=Ft.checkPathsSync(u,o,"copy",r);return function(e,t,n,r){if(!r.filter||r.filter(t,n))return gt(e,t,n,r)}(i,u,o,r)}(r,e,t,n)))}var wt=function(e,t,n){"function"==typeof n&&(n={filter:n}),(n=n||{}).clobber=!("clobber"in n)||!!n.clobber,n.overwrite="overwrite"in n?!!n.overwrite:n.clobber,n.preserveTimestamps&&"ia32"===process.arch&&console.warn("fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;\n\n see https://github.com/jprichardson/node-fs-extra/issues/269");const{srcStat:r,destStat:u}=Ft.checkPathsSync(e,t,"copy",n);return Ft.checkParentPathsSync(e,r,t,"copy"),function(e,t,n,r){if(r.filter&&!r.filter(t,n))return;const u=ht.dirname(n);mt.existsSync(u)||yt(u);return gt(e,t,n,r)}(u,e,t,n)};var Ot={copy:(0,re.fromCallback)(Et),copySync:wt};const bt=we,_t=p.default,Bt=g.default,Pt="win32"===process.platform;function kt(e){["unlink","chmod","stat","lstat","rmdir","readdir"].forEach((t=>{e[t]=e[t]||bt[t],e[t+="Sync"]=e[t]||bt[t]})),e.maxBusyTries=e.maxBusyTries||3}function xt(e,t,n){let r=0;"function"==typeof t&&(n=t,t={}),Bt(e,"rimraf: missing path"),Bt.strictEqual(typeof e,"string","rimraf: path should be a string"),Bt.strictEqual(typeof n,"function","rimraf: callback function required"),Bt(t,"rimraf: invalid options argument provided"),Bt.strictEqual(typeof t,"object","rimraf: options should be object"),kt(t),Nt(e,t,(function u(o){if(o){if(("EBUSY"===o.code||"ENOTEMPTY"===o.code||"EPERM"===o.code)&&rNt(e,t,u)),100*r)}"ENOENT"===o.code&&(o=null)}n(o)}))}function Nt(e,t,n){Bt(e),Bt(t),Bt("function"==typeof n),t.lstat(e,((r,u)=>r&&"ENOENT"===r.code?n(null):r&&"EPERM"===r.code&&Pt?It(e,t,r,n):u&&u.isDirectory()?Rt(e,t,r,n):void t.unlink(e,(r=>{if(r){if("ENOENT"===r.code)return n(null);if("EPERM"===r.code)return Pt?It(e,t,r,n):Rt(e,t,r,n);if("EISDIR"===r.code)return Rt(e,t,r,n)}return n(r)}))))}function It(e,t,n,r){Bt(e),Bt(t),Bt("function"==typeof r),t.chmod(e,438,(u=>{u?r("ENOENT"===u.code?null:n):t.stat(e,((u,o)=>{u?r("ENOENT"===u.code?null:n):o.isDirectory()?Rt(e,t,n,r):t.unlink(e,r)}))}))}function Tt(e,t,n){let r;Bt(e),Bt(t);try{t.chmodSync(e,438)}catch(e){if("ENOENT"===e.code)return;throw n}try{r=t.statSync(e)}catch(e){if("ENOENT"===e.code)return;throw n}r.isDirectory()?Lt(e,t,n):t.unlinkSync(e)}function Rt(e,t,n,r){Bt(e),Bt(t),Bt("function"==typeof r),t.rmdir(e,(u=>{!u||"ENOTEMPTY"!==u.code&&"EEXIST"!==u.code&&"EPERM"!==u.code?u&&"ENOTDIR"===u.code?r(n):r(u):function(e,t,n){Bt(e),Bt(t),Bt("function"==typeof n),t.readdir(e,((r,u)=>{if(r)return n(r);let o,i=u.length;if(0===i)return t.rmdir(e,n);u.forEach((r=>{xt(_t.join(e,r),t,(r=>{if(!o)return r?n(o=r):void(0==--i&&t.rmdir(e,n))}))}))}))}(e,t,r)}))}function Mt(e,t){let n;kt(t=t||{}),Bt(e,"rimraf: missing path"),Bt.strictEqual(typeof e,"string","rimraf: path should be a string"),Bt(t,"rimraf: missing options"),Bt.strictEqual(typeof t,"object","rimraf: options should be object");try{n=t.lstatSync(e)}catch(n){if("ENOENT"===n.code)return;"EPERM"===n.code&&Pt&&Tt(e,t,n)}try{n&&n.isDirectory()?Lt(e,t,null):t.unlinkSync(e)}catch(n){if("ENOENT"===n.code)return;if("EPERM"===n.code)return Pt?Tt(e,t,n):Lt(e,t,n);if("EISDIR"!==n.code)throw n;Lt(e,t,n)}}function Lt(e,t,n){Bt(e),Bt(t);try{t.rmdirSync(e)}catch(r){if("ENOTDIR"===r.code)throw n;if("ENOTEMPTY"===r.code||"EEXIST"===r.code||"EPERM"===r.code)!function(e,t){if(Bt(e),Bt(t),t.readdirSync(e).forEach((n=>Mt(_t.join(e,n),t))),!Pt){return t.rmdirSync(e,t)}{const n=Date.now();do{try{return t.rmdirSync(e,t)}catch{}}while(Date.now()-n<500)}}(e,t);else if("ENOENT"!==r.code)throw r}}var jt=xt;xt.sync=Mt;const $t=we,Ht=re.fromCallback,Jt=jt;var Gt={remove:Ht((function(e,t){if($t.rm)return $t.rm(e,{recursive:!0,force:!0},t);Jt(e,t)})),removeSync:function(e){if($t.rmSync)return $t.rmSync(e,{recursive:!0,force:!0});Jt.sync(e)}};const Vt=re.fromPromise,Ut=ne,Wt=p.default,zt=$e,Kt=Gt,qt=Vt((async function(e){let t;try{t=await Ut.readdir(e)}catch{return zt.mkdirs(e)}return Promise.all(t.map((t=>Kt.remove(Wt.join(e,t)))))}));function Yt(e){let t;try{t=Ut.readdirSync(e)}catch{return zt.mkdirsSync(e)}t.forEach((t=>{t=Wt.join(e,t),Kt.removeSync(t)}))}var Xt={emptyDirSync:Yt,emptydirSync:Yt,emptyDir:qt,emptydir:qt};const Zt=re.fromCallback,Qt=p.default,en=we,tn=$e;var nn={createFile:Zt((function(e,t){function n(){en.writeFile(e,"",(e=>{if(e)return t(e);t()}))}en.stat(e,((r,u)=>{if(!r&&u.isFile())return t();const o=Qt.dirname(e);en.stat(o,((e,r)=>{if(e)return"ENOENT"===e.code?tn.mkdirs(o,(e=>{if(e)return t(e);n()})):t(e);r.isDirectory()?n():en.readdir(o,(e=>{if(e)return t(e)}))}))}))})),createFileSync:function(e){let t;try{t=en.statSync(e)}catch{}if(t&&t.isFile())return;const n=Qt.dirname(e);try{en.statSync(n).isDirectory()||en.readdirSync(n)}catch(e){if(!e||"ENOENT"!==e.code)throw e;tn.mkdirsSync(n)}en.writeFileSync(e,"")}};const rn=re.fromCallback,un=p.default,on=we,sn=$e,cn=Ge.pathExists,{areIdentical:an}=et;var ln={createLink:rn((function(e,t,n){function r(e,t){on.link(e,t,(e=>{if(e)return n(e);n(null)}))}on.lstat(t,((u,o)=>{on.lstat(e,((u,i)=>{if(u)return u.message=u.message.replace("lstat","ensureLink"),n(u);if(o&&an(i,o))return n(null);const s=un.dirname(t);cn(s,((u,o)=>u?n(u):o?r(e,t):void sn.mkdirs(s,(u=>{if(u)return n(u);r(e,t)}))))}))}))})),createLinkSync:function(e,t){let n;try{n=on.lstatSync(t)}catch{}try{const t=on.lstatSync(e);if(n&&an(t,n))return}catch(e){throw e.message=e.message.replace("lstat","ensureLink"),e}const r=un.dirname(t);return on.existsSync(r)||sn.mkdirsSync(r),on.linkSync(e,t)}};const fn=p.default,dn=we,Dn=Ge.pathExists;var pn={symlinkPaths:function(e,t,n){if(fn.isAbsolute(e))return dn.lstat(e,(t=>t?(t.message=t.message.replace("lstat","ensureSymlink"),n(t)):n(null,{toCwd:e,toDst:e})));{const r=fn.dirname(t),u=fn.join(r,e);return Dn(u,((t,o)=>t?n(t):o?n(null,{toCwd:u,toDst:e}):dn.lstat(e,(t=>t?(t.message=t.message.replace("lstat","ensureSymlink"),n(t)):n(null,{toCwd:e,toDst:fn.relative(r,e)})))))}},symlinkPathsSync:function(e,t){let n;if(fn.isAbsolute(e)){if(n=dn.existsSync(e),!n)throw new Error("absolute srcpath does not exist");return{toCwd:e,toDst:e}}{const r=fn.dirname(t),u=fn.join(r,e);if(n=dn.existsSync(u),n)return{toCwd:u,toDst:e};if(n=dn.existsSync(e),!n)throw new Error("relative srcpath does not exist");return{toCwd:e,toDst:fn.relative(r,e)}}}};const En=we;var mn={symlinkType:function(e,t,n){if(n="function"==typeof t?t:n,t="function"!=typeof t&&t)return n(null,t);En.lstat(e,((e,r)=>{if(e)return n(null,"file");t=r&&r.isDirectory()?"dir":"file",n(null,t)}))},symlinkTypeSync:function(e,t){let n;if(t)return t;try{n=En.lstatSync(e)}catch{return"file"}return n&&n.isDirectory()?"dir":"file"}};const hn=re.fromCallback,yn=p.default,Cn=ne,Fn=$e.mkdirs,gn=$e.mkdirsSync,An=pn.symlinkPaths,vn=pn.symlinkPathsSync,Sn=mn.symlinkType,wn=mn.symlinkTypeSync,On=Ge.pathExists,{areIdentical:bn}=et;function _n(e,t,n,r){An(e,t,((u,o)=>{if(u)return r(u);e=o.toDst,Sn(o.toCwd,n,((n,u)=>{if(n)return r(n);const o=yn.dirname(t);On(o,((n,i)=>n?r(n):i?Cn.symlink(e,t,u,r):void Fn(o,(n=>{if(n)return r(n);Cn.symlink(e,t,u,r)}))))}))}))}var Bn={createSymlink:hn((function(e,t,n,r){r="function"==typeof n?n:r,n="function"!=typeof n&&n,Cn.lstat(t,((u,o)=>{!u&&o.isSymbolicLink()?Promise.all([Cn.stat(e),Cn.stat(t)]).then((([u,o])=>{if(bn(u,o))return r(null);_n(e,t,n,r)})):_n(e,t,n,r)}))})),createSymlinkSync:function(e,t,n){let r;try{r=Cn.lstatSync(t)}catch{}if(r&&r.isSymbolicLink()){const n=Cn.statSync(e),r=Cn.statSync(t);if(bn(n,r))return}const u=vn(e,t);e=u.toDst,n=wn(u.toCwd,n);const o=yn.dirname(t);return Cn.existsSync(o)||gn(o),Cn.symlinkSync(e,t,n)}};const{createFile:Pn,createFileSync:kn}=nn,{createLink:xn,createLinkSync:Nn}=ln,{createSymlink:In,createSymlinkSync:Tn}=Bn;var Rn={createFile:Pn,createFileSync:kn,ensureFile:Pn,ensureFileSync:kn,createLink:xn,createLinkSync:Nn,ensureLink:xn,ensureLinkSync:Nn,createSymlink:In,createSymlinkSync:Tn,ensureSymlink:In,ensureSymlinkSync:Tn};var Mn={stringify:function(e,{EOL:t="\n",finalEOL:n=!0,replacer:r=null,spaces:u}={}){const o=n?t:"";return JSON.stringify(e,r,u).replace(/\n/g,t)+o},stripBom:function(e){return Buffer.isBuffer(e)&&(e=e.toString("utf8")),e.replace(/^\uFEFF/,"")}};let Ln;try{Ln=we}catch(e){Ln=D.default}const jn=re,{stringify:$n,stripBom:Hn}=Mn;const Jn=jn.fromPromise((async function(e,t={}){"string"==typeof t&&(t={encoding:t});const n=t.fs||Ln,r=!("throws"in t)||t.throws;let u,o=await jn.fromCallback(n.readFile)(e,t);o=Hn(o);try{u=JSON.parse(o,t?t.reviver:null)}catch(t){if(r)throw t.message=`${e}: ${t.message}`,t;return null}return u}));const Gn=jn.fromPromise((async function(e,t,n={}){const r=n.fs||Ln,u=$n(t,n);await jn.fromCallback(r.writeFile)(e,u,n)}));const Vn={readFile:Jn,readFileSync:function(e,t={}){"string"==typeof t&&(t={encoding:t});const n=t.fs||Ln,r=!("throws"in t)||t.throws;try{let r=n.readFileSync(e,t);return r=Hn(r),JSON.parse(r,t.reviver)}catch(t){if(r)throw t.message=`${e}: ${t.message}`,t;return null}},writeFile:Gn,writeFileSync:function(e,t,n={}){const r=n.fs||Ln,u=$n(t,n);return r.writeFileSync(e,u,n)}};var Un={readJson:Vn.readFile,readJsonSync:Vn.readFileSync,writeJson:Vn.writeFile,writeJsonSync:Vn.writeFileSync};const Wn=re.fromCallback,zn=we,Kn=p.default,qn=$e,Yn=Ge.pathExists;var Xn={outputFile:Wn((function(e,t,n,r){"function"==typeof n&&(r=n,n="utf8");const u=Kn.dirname(e);Yn(u,((o,i)=>o?r(o):i?zn.writeFile(e,t,n,r):void qn.mkdirs(u,(u=>{if(u)return r(u);zn.writeFile(e,t,n,r)}))))})),outputFileSync:function(e,...t){const n=Kn.dirname(e);if(zn.existsSync(n))return zn.writeFileSync(e,...t);qn.mkdirsSync(n),zn.writeFileSync(e,...t)}};const{stringify:Zn}=Mn,{outputFile:Qn}=Xn;var er=async function(e,t,n={}){const r=Zn(t,n);await Qn(e,r,n)};const{stringify:tr}=Mn,{outputFileSync:nr}=Xn;var rr=function(e,t,n){const r=tr(t,n);nr(e,r,n)};const ur=re.fromPromise,or=Un;or.outputJson=ur(er),or.outputJsonSync=rr,or.outputJSON=or.outputJson,or.outputJSONSync=or.outputJsonSync,or.writeJSON=or.writeJson,or.writeJSONSync=or.writeJsonSync,or.readJSON=or.readJson,or.readJSONSync=or.readJsonSync;var ir=or;const sr=we,cr=p.default,ar=Ot.copy,lr=Gt.remove,fr=$e.mkdirp,dr=Ge.pathExists,Dr=et;function pr(e,t,n,r,u){return r?Er(e,t,n,u):n?lr(t,(r=>r?u(r):Er(e,t,n,u))):void dr(t,((r,o)=>r?u(r):o?u(new Error("dest already exists.")):Er(e,t,n,u)))}function Er(e,t,n,r){sr.rename(e,t,(u=>u?"EXDEV"!==u.code?r(u):function(e,t,n,r){const u={overwrite:n,errorOnExist:!0};ar(e,t,u,(t=>t?r(t):lr(e,r)))}(e,t,n,r):r()))}var mr=function(e,t,n,r){"function"==typeof n&&(r=n,n={});const u=n.overwrite||n.clobber||!1;Dr.checkPaths(e,t,"move",n,((n,o)=>{if(n)return r(n);const{srcStat:i,isChangingCase:s=!1}=o;Dr.checkParentPaths(e,i,t,"move",(n=>n?r(n):function(e){const t=cr.dirname(e);return cr.parse(t).root===t}(t)?pr(e,t,u,s,r):void fr(cr.dirname(t),(n=>n?r(n):pr(e,t,u,s,r)))))}))};const hr=we,yr=p.default,Cr=Ot.copySync,Fr=Gt.removeSync,gr=$e.mkdirpSync,Ar=et;function vr(e,t,n){try{hr.renameSync(e,t)}catch(r){if("EXDEV"!==r.code)throw r;return function(e,t,n){const r={overwrite:n,errorOnExist:!0};return Cr(e,t,r),Fr(e)}(e,t,n)}}var Sr=function(e,t,n){const r=(n=n||{}).overwrite||n.clobber||!1,{srcStat:u,isChangingCase:o=!1}=Ar.checkPathsSync(e,t,"move",n);return Ar.checkParentPathsSync(e,u,t,"move"),function(e){const t=yr.dirname(e);return yr.parse(t).root===t}(t)||gr(yr.dirname(t)),function(e,t,n,r){if(r)return vr(e,t,n);if(n)return Fr(t),vr(e,t,n);if(hr.existsSync(t))throw new Error("dest already exists.");return vr(e,t,n)}(e,t,r,o)};var wr,Or,br,_r,Br,Pr={move:(0,re.fromCallback)(mr),moveSync:Sr},kr={...ne,...Ot,...Xt,...Rn,...ir,...$e,...Pr,...Xn,...Ge,...Gt},xr={},Nr={exports:{}},Ir={exports:{}};function Tr(){if(Or)return wr;Or=1;var e=1e3,t=60*e,n=60*t,r=24*n,u=7*r,o=365.25*r;function i(e,t,n,r){var u=t>=1.5*n;return Math.round(e/n)+" "+r+(u?"s":"")}return wr=function(s,c){c=c||{};var a=typeof s;if("string"===a&&s.length>0)return function(i){if((i=String(i)).length>100)return;var s=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(i);if(!s)return;var c=parseFloat(s[1]);switch((s[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return c*o;case"weeks":case"week":case"w":return c*u;case"days":case"day":case"d":return c*r;case"hours":case"hour":case"hrs":case"hr":case"h":return c*n;case"minutes":case"minute":case"mins":case"min":case"m":return c*t;case"seconds":case"second":case"secs":case"sec":case"s":return c*e;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return c;default:return}}(s);if("number"===a&&isFinite(s))return c.long?function(u){var o=Math.abs(u);if(o>=r)return i(u,o,r,"day");if(o>=n)return i(u,o,n,"hour");if(o>=t)return i(u,o,t,"minute");if(o>=e)return i(u,o,e,"second");return u+" ms"}(s):function(u){var o=Math.abs(u);if(o>=r)return Math.round(u/r)+"d";if(o>=n)return Math.round(u/n)+"h";if(o>=t)return Math.round(u/t)+"m";if(o>=e)return Math.round(u/e)+"s";return u+"ms"}(s);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(s))}}function Rr(){if(_r)return br;return _r=1,br=function(e){function t(e){let r,u,o,i=null;function s(...e){if(!s.enabled)return;const n=s,u=Number(new Date),o=u-(r||u);n.diff=o,n.prev=r,n.curr=u,r=u,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((r,u)=>{if("%%"===r)return"%";i++;const o=t.formatters[u];if("function"==typeof o){const t=e[i];r=o.call(n,t),e.splice(i,1),i--}return r})),t.formatArgs.call(n,e);(n.log||t.log).apply(n,e)}return s.namespace=e,s.useColors=t.useColors(),s.color=t.selectColor(e),s.extend=n,s.destroy=t.destroy,Object.defineProperty(s,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(u!==t.namespaces&&(u=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(s),s}function n(e,n){const r=t(this.namespace+(void 0===n?":":n)+e);return r.log=this.log,r}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){if(e instanceof Error)return e.stack||e.message;return e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let n;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const r=("string"==typeof e?e:"").split(/[\s,]+/),u=r.length;for(n=0;n{t[n]=e[n]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;t{const n=e.startsWith("-")?"":1===e.length?"-":"--",r=t.indexOf(n+e),u=t.indexOf("--");return-1!==r&&(-1===u||r{}),"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."),t.colors=[6,2,3,4,5,1];try{const e=function(){if($r)return jr;$r=1;const e=E.default,t=A.default,n=Vr(),{env:r}=process;let u;function o(e){return 0!==e&&{level:e,hasBasic:!0,has256:e>=2,has16m:e>=3}}function i(t,o){if(0===u)return 0;if(n("color=16m")||n("color=full")||n("color=truecolor"))return 3;if(n("color=256"))return 2;if(t&&!o&&void 0===u)return 0;const i=u||0;if("dumb"===r.TERM)return i;if("win32"===process.platform){const t=e.release().split(".");return Number(t[0])>=10&&Number(t[2])>=10586?Number(t[2])>=14931?3:2:1}if("CI"in r)return["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI","GITHUB_ACTIONS","BUILDKITE"].some((e=>e in r))||"codeship"===r.CI_NAME?1:i;if("TEAMCITY_VERSION"in r)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(r.TEAMCITY_VERSION)?1:0;if("truecolor"===r.COLORTERM)return 3;if("TERM_PROGRAM"in r){const e=parseInt((r.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(r.TERM_PROGRAM){case"iTerm.app":return e>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(r.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(r.TERM)||"COLORTERM"in r?1:i}return n("no-color")||n("no-colors")||n("color=false")||n("color=never")?u=0:(n("color")||n("colors")||n("color=true")||n("color=always"))&&(u=1),"FORCE_COLOR"in r&&(u="true"===r.FORCE_COLOR?1:"false"===r.FORCE_COLOR?0:0===r.FORCE_COLOR.length?1:Math.min(parseInt(r.FORCE_COLOR,10),3)),jr={supportsColor:function(e){return o(i(e,e&&e.isTTY))},stdout:o(i(!0,t.isatty(1))),stderr:o(i(!0,t.isatty(2)))}}();e&&(e.stderr||e).level>=2&&(t.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch(e){}t.inspectOpts=Object.keys(process.env).filter((e=>/^debug_/i.test(e))).reduce(((e,t)=>{const n=t.substring(6).toLowerCase().replace(/_([a-z])/g,((e,t)=>t.toUpperCase()));let r=process.env[t];return r=!!/^(yes|on|true|enabled)$/i.test(r)||!/^(no|off|false|disabled)$/i.test(r)&&("null"===r?null:Number(r)),e[n]=r,e}),{}),e.exports=Rr()(t);const{formatters:u}=e.exports;u.o=function(e){return this.inspectOpts.colors=this.useColors,r.inspect(e,this.inspectOpts).split("\n").map((e=>e.trim())).join(" ")},u.O=function(e){return this.inspectOpts.colors=this.useColors,r.inspect(e,this.inspectOpts)}}(Gr,Gr.exports)),Gr.exports}Jr=Nr,"undefined"==typeof process||"renderer"===process.type||!0===process.browser||process.__nwjs?Jr.exports=(Br||(Br=1,function(e,t){t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;t.splice(1,0,n,"color: inherit");let r=0,u=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(r++,"%c"===e&&(u=r))})),t.splice(u,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=Rr()(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}}(Ir,Ir.exports)),Ir.exports):Jr.exports=Ur();var Wr=function(e){return(e=e||{}).circles?function(e){var t=[],n=[];return e.proto?function e(u){if("object"!=typeof u||null===u)return u;if(u instanceof Date)return new Date(u);if(Array.isArray(u))return r(u,e);if(u instanceof Map)return new Map(r(Array.from(u),e));if(u instanceof Set)return new Set(r(Array.from(u),e));var o={};for(var i in t.push(u),n.push(o),u){var s=u[i];if("object"!=typeof s||null===s)o[i]=s;else if(s instanceof Date)o[i]=new Date(s);else if(s instanceof Map)o[i]=new Map(r(Array.from(s),e));else if(s instanceof Set)o[i]=new Set(r(Array.from(s),e));else if(ArrayBuffer.isView(s))o[i]=zr(s);else{var c=t.indexOf(s);o[i]=-1!==c?n[c]:e(s)}}return t.pop(),n.pop(),o}:function e(u){if("object"!=typeof u||null===u)return u;if(u instanceof Date)return new Date(u);if(Array.isArray(u))return r(u,e);if(u instanceof Map)return new Map(r(Array.from(u),e));if(u instanceof Set)return new Set(r(Array.from(u),e));var o={};for(var i in t.push(u),n.push(o),u)if(!1!==Object.hasOwnProperty.call(u,i)){var s=u[i];if("object"!=typeof s||null===s)o[i]=s;else if(s instanceof Date)o[i]=new Date(s);else if(s instanceof Map)o[i]=new Map(r(Array.from(s),e));else if(s instanceof Set)o[i]=new Set(r(Array.from(s),e));else if(ArrayBuffer.isView(s))o[i]=zr(s);else{var c=t.indexOf(s);o[i]=-1!==c?n[c]:e(s)}}return t.pop(),n.pop(),o};function r(e,r){for(var u=Object.keys(e),o=new Array(u.length),i=0;i!e,Qr=e=>e&&"object"==typeof e&&!Array.isArray(e),eu=(e,t,n)=>{(Array.isArray(t)?t:[t]).forEach((t=>{if(t)throw new Error(`Problem with log4js configuration: (${Kr.inspect(e,{depth:5})}) - ${n}`)}))};var tu={configure:e=>{qr("New configuration to be validated: ",e),eu(e,Zr(Qr(e)),"must be an object."),qr(`Calling pre-processing listeners (${Yr.length})`),Yr.forEach((t=>t(e))),qr("Configuration pre-processing finished."),qr(`Calling configuration listeners (${Xr.length})`),Xr.forEach((t=>t(e))),qr("Configuration finished.")},addListener:e=>{Xr.push(e),qr(`Added listener, now ${Xr.length} listeners`)},addPreProcessingListener:e=>{Yr.push(e),qr(`Added pre-processing listener, now ${Yr.length} listeners`)},throwExceptionIf:eu,anObject:Qr,anInteger:e=>e&&"number"==typeof e&&Number.isInteger(e),validIdentifier:e=>/^[A-Za-z][A-Za-z0-9_]*$/g.test(e),not:Zr},nu={exports:{}};!function(e){function t(e,t){for(var n=e.toString();n.length-1?s:c,l=n(u.getHours()),f=n(u.getMinutes()),d=n(u.getSeconds()),D=t(u.getMilliseconds(),3),p=function(e){var t=Math.abs(e),n=String(Math.floor(t/60)),r=String(t%60);return n=("0"+n).slice(-2),r=("0"+r).slice(-2),0===e?"Z":(e<0?"+":"-")+n+":"+r}(u.getTimezoneOffset());return r.replace(/dd/g,o).replace(/MM/g,i).replace(/y{1,4}/g,a).replace(/hh/g,l).replace(/mm/g,f).replace(/ss/g,d).replace(/SSS/g,D).replace(/O/g,p)}function u(e,t,n,r){e["set"+(r?"":"UTC")+t](n)}e.exports=r,e.exports.asString=r,e.exports.parse=function(t,n,r){if(!t)throw new Error("pattern must be supplied");return function(t,n,r){var o=t.indexOf("O")<0,i=!1,s=[{pattern:/y{1,4}/,regexp:"\\d{1,4}",fn:function(e,t){u(e,"FullYear",t,o)}},{pattern:/MM/,regexp:"\\d{1,2}",fn:function(e,t){u(e,"Month",t-1,o),e.getMonth()!==t-1&&(i=!0)}},{pattern:/dd/,regexp:"\\d{1,2}",fn:function(e,t){i&&u(e,"Month",e.getMonth()-1,o),u(e,"Date",t,o)}},{pattern:/hh/,regexp:"\\d{1,2}",fn:function(e,t){u(e,"Hours",t,o)}},{pattern:/mm/,regexp:"\\d\\d",fn:function(e,t){u(e,"Minutes",t,o)}},{pattern:/ss/,regexp:"\\d\\d",fn:function(e,t){u(e,"Seconds",t,o)}},{pattern:/SSS/,regexp:"\\d\\d\\d",fn:function(e,t){u(e,"Milliseconds",t,o)}},{pattern:/O/,regexp:"[+-]\\d{1,2}:?\\d{2}?|Z",fn:function(e,t){t="Z"===t?0:t.replace(":","");var n=Math.abs(t),r=(t>0?-1:1)*(n%100+60*Math.floor(n/100));e.setUTCMinutes(e.getUTCMinutes()+r)}}],c=s.reduce((function(e,t){return t.pattern.test(e.regexp)?(t.index=e.regexp.match(t.pattern).index,e.regexp=e.regexp.replace(t.pattern,"("+t.regexp+")")):t.index=-1,e}),{regexp:t,index:[]}),a=s.filter((function(e){return e.index>-1}));a.sort((function(e,t){return e.index-t.index}));var l=new RegExp(c.regexp).exec(n);if(l){var f=r||e.exports.now();return a.forEach((function(e,t){e.fn(f,l[t+1])})),f}throw new Error("String '"+n+"' could not be parsed as '"+t+"'")}(t,n,r)},e.exports.now=function(){return new Date},e.exports.ISO8601_FORMAT="yyyy-MM-ddThh:mm:ss.SSS",e.exports.ISO8601_WITH_TZ_OFFSET_FORMAT="yyyy-MM-ddThh:mm:ss.SSSO",e.exports.DATETIME_FORMAT="dd MM yyyy hh:mm:ss.SSS",e.exports.ABSOLUTETIME_FORMAT="hh:mm:ss.SSS"}(nu);const ru=nu.exports,uu=E.default,ou=F.default,iu=p.default,su={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[90,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[91,39],yellow:[33,39]};function cu(e){return e?`[${su[e][0]}m`:""}function au(e){return e?`[${su[e][1]}m`:""}function lu(e,t){return n=ou.format("[%s] [%s] %s - ",ru.asString(e.startTime),e.level.toString(),e.categoryName),cu(r=t)+n+au(r);var n,r}function fu(e){return lu(e)+ou.format(...e.data)}function du(e){return lu(e,e.level.colour)+ou.format(...e.data)}function Du(e){return ou.format(...e.data)}function pu(e){return e.data[0]}function Eu(e,t){const n=/%(-?[0-9]+)?(\.?-?[0-9]+)?([[\]cdhmnprzxXyflos%])(\{([^}]+)\})?|([^%]+)/;function r(e){return e&&e.pid?e.pid.toString():process.pid.toString()}e=e||"%r %p %c - %m%n";const u={c:function(e,t){let n=e.categoryName;if(t){const e=parseInt(t,10),r=n.split(".");ee&&(n=r.slice(-e).join(iu.sep))}return n},l:function(e){return e.lineNumber?`${e.lineNumber}`:""},o:function(e){return e.columnNumber?`${e.columnNumber}`:""},s:function(e){return e.callStack||""}};function o(e,t,n){return u[e](t,n)}function i(e,t,n){let r=e;return r=function(e,t){let n;return e?(n=parseInt(e.substr(1),10),n>0?t.slice(0,n):t.slice(n)):t}(t,r),r=function(e,t){let n;if(e)if("-"===e.charAt(0))for(n=parseInt(e.substr(1),10);t.lengthDu,basic:()=>fu,colored:()=>du,coloured:()=>du,pattern:e=>Eu(e&&e.pattern,e&&e.tokens),dummy:()=>pu};var hu={basicLayout:fu,messagePassThroughLayout:Du,patternLayout:Eu,colouredLayout:du,coloredLayout:du,dummyLayout:pu,addLayout(e,t){mu[e]=t},layout:(e,t)=>mu[e]&&mu[e](t)};const yu=tu,Cu=["white","grey","black","blue","cyan","green","magenta","red","yellow"];class Fu{constructor(e,t,n){this.level=e,this.levelStr=t,this.colour=n}toString(){return this.levelStr}static getLevel(e,t){return e?e instanceof Fu?e:(e instanceof Object&&e.levelStr&&(e=e.levelStr),Fu[e.toString().toUpperCase()]||t):t}static addLevels(e){if(e){Object.keys(e).forEach((t=>{const n=t.toUpperCase();Fu[n]=new Fu(e[t].value,n,e[t].colour);const r=Fu.levels.findIndex((e=>e.levelStr===n));r>-1?Fu.levels[r]=Fu[n]:Fu.levels.push(Fu[n])})),Fu.levels.sort(((e,t)=>e.level-t.level))}}isLessThanOrEqualTo(e){return"string"==typeof e&&(e=Fu.getLevel(e)),this.level<=e.level}isGreaterThanOrEqualTo(e){return"string"==typeof e&&(e=Fu.getLevel(e)),this.level>=e.level}isEqualTo(e){return"string"==typeof e&&(e=Fu.getLevel(e)),this.level===e.level}}Fu.levels=[],Fu.addLevels({ALL:{value:Number.MIN_VALUE,colour:"grey"},TRACE:{value:5e3,colour:"blue"},DEBUG:{value:1e4,colour:"cyan"},INFO:{value:2e4,colour:"green"},WARN:{value:3e4,colour:"yellow"},ERROR:{value:4e4,colour:"red"},FATAL:{value:5e4,colour:"magenta"},MARK:{value:9007199254740992,colour:"grey"},OFF:{value:Number.MAX_VALUE,colour:"grey"}}),yu.addListener((e=>{const t=e.levels;if(t){yu.throwExceptionIf(e,yu.not(yu.anObject(t)),"levels must be an object");Object.keys(t).forEach((n=>{yu.throwExceptionIf(e,yu.not(yu.validIdentifier(n)),`level name "${n}" is not a valid identifier (must start with a letter, only contain A-Z,a-z,0-9,_)`),yu.throwExceptionIf(e,yu.not(yu.anObject(t[n])),`level "${n}" must be an object`),yu.throwExceptionIf(e,yu.not(t[n].value),`level "${n}" must have a 'value' property`),yu.throwExceptionIf(e,yu.not(yu.anInteger(t[n].value)),`level "${n}".value must have an integer value`),yu.throwExceptionIf(e,yu.not(t[n].colour),`level "${n}" must have a 'colour' property`),yu.throwExceptionIf(e,yu.not(Cu.indexOf(t[n].colour)>-1),`level "${n}".colour must be one of ${Cu.join(", ")}`)}))}})),yu.addListener((e=>{Fu.addLevels(e.levels)}));var gu=Fu,Au={exports:{}},vu={};/*! (c) 2020 Andrea Giammarchi */ -const{parse:Su,stringify:wu}=JSON,{keys:Ou}=Object,bu=String,_u="string",Bu={},Pu="object",ku=(e,t)=>t,xu=e=>e instanceof bu?bu(e):e,Nu=(e,t)=>typeof t===_u?new bu(t):t,Iu=(e,t,n,r)=>{const u=[];for(let o=Ou(n),{length:i}=o,s=0;s{const r=bu(t.push(n)-1);return e.set(n,r),r},Ru=(e,t)=>{const n=Su(e,Nu).map(xu),r=n[0],u=t||ku,o=typeof r===Pu&&r?Iu(n,new Set,r,u):r;return u.call({"":o},"",o)};vu.parse=Ru;const Mu=(e,t,n)=>{const r=t&&typeof t===Pu?(e,n)=>""===e||-1Su(Mu(e));vu.fromJSON=e=>Ru(wu(e));const Lu=vu,ju=gu;class $u{constructor(e,t,n,r,u){this.startTime=new Date,this.categoryName=e,this.data=n,this.level=t,this.context=Object.assign({},r),this.pid=process.pid,u&&(this.functionName=u.functionName,this.fileName=u.fileName,this.lineNumber=u.lineNumber,this.columnNumber=u.columnNumber,this.callStack=u.callStack)}serialise(){const e=this.data.map((e=>(e&&e.message&&e.stack&&(e=Object.assign({message:e.message,stack:e.stack},e)),e)));return this.data=e,Lu.stringify(this)}static deserialise(e){let t;try{const n=Lu.parse(e);n.data=n.data.map((e=>{if(e&&e.message&&e.stack){const t=new Error(e);Object.keys(e).forEach((n=>{t[n]=e[n]})),e=t}return e})),t=new $u(n.categoryName,ju.getLevel(n.level.levelStr),n.data,n.context),t.startTime=new Date(n.startTime),t.pid=n.pid,t.cluster=n.cluster}catch(n){t=new $u("log4js",ju.ERROR,["Unable to parse log:",e,"because: ",n])}return t}}var Hu=$u;const Ju=Nr.exports("log4js:clustering"),Gu=Hu,Vu=tu;let Uu=!1,Wu=null;try{Wu=require("cluster")}catch(e){Ju("cluster module not present"),Uu=!0}const zu=[];let Ku=!1,qu="NODE_APP_INSTANCE";const Yu=()=>Ku&&"0"===process.env[qu],Xu=()=>Uu||Wu.isMaster||Yu(),Zu=e=>{zu.forEach((t=>t(e)))},Qu=(e,t)=>{if(Ju("cluster message received from worker ",e,": ",t),e.topic&&e.data&&(t=e,e=void 0),t&&t.topic&&"log4js:message"===t.topic){Ju("received message: ",t.data);const e=Gu.deserialise(t.data);Zu(e)}};Uu||Vu.addListener((e=>{zu.length=0,({pm2:Ku,disableClustering:Uu,pm2InstanceVar:qu="NODE_APP_INSTANCE"}=e),Ju(`clustering disabled ? ${Uu}`),Ju(`cluster.isMaster ? ${Wu&&Wu.isMaster}`),Ju(`pm2 enabled ? ${Ku}`),Ju(`pm2InstanceVar = ${qu}`),Ju(`process.env[${qu}] = ${process.env[qu]}`),Ku&&process.removeListener("message",Qu),Wu&&Wu.removeListener&&Wu.removeListener("message",Qu),Uu||e.disableClustering?Ju("Not listening for cluster messages, because clustering disabled."):Yu()?(Ju("listening for PM2 broadcast messages"),process.on("message",Qu)):Wu.isMaster?(Ju("listening for cluster messages"),Wu.on("message",Qu)):Ju("not listening for messages, because we are not a master process")}));var eo={onlyOnMaster:(e,t)=>Xu()?e():t,isMaster:Xu,send:e=>{Xu()?Zu(e):(Ku||(e.cluster={workerId:Wu.worker.id,worker:process.pid}),process.send({topic:"log4js:message",data:e.serialise()}))},onMessage:e=>{zu.push(e)}},to={};function no(e){if("number"==typeof e&&Number.isInteger(e))return e;const t={K:1024,M:1048576,G:1073741824},n=Object.keys(t),r=e.substr(e.length-1).toLocaleUpperCase(),u=e.substring(0,e.length-1).trim();if(n.indexOf(r)<0||!Number.isInteger(Number(u)))throw Error(`maxLogSize: "${e}" is invalid`);return u*t[r]}function ro(e){return function(e,t){const n=Object.assign({},t);return Object.keys(e).forEach((r=>{n[r]&&(n[r]=e[r](t[r]))})),n}({maxLogSize:no},e)}const uo={file:ro,fileSync:ro};to.modifyConfig=e=>uo[e.type]?uo[e.type](e):e;var oo={};const io=console.log.bind(console);oo.configure=function(e,t){let n=t.colouredLayout;return e.layout&&(n=t.layout(e.layout.type,e.layout)),function(e,t){return n=>{io(e(n,t))}}(n,e.timezoneOffset)};var so={};so.configure=function(e,t){let n=t.colouredLayout;return e.layout&&(n=t.layout(e.layout.type,e.layout)),function(e,t){return n=>{process.stdout.write(`${e(n,t)}\n`)}}(n,e.timezoneOffset)};var co={};co.configure=function(e,t){let n=t.colouredLayout;return e.layout&&(n=t.layout(e.layout.type,e.layout)),function(e,t){return n=>{process.stderr.write(`${e(n,t)}\n`)}}(n,e.timezoneOffset)};var ao={};ao.configure=function(e,t,n,r){const u=n(e.appender);return function(e,t,n,r){const u=r.getLevel(e),o=r.getLevel(t,r.FATAL);return e=>{const t=e.level;t.isGreaterThanOrEqualTo(u)&&t.isLessThanOrEqualTo(o)&&n(e)}}(e.level,e.maxLevel,u,r)};var lo={};const fo=Nr.exports("log4js:categoryFilter");lo.configure=function(e,t,n){const r=n(e.appender);return function(e,t){return"string"==typeof e&&(e=[e]),n=>{fo(`Checking ${n.categoryName} against ${e}`),-1===e.indexOf(n.categoryName)&&(fo("Not excluded, sending to appender"),t(n))}}(e.exclude,r)};var Do={};const po=Nr.exports("log4js:noLogFilter");Do.configure=function(e,t,n){const r=n(e.appender);return function(e,t){return n=>{po(`Checking data: ${n.data} against filters: ${e}`),"string"==typeof e&&(e=[e]),e=e.filter((e=>null!=e&&""!==e));const r=new RegExp(e.join("|"),"i");(0===e.length||n.data.findIndex((e=>r.test(e)))<0)&&(po("Not excluded, sending to appender"),t(n))}}(e.exclude,r)};var Eo={},mo={exports:{}},ho={},yo={fromCallback:function(e){return Object.defineProperty((function(){if("function"!=typeof arguments[arguments.length-1])return new Promise(((t,n)=>{arguments[arguments.length]=(e,r)=>{if(e)return n(e);t(r)},arguments.length++,e.apply(this,arguments)}));e.apply(this,arguments)}),"name",{value:e.name})},fromPromise:function(e){return Object.defineProperty((function(){const t=arguments[arguments.length-1];if("function"!=typeof t)return e.apply(this,arguments);e.apply(this,arguments).then((e=>t(null,e)),t)}),"name",{value:e.name})}};!function(e){const t=yo.fromCallback,n=we,r=["access","appendFile","chmod","chown","close","copyFile","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","lchown","lchmod","link","lstat","mkdir","mkdtemp","open","readFile","readdir","readlink","realpath","rename","rmdir","stat","symlink","truncate","unlink","utimes","writeFile"].filter((e=>"function"==typeof n[e]));Object.keys(n).forEach((t=>{"promises"!==t&&(e[t]=n[t])})),r.forEach((r=>{e[r]=t(n[r])})),e.exists=function(e,t){return"function"==typeof t?n.exists(e,t):new Promise((t=>n.exists(e,t)))},e.read=function(e,t,r,u,o,i){return"function"==typeof i?n.read(e,t,r,u,o,i):new Promise(((i,s)=>{n.read(e,t,r,u,o,((e,t,n)=>{if(e)return s(e);i({bytesRead:t,buffer:n})}))}))},e.write=function(e,t,...r){return"function"==typeof r[r.length-1]?n.write(e,t,...r):new Promise(((u,o)=>{n.write(e,t,...r,((e,t,n)=>{if(e)return o(e);u({bytesWritten:t,buffer:n})}))}))},"function"==typeof n.realpath.native&&(e.realpath.native=t(n.realpath.native))}(ho);const Co=p.default;function Fo(e){return(e=Co.normalize(Co.resolve(e)).split(Co.sep)).length>0?e[0]:null}const go=/[<>:"|?*]/;var Ao=function(e){const t=Fo(e);return e=e.replace(t,""),go.test(e)};const vo=we,So=p.default,wo=Ao,Oo=parseInt("0777",8);var bo=function e(t,n,r,u){if("function"==typeof n?(r=n,n={}):n&&"object"==typeof n||(n={mode:n}),"win32"===process.platform&&wo(t)){const e=new Error(t+" contains invalid WIN32 path characters.");return e.code="EINVAL",r(e)}let o=n.mode;const i=n.fs||vo;void 0===o&&(o=Oo&~process.umask()),u||(u=null),r=r||function(){},t=So.resolve(t),i.mkdir(t,o,(o=>{if(!o)return r(null,u=u||t);if("ENOENT"===o.code){if(So.dirname(t)===t)return r(o);e(So.dirname(t),n,((u,o)=>{u?r(u,o):e(t,n,r,o)}))}else i.stat(t,((e,t)=>{e||!t.isDirectory()?r(o,u):r(null,u)}))}))};const _o=we,Bo=p.default,Po=Ao,ko=parseInt("0777",8);var xo=function e(t,n,r){n&&"object"==typeof n||(n={mode:n});let u=n.mode;const o=n.fs||_o;if("win32"===process.platform&&Po(t)){const e=new Error(t+" contains invalid WIN32 path characters.");throw e.code="EINVAL",e}void 0===u&&(u=ko&~process.umask()),r||(r=null),t=Bo.resolve(t);try{o.mkdirSync(t,u),r=r||t}catch(u){if("ENOENT"===u.code){if(Bo.dirname(t)===t)throw u;r=e(Bo.dirname(t),n,r),e(t,n,r)}else{let e;try{e=o.statSync(t)}catch(e){throw u}if(!e.isDirectory())throw u}}return r};const No=(0,yo.fromCallback)(bo);var Io={mkdirs:No,mkdirsSync:xo,mkdirp:No,mkdirpSync:xo,ensureDir:No,ensureDirSync:xo};const To=we;E.default,p.default;var Ro=function(e,t,n,r){To.open(e,"r+",((e,u)=>{if(e)return r(e);To.futimes(u,t,n,(e=>{To.close(u,(t=>{r&&r(e||t)}))}))}))},Mo=function(e,t,n){const r=To.openSync(e,"r+");return To.futimesSync(r,t,n),To.closeSync(r)};const Lo=we,jo=p.default,$o=10,Ho=5,Jo=0,Go=process.versions.node.split("."),Vo=Number.parseInt(Go[0],10),Uo=Number.parseInt(Go[1],10),Wo=Number.parseInt(Go[2],10);function zo(){if(Vo>$o)return!0;if(Vo===$o){if(Uo>Ho)return!0;if(Uo===Ho&&Wo>=Jo)return!0}return!1}function Ko(e,t){const n=jo.resolve(e).split(jo.sep).filter((e=>e)),r=jo.resolve(t).split(jo.sep).filter((e=>e));return n.reduce(((e,t,n)=>e&&r[n]===t),!0)}function qo(e,t,n){return`Cannot ${n} '${e}' to a subdirectory of itself, '${t}'.`}var Yo,Xo,Zo={checkPaths:function(e,t,n,r){!function(e,t,n){zo()?Lo.stat(e,{bigint:!0},((e,r)=>{if(e)return n(e);Lo.stat(t,{bigint:!0},((e,t)=>e?"ENOENT"===e.code?n(null,{srcStat:r,destStat:null}):n(e):n(null,{srcStat:r,destStat:t})))})):Lo.stat(e,((e,r)=>{if(e)return n(e);Lo.stat(t,((e,t)=>e?"ENOENT"===e.code?n(null,{srcStat:r,destStat:null}):n(e):n(null,{srcStat:r,destStat:t})))}))}(e,t,((u,o)=>{if(u)return r(u);const{srcStat:i,destStat:s}=o;return s&&s.ino&&s.dev&&s.ino===i.ino&&s.dev===i.dev?r(new Error("Source and destination must not be the same.")):i.isDirectory()&&Ko(e,t)?r(new Error(qo(e,t,n))):r(null,{srcStat:i,destStat:s})}))},checkPathsSync:function(e,t,n){const{srcStat:r,destStat:u}=function(e,t){let n,r;n=zo()?Lo.statSync(e,{bigint:!0}):Lo.statSync(e);try{r=zo()?Lo.statSync(t,{bigint:!0}):Lo.statSync(t)}catch(e){if("ENOENT"===e.code)return{srcStat:n,destStat:null};throw e}return{srcStat:n,destStat:r}}(e,t);if(u&&u.ino&&u.dev&&u.ino===r.ino&&u.dev===r.dev)throw new Error("Source and destination must not be the same.");if(r.isDirectory()&&Ko(e,t))throw new Error(qo(e,t,n));return{srcStat:r,destStat:u}},checkParentPaths:function e(t,n,r,u,o){const i=jo.resolve(jo.dirname(t)),s=jo.resolve(jo.dirname(r));if(s===i||s===jo.parse(s).root)return o();zo()?Lo.stat(s,{bigint:!0},((i,c)=>i?"ENOENT"===i.code?o():o(i):c.ino&&c.dev&&c.ino===n.ino&&c.dev===n.dev?o(new Error(qo(t,r,u))):e(t,n,s,u,o))):Lo.stat(s,((i,c)=>i?"ENOENT"===i.code?o():o(i):c.ino&&c.dev&&c.ino===n.ino&&c.dev===n.dev?o(new Error(qo(t,r,u))):e(t,n,s,u,o)))},checkParentPathsSync:function e(t,n,r,u){const o=jo.resolve(jo.dirname(t)),i=jo.resolve(jo.dirname(r));if(i===o||i===jo.parse(i).root)return;let s;try{s=zo()?Lo.statSync(i,{bigint:!0}):Lo.statSync(i)}catch(e){if("ENOENT"===e.code)return;throw e}if(s.ino&&s.dev&&s.ino===n.ino&&s.dev===n.dev)throw new Error(qo(t,r,u));return e(t,n,i,u)},isSrcSubdir:Ko};const Qo=we,ei=p.default,ti=Io.mkdirsSync,ni=Mo,ri=Zo;function ui(e,t,n,r){if(!r.filter||r.filter(t,n))return function(e,t,n,r){const u=r.dereference?Qo.statSync:Qo.lstatSync,o=u(t);if(o.isDirectory())return function(e,t,n,r,u){if(!t)return function(e,t,n,r){return Qo.mkdirSync(n),ii(t,n,r),Qo.chmodSync(n,e.mode)}(e,n,r,u);if(t&&!t.isDirectory())throw new Error(`Cannot overwrite non-directory '${r}' with directory '${n}'.`);return ii(n,r,u)}(o,e,t,n,r);if(o.isFile()||o.isCharacterDevice()||o.isBlockDevice())return function(e,t,n,r,u){return t?function(e,t,n,r){if(r.overwrite)return Qo.unlinkSync(n),oi(e,t,n,r);if(r.errorOnExist)throw new Error(`'${n}' already exists`)}(e,n,r,u):oi(e,n,r,u)}(o,e,t,n,r);if(o.isSymbolicLink())return function(e,t,n,r){let u=Qo.readlinkSync(t);r.dereference&&(u=ei.resolve(process.cwd(),u));if(e){let e;try{e=Qo.readlinkSync(n)}catch(e){if("EINVAL"===e.code||"UNKNOWN"===e.code)return Qo.symlinkSync(u,n);throw e}if(r.dereference&&(e=ei.resolve(process.cwd(),e)),ri.isSrcSubdir(u,e))throw new Error(`Cannot copy '${u}' to a subdirectory of itself, '${e}'.`);if(Qo.statSync(n).isDirectory()&&ri.isSrcSubdir(e,u))throw new Error(`Cannot overwrite '${e}' with '${u}'.`);return function(e,t){return Qo.unlinkSync(t),Qo.symlinkSync(e,t)}(u,n)}return Qo.symlinkSync(u,n)}(e,t,n,r)}(e,t,n,r)}function oi(e,t,n,r){return"function"==typeof Qo.copyFileSync?(Qo.copyFileSync(t,n),Qo.chmodSync(n,e.mode),r.preserveTimestamps?ni(n,e.atime,e.mtime):void 0):function(e,t,n,r){const u=65536,o=(Xo?Yo:(Xo=1,Yo=function(e){if("function"==typeof Buffer.allocUnsafe)try{return Buffer.allocUnsafe(e)}catch(t){return new Buffer(e)}return new Buffer(e)}))(u),i=Qo.openSync(t,"r"),s=Qo.openSync(n,"w",e.mode);let c=0;for(;cfunction(e,t,n,r){const u=ei.join(t,e),o=ei.join(n,e),{destStat:i}=ri.checkPathsSync(u,o,"copy");return ui(i,u,o,r)}(r,e,t,n)))}var si=function(e,t,n){"function"==typeof n&&(n={filter:n}),(n=n||{}).clobber=!("clobber"in n)||!!n.clobber,n.overwrite="overwrite"in n?!!n.overwrite:n.clobber,n.preserveTimestamps&&"ia32"===process.arch&&console.warn("fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;\n\n see https://github.com/jprichardson/node-fs-extra/issues/269");const{srcStat:r,destStat:u}=ri.checkPathsSync(e,t,"copy");return ri.checkParentPathsSync(e,r,t,"copy"),function(e,t,n,r){if(r.filter&&!r.filter(t,n))return;const u=ei.dirname(n);Qo.existsSync(u)||ti(u);return ui(e,t,n,r)}(u,e,t,n)},ci={copySync:si};const ai=yo.fromPromise,li=ho;var fi={pathExists:ai((function(e){return li.access(e).then((()=>!0)).catch((()=>!1))})),pathExistsSync:li.existsSync};const di=we,Di=p.default,pi=Io.mkdirs,Ei=fi.pathExists,mi=Ro,hi=Zo;function yi(e,t,n,r,u){const o=Di.dirname(n);Ei(o,((i,s)=>i?u(i):s?Fi(e,t,n,r,u):void pi(o,(o=>o?u(o):Fi(e,t,n,r,u)))))}function Ci(e,t,n,r,u,o){Promise.resolve(u.filter(n,r)).then((i=>i?e(t,n,r,u,o):o()),(e=>o(e)))}function Fi(e,t,n,r,u){return r.filter?Ci(gi,e,t,n,r,u):gi(e,t,n,r,u)}function gi(e,t,n,r,u){(r.dereference?di.stat:di.lstat)(t,((o,i)=>o?u(o):i.isDirectory()?function(e,t,n,r,u,o){if(!t)return function(e,t,n,r,u){di.mkdir(n,(o=>{if(o)return u(o);Si(t,n,r,(t=>t?u(t):di.chmod(n,e.mode,u)))}))}(e,n,r,u,o);if(t&&!t.isDirectory())return o(new Error(`Cannot overwrite non-directory '${r}' with directory '${n}'.`));return Si(n,r,u,o)}(i,e,t,n,r,u):i.isFile()||i.isCharacterDevice()||i.isBlockDevice()?function(e,t,n,r,u,o){return t?function(e,t,n,r,u){if(!r.overwrite)return r.errorOnExist?u(new Error(`'${n}' already exists`)):u();di.unlink(n,(o=>o?u(o):Ai(e,t,n,r,u)))}(e,n,r,u,o):Ai(e,n,r,u,o)}(i,e,t,n,r,u):i.isSymbolicLink()?function(e,t,n,r,u){di.readlink(t,((t,o)=>t?u(t):(r.dereference&&(o=Di.resolve(process.cwd(),o)),e?void di.readlink(n,((t,i)=>t?"EINVAL"===t.code||"UNKNOWN"===t.code?di.symlink(o,n,u):u(t):(r.dereference&&(i=Di.resolve(process.cwd(),i)),hi.isSrcSubdir(o,i)?u(new Error(`Cannot copy '${o}' to a subdirectory of itself, '${i}'.`)):e.isDirectory()&&hi.isSrcSubdir(i,o)?u(new Error(`Cannot overwrite '${i}' with '${o}'.`)):function(e,t,n){di.unlink(t,(r=>r?n(r):di.symlink(e,t,n)))}(o,n,u)))):di.symlink(o,n,u))))}(e,t,n,r,u):void 0))}function Ai(e,t,n,r,u){return"function"==typeof di.copyFile?di.copyFile(t,n,(t=>t?u(t):vi(e,n,r,u))):function(e,t,n,r,u){const o=di.createReadStream(t);o.on("error",(e=>u(e))).once("open",(()=>{const t=di.createWriteStream(n,{mode:e.mode});t.on("error",(e=>u(e))).on("open",(()=>o.pipe(t))).once("close",(()=>vi(e,n,r,u)))}))}(e,t,n,r,u)}function vi(e,t,n,r){di.chmod(t,e.mode,(u=>u?r(u):n.preserveTimestamps?mi(t,e.atime,e.mtime,r):r()))}function Si(e,t,n,r){di.readdir(e,((u,o)=>u?r(u):wi(o,e,t,n,r)))}function wi(e,t,n,r,u){const o=e.pop();return o?function(e,t,n,r,u,o){const i=Di.join(n,t),s=Di.join(r,t);hi.checkPaths(i,s,"copy",((t,c)=>{if(t)return o(t);const{destStat:a}=c;Fi(a,i,s,u,(t=>t?o(t):wi(e,n,r,u,o)))}))}(e,o,t,n,r,u):u()}var Oi=function(e,t,n,r){"function"!=typeof n||r?"function"==typeof n&&(n={filter:n}):(r=n,n={}),r=r||function(){},(n=n||{}).clobber=!("clobber"in n)||!!n.clobber,n.overwrite="overwrite"in n?!!n.overwrite:n.clobber,n.preserveTimestamps&&"ia32"===process.arch&&console.warn("fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;\n\n see https://github.com/jprichardson/node-fs-extra/issues/269"),hi.checkPaths(e,t,"copy",((u,o)=>{if(u)return r(u);const{srcStat:i,destStat:s}=o;hi.checkParentPaths(e,i,t,"copy",(u=>u?r(u):n.filter?Ci(yi,s,e,t,n,r):yi(s,e,t,n,r)))}))};var bi={copy:(0,yo.fromCallback)(Oi)};const _i=we,Bi=p.default,Pi=g.default,ki="win32"===process.platform;function xi(e){["unlink","chmod","stat","lstat","rmdir","readdir"].forEach((t=>{e[t]=e[t]||_i[t],e[t+="Sync"]=e[t]||_i[t]})),e.maxBusyTries=e.maxBusyTries||3}function Ni(e,t,n){let r=0;"function"==typeof t&&(n=t,t={}),Pi(e,"rimraf: missing path"),Pi.strictEqual(typeof e,"string","rimraf: path should be a string"),Pi.strictEqual(typeof n,"function","rimraf: callback function required"),Pi(t,"rimraf: invalid options argument provided"),Pi.strictEqual(typeof t,"object","rimraf: options should be object"),xi(t),Ii(e,t,(function u(o){if(o){if(("EBUSY"===o.code||"ENOTEMPTY"===o.code||"EPERM"===o.code)&&rIi(e,t,u)),100*r)}"ENOENT"===o.code&&(o=null)}n(o)}))}function Ii(e,t,n){Pi(e),Pi(t),Pi("function"==typeof n),t.lstat(e,((r,u)=>r&&"ENOENT"===r.code?n(null):r&&"EPERM"===r.code&&ki?Ti(e,t,r,n):u&&u.isDirectory()?Mi(e,t,r,n):void t.unlink(e,(r=>{if(r){if("ENOENT"===r.code)return n(null);if("EPERM"===r.code)return ki?Ti(e,t,r,n):Mi(e,t,r,n);if("EISDIR"===r.code)return Mi(e,t,r,n)}return n(r)}))))}function Ti(e,t,n,r){Pi(e),Pi(t),Pi("function"==typeof r),n&&Pi(n instanceof Error),t.chmod(e,438,(u=>{u?r("ENOENT"===u.code?null:n):t.stat(e,((u,o)=>{u?r("ENOENT"===u.code?null:n):o.isDirectory()?Mi(e,t,n,r):t.unlink(e,r)}))}))}function Ri(e,t,n){let r;Pi(e),Pi(t),n&&Pi(n instanceof Error);try{t.chmodSync(e,438)}catch(e){if("ENOENT"===e.code)return;throw n}try{r=t.statSync(e)}catch(e){if("ENOENT"===e.code)return;throw n}r.isDirectory()?ji(e,t,n):t.unlinkSync(e)}function Mi(e,t,n,r){Pi(e),Pi(t),n&&Pi(n instanceof Error),Pi("function"==typeof r),t.rmdir(e,(u=>{!u||"ENOTEMPTY"!==u.code&&"EEXIST"!==u.code&&"EPERM"!==u.code?u&&"ENOTDIR"===u.code?r(n):r(u):function(e,t,n){Pi(e),Pi(t),Pi("function"==typeof n),t.readdir(e,((r,u)=>{if(r)return n(r);let o,i=u.length;if(0===i)return t.rmdir(e,n);u.forEach((r=>{Ni(Bi.join(e,r),t,(r=>{if(!o)return r?n(o=r):void(0==--i&&t.rmdir(e,n))}))}))}))}(e,t,r)}))}function Li(e,t){let n;xi(t=t||{}),Pi(e,"rimraf: missing path"),Pi.strictEqual(typeof e,"string","rimraf: path should be a string"),Pi(t,"rimraf: missing options"),Pi.strictEqual(typeof t,"object","rimraf: options should be object");try{n=t.lstatSync(e)}catch(n){if("ENOENT"===n.code)return;"EPERM"===n.code&&ki&&Ri(e,t,n)}try{n&&n.isDirectory()?ji(e,t,null):t.unlinkSync(e)}catch(n){if("ENOENT"===n.code)return;if("EPERM"===n.code)return ki?Ri(e,t,n):ji(e,t,n);if("EISDIR"!==n.code)throw n;ji(e,t,n)}}function ji(e,t,n){Pi(e),Pi(t),n&&Pi(n instanceof Error);try{t.rmdirSync(e)}catch(r){if("ENOTDIR"===r.code)throw n;if("ENOTEMPTY"===r.code||"EEXIST"===r.code||"EPERM"===r.code)!function(e,t){if(Pi(e),Pi(t),t.readdirSync(e).forEach((n=>Li(Bi.join(e,n),t))),!ki){return t.rmdirSync(e,t)}{const n=Date.now();do{try{return t.rmdirSync(e,t)}catch(e){}}while(Date.now()-n<500)}}(e,t);else if("ENOENT"!==r.code)throw r}}var $i=Ni;Ni.sync=Li;const Hi=$i;var Ji={remove:(0,yo.fromCallback)(Hi),removeSync:Hi.sync};const Gi=yo.fromCallback,Vi=we,Ui=p.default,Wi=Io,zi=Ji,Ki=Gi((function(e,t){t=t||function(){},Vi.readdir(e,((n,r)=>{if(n)return Wi.mkdirs(e,t);r=r.map((t=>Ui.join(e,t))),function e(){const n=r.pop();if(!n)return t();zi.remove(n,(n=>{if(n)return t(n);e()}))}()}))}));function qi(e){let t;try{t=Vi.readdirSync(e)}catch(t){return Wi.mkdirsSync(e)}t.forEach((t=>{t=Ui.join(e,t),zi.removeSync(t)}))}var Yi={emptyDirSync:qi,emptydirSync:qi,emptyDir:Ki,emptydir:Ki};const Xi=yo.fromCallback,Zi=p.default,Qi=we,es=Io,ts=fi.pathExists;var ns={createFile:Xi((function(e,t){function n(){Qi.writeFile(e,"",(e=>{if(e)return t(e);t()}))}Qi.stat(e,((r,u)=>{if(!r&&u.isFile())return t();const o=Zi.dirname(e);ts(o,((e,r)=>e?t(e):r?n():void es.mkdirs(o,(e=>{if(e)return t(e);n()}))))}))})),createFileSync:function(e){let t;try{t=Qi.statSync(e)}catch(e){}if(t&&t.isFile())return;const n=Zi.dirname(e);Qi.existsSync(n)||es.mkdirsSync(n),Qi.writeFileSync(e,"")}};const rs=yo.fromCallback,us=p.default,os=we,is=Io,ss=fi.pathExists;var cs={createLink:rs((function(e,t,n){function r(e,t){os.link(e,t,(e=>{if(e)return n(e);n(null)}))}ss(t,((u,o)=>u?n(u):o?n(null):void os.lstat(e,(u=>{if(u)return u.message=u.message.replace("lstat","ensureLink"),n(u);const o=us.dirname(t);ss(o,((u,i)=>u?n(u):i?r(e,t):void is.mkdirs(o,(u=>{if(u)return n(u);r(e,t)}))))}))))})),createLinkSync:function(e,t){if(os.existsSync(t))return;try{os.lstatSync(e)}catch(e){throw e.message=e.message.replace("lstat","ensureLink"),e}const n=us.dirname(t);return os.existsSync(n)||is.mkdirsSync(n),os.linkSync(e,t)}};const as=p.default,ls=we,fs=fi.pathExists;var ds={symlinkPaths:function(e,t,n){if(as.isAbsolute(e))return ls.lstat(e,(t=>t?(t.message=t.message.replace("lstat","ensureSymlink"),n(t)):n(null,{toCwd:e,toDst:e})));{const r=as.dirname(t),u=as.join(r,e);return fs(u,((t,o)=>t?n(t):o?n(null,{toCwd:u,toDst:e}):ls.lstat(e,(t=>t?(t.message=t.message.replace("lstat","ensureSymlink"),n(t)):n(null,{toCwd:e,toDst:as.relative(r,e)})))))}},symlinkPathsSync:function(e,t){let n;if(as.isAbsolute(e)){if(n=ls.existsSync(e),!n)throw new Error("absolute srcpath does not exist");return{toCwd:e,toDst:e}}{const r=as.dirname(t),u=as.join(r,e);if(n=ls.existsSync(u),n)return{toCwd:u,toDst:e};if(n=ls.existsSync(e),!n)throw new Error("relative srcpath does not exist");return{toCwd:e,toDst:as.relative(r,e)}}}};const Ds=we;var ps={symlinkType:function(e,t,n){if(n="function"==typeof t?t:n,t="function"!=typeof t&&t)return n(null,t);Ds.lstat(e,((e,r)=>{if(e)return n(null,"file");t=r&&r.isDirectory()?"dir":"file",n(null,t)}))},symlinkTypeSync:function(e,t){let n;if(t)return t;try{n=Ds.lstatSync(e)}catch(e){return"file"}return n&&n.isDirectory()?"dir":"file"}};const Es=yo.fromCallback,ms=p.default,hs=we,ys=Io.mkdirs,Cs=Io.mkdirsSync,Fs=ds.symlinkPaths,gs=ds.symlinkPathsSync,As=ps.symlinkType,vs=ps.symlinkTypeSync,Ss=fi.pathExists;var ws={createSymlink:Es((function(e,t,n,r){r="function"==typeof n?n:r,n="function"!=typeof n&&n,Ss(t,((u,o)=>u?r(u):o?r(null):void Fs(e,t,((u,o)=>{if(u)return r(u);e=o.toDst,As(o.toCwd,n,((n,u)=>{if(n)return r(n);const o=ms.dirname(t);Ss(o,((n,i)=>n?r(n):i?hs.symlink(e,t,u,r):void ys(o,(n=>{if(n)return r(n);hs.symlink(e,t,u,r)}))))}))}))))})),createSymlinkSync:function(e,t,n){if(hs.existsSync(t))return;const r=gs(e,t);e=r.toDst,n=vs(r.toCwd,n);const u=ms.dirname(t);return hs.existsSync(u)||Cs(u),hs.symlinkSync(e,t,n)}};var Os,bs={createFile:ns.createFile,createFileSync:ns.createFileSync,ensureFile:ns.createFile,ensureFileSync:ns.createFileSync,createLink:cs.createLink,createLinkSync:cs.createLinkSync,ensureLink:cs.createLink,ensureLinkSync:cs.createLinkSync,createSymlink:ws.createSymlink,createSymlinkSync:ws.createSymlinkSync,ensureSymlink:ws.createSymlink,ensureSymlinkSync:ws.createSymlinkSync};try{Os=we}catch(e){Os=D.default}function _s(e,t){var n,r="\n";return"object"==typeof t&&null!==t&&(t.spaces&&(n=t.spaces),t.EOL&&(r=t.EOL)),JSON.stringify(e,t?t.replacer:null,n).replace(/\n/g,r)+r}function Bs(e){return Buffer.isBuffer(e)&&(e=e.toString("utf8")),e=e.replace(/^\uFEFF/,"")}var Ps={readFile:function(e,t,n){null==n&&(n=t,t={}),"string"==typeof t&&(t={encoding:t});var r=(t=t||{}).fs||Os,u=!0;"throws"in t&&(u=t.throws),r.readFile(e,t,(function(r,o){if(r)return n(r);var i;o=Bs(o);try{i=JSON.parse(o,t?t.reviver:null)}catch(t){return u?(t.message=e+": "+t.message,n(t)):n(null,null)}n(null,i)}))},readFileSync:function(e,t){"string"==typeof(t=t||{})&&(t={encoding:t});var n=t.fs||Os,r=!0;"throws"in t&&(r=t.throws);try{var u=n.readFileSync(e,t);return u=Bs(u),JSON.parse(u,t.reviver)}catch(t){if(r)throw t.message=e+": "+t.message,t;return null}},writeFile:function(e,t,n,r){null==r&&(r=n,n={});var u=(n=n||{}).fs||Os,o="";try{o=_s(t,n)}catch(e){return void(r&&r(e,null))}u.writeFile(e,o,n,r)},writeFileSync:function(e,t,n){var r=(n=n||{}).fs||Os,u=_s(t,n);return r.writeFileSync(e,u,n)}},ks=Ps;const xs=yo.fromCallback,Ns=ks;var Is={readJson:xs(Ns.readFile),readJsonSync:Ns.readFileSync,writeJson:xs(Ns.writeFile),writeJsonSync:Ns.writeFileSync};const Ts=p.default,Rs=Io,Ms=fi.pathExists,Ls=Is;var js=function(e,t,n,r){"function"==typeof n&&(r=n,n={});const u=Ts.dirname(e);Ms(u,((o,i)=>o?r(o):i?Ls.writeJson(e,t,n,r):void Rs.mkdirs(u,(u=>{if(u)return r(u);Ls.writeJson(e,t,n,r)}))))};const $s=we,Hs=p.default,Js=Io,Gs=Is;var Vs=function(e,t,n){const r=Hs.dirname(e);$s.existsSync(r)||Js.mkdirsSync(r),Gs.writeJsonSync(e,t,n)};const Us=yo.fromCallback,Ws=Is;Ws.outputJson=Us(js),Ws.outputJsonSync=Vs,Ws.outputJSON=Ws.outputJson,Ws.outputJSONSync=Ws.outputJsonSync,Ws.writeJSON=Ws.writeJson,Ws.writeJSONSync=Ws.writeJsonSync,Ws.readJSON=Ws.readJson,Ws.readJSONSync=Ws.readJsonSync;var zs=Ws;const Ks=we,qs=p.default,Ys=ci.copySync,Xs=Ji.removeSync,Zs=Io.mkdirpSync,Qs=Zo;function ec(e,t,n){try{Ks.renameSync(e,t)}catch(r){if("EXDEV"!==r.code)throw r;return function(e,t,n){const r={overwrite:n,errorOnExist:!0};return Ys(e,t,r),Xs(e)}(e,t,n)}}var tc=function(e,t,n){const r=(n=n||{}).overwrite||n.clobber||!1,{srcStat:u}=Qs.checkPathsSync(e,t,"move");return Qs.checkParentPathsSync(e,u,t,"move"),Zs(qs.dirname(t)),function(e,t,n){if(n)return Xs(t),ec(e,t,n);if(Ks.existsSync(t))throw new Error("dest already exists.");return ec(e,t,n)}(e,t,r)},nc={moveSync:tc};const rc=we,uc=p.default,oc=bi.copy,ic=Ji.remove,sc=Io.mkdirp,cc=fi.pathExists,ac=Zo;function lc(e,t,n,r){rc.rename(e,t,(u=>u?"EXDEV"!==u.code?r(u):function(e,t,n,r){const u={overwrite:n,errorOnExist:!0};oc(e,t,u,(t=>t?r(t):ic(e,r)))}(e,t,n,r):r()))}var fc=function(e,t,n,r){"function"==typeof n&&(r=n,n={});const u=n.overwrite||n.clobber||!1;ac.checkPaths(e,t,"move",((n,o)=>{if(n)return r(n);const{srcStat:i}=o;ac.checkParentPaths(e,i,t,"move",(n=>{if(n)return r(n);sc(uc.dirname(t),(n=>n?r(n):function(e,t,n,r){if(n)return ic(t,(u=>u?r(u):lc(e,t,n,r)));cc(t,((u,o)=>u?r(u):o?r(new Error("dest already exists.")):lc(e,t,n,r)))}(e,t,u,r)))}))}))};var dc={move:(0,yo.fromCallback)(fc)};const Dc=yo.fromCallback,pc=we,Ec=p.default,mc=Io,hc=fi.pathExists;var yc={outputFile:Dc((function(e,t,n,r){"function"==typeof n&&(r=n,n="utf8");const u=Ec.dirname(e);hc(u,((o,i)=>o?r(o):i?pc.writeFile(e,t,n,r):void mc.mkdirs(u,(u=>{if(u)return r(u);pc.writeFile(e,t,n,r)}))))})),outputFileSync:function(e,...t){const n=Ec.dirname(e);if(pc.existsSync(n))return pc.writeFileSync(e,...t);mc.mkdirsSync(n),pc.writeFileSync(e,...t)}};!function(e){e.exports=Object.assign({},ho,ci,bi,Yi,bs,zs,Io,nc,dc,yc,fi,Ji);const t=D.default;Object.getOwnPropertyDescriptor(t,"promises")&&Object.defineProperty(e.exports,"promises",{get:()=>t.promises})}(mo);const Cc=Nr.exports("streamroller:fileNameFormatter"),Fc=p.default;const gc=Nr.exports("streamroller:fileNameParser"),Ac=nu.exports;const vc=Nr.exports("streamroller:moveAndMaybeCompressFile"),Sc=mo.exports,wc=v.default;var Oc=async(e,t,n)=>{if(n=function(e){const t={mode:parseInt("0600",8),compress:!1},n=Object.assign({},t,e);return vc(`_parseOption: moveAndMaybeCompressFile called with option=${JSON.stringify(n)}`),n}(n),e!==t){if(await Sc.pathExists(e))if(vc(`moveAndMaybeCompressFile: moving file from ${e} to ${t} ${n.compress?"with":"without"} compress`),n.compress)await new Promise(((r,u)=>{let o=!1;const i=Sc.createWriteStream(t,{mode:n.mode,flags:"wx"}).on("open",(()=>{o=!0;const t=Sc.createReadStream(e).on("open",(()=>{t.pipe(wc.createGzip()).pipe(i)})).on("error",(t=>{vc(`moveAndMaybeCompressFile: error reading ${e}`,t),i.destroy(t)}))})).on("finish",(()=>{vc(`moveAndMaybeCompressFile: finished compressing ${t}, deleting ${e}`),Sc.unlink(e).then(r).catch((t=>{vc(`moveAndMaybeCompressFile: error deleting ${e}, truncating instead`,t),Sc.truncate(e).then(r).catch((t=>{vc(`moveAndMaybeCompressFile: error truncating ${e}`,t),u(t)}))}))})).on("error",(e=>{o?(vc(`moveAndMaybeCompressFile: error writing ${t}, deleting`,e),Sc.unlink(t).then((()=>{u(e)})).catch((e=>{vc(`moveAndMaybeCompressFile: error deleting ${t}`,e),u(e)}))):(vc(`moveAndMaybeCompressFile: error creating ${t}`,e),u(e))}))})).catch((()=>{}));else{vc(`moveAndMaybeCompressFile: renaming ${e} to ${t}`);try{await Sc.move(e,t,{overwrite:!0})}catch(n){if(vc(`moveAndMaybeCompressFile: error renaming ${e} to ${t}`,n),"ENOENT"!==n.code){vc("moveAndMaybeCompressFile: trying copy+truncate instead");try{await Sc.copy(e,t,{overwrite:!0}),await Sc.truncate(e)}catch(e){vc("moveAndMaybeCompressFile: error copy+truncate",e)}}}}}else vc("moveAndMaybeCompressFile: source and target are the same, not doing anything")};const bc=Nr.exports("streamroller:RollingFileWriteStream"),_c=mo.exports,Bc=p.default,Pc=E.default,kc=()=>new Date,xc=nu.exports,{Writable:Nc}=C.default,Ic=({file:e,keepFileExt:t,needsIndex:n,alwaysIncludeDate:r,compress:u,fileNameSep:o})=>{let i=o||".";const s=Fc.join(e.dir,e.name),c=t=>t+e.ext,a=(e,t,r)=>!n&&r||!t?e:e+i+t,l=(e,t,n)=>(t>0||r)&&n?e+i+n:e,f=(e,t)=>t&&u?e+".gz":e,d=t?[l,a,c,f]:[c,l,a,f];return({date:e,index:t})=>(Cc(`_formatFileName: date=${e}, index=${t}`),d.reduce(((n,r)=>r(n,t,e)),s))},Tc=({file:e,keepFileExt:t,pattern:n,fileNameSep:r})=>{let u=r||".";const o="__NOT_MATCHING__";let i=[(e,t)=>e.endsWith(".gz")?(gc("it is gzipped"),t.isCompressed=!0,e.slice(0,-1*".gz".length)):e,t?t=>t.startsWith(e.name)&&t.endsWith(e.ext)?(gc("it starts and ends with the right things"),t.slice(e.name.length+1,-1*e.ext.length)):o:t=>t.startsWith(e.base)?(gc("it starts with the right things"),t.slice(e.base.length+1)):o,n?(e,t)=>{const r=e.split(u);let o=r[r.length-1];gc("items: ",r,", indexStr: ",o);let i=e;void 0!==o&&o.match(/^\d+$/)?(i=e.slice(0,-1*(o.length+1)),gc(`dateStr is ${i}`),n&&!i&&(i=o,o="0")):o="0";try{const r=Ac.parse(n,i,new Date(0,0));return Ac.asString(n,r)!==i?e:(t.index=parseInt(o,10),t.date=i,t.timestamp=r.getTime(),"")}catch(t){return gc(`Problem parsing ${i} as ${n}, error was: `,t),e}}:(e,t)=>e.match(/^\d+$/)?(gc("it has an index"),t.index=parseInt(e,10),""):e];return e=>{let t={filename:e,index:0,isCompressed:!1};return i.reduce(((e,n)=>n(e,t)),e)?null:t}},Rc=Oc;var Mc=class extends Nc{constructor(e,t){if(bc(`constructor: creating RollingFileWriteStream. path=${e}`),"string"!=typeof e||0===e.length)throw new Error(`Invalid filename: ${e}`);if(e.endsWith(Bc.sep))throw new Error(`Filename is a directory: ${e}`);0===e.indexOf(`~${Bc.sep}`)&&(e=e.replace("~",Pc.homedir())),super(t),this.options=this._parseOption(t),this.fileObject=Bc.parse(e),""===this.fileObject.dir&&(this.fileObject=Bc.parse(Bc.join(process.cwd(),e))),this.fileFormatter=Ic({file:this.fileObject,alwaysIncludeDate:this.options.alwaysIncludePattern,needsIndex:this.options.maxSize 0`)}else delete n.maxSize;if(n.numBackups||0===n.numBackups){if(n.numBackups<0)throw new Error(`options.numBackups (${n.numBackups}) should be >= 0`);if(n.numBackups>=Number.MAX_SAFE_INTEGER)throw new Error(`options.numBackups (${n.numBackups}) should be < Number.MAX_SAFE_INTEGER`);n.numToKeep=n.numBackups+1}else if(n.numToKeep<=0)throw new Error(`options.numToKeep (${n.numToKeep}) should be > 0`);return bc(`_parseOption: creating stream with option=${JSON.stringify(n)}`),n}_final(e){this.currentFileStream.end("",this.options.encoding,e)}_write(e,t,n){this._shouldRoll().then((()=>{bc(`_write: writing chunk. file=${this.currentFileStream.path} state=${JSON.stringify(this.state)} chunk=${e}`),this.currentFileStream.write(e,t,(t=>{this.state.currentSize+=e.length,n(t)}))}))}async _shouldRoll(){(this._dateChanged()||this._tooBig())&&(bc(`_shouldRoll: rolling because dateChanged? ${this._dateChanged()} or tooBig? ${this._tooBig()}`),await this._roll())}_dateChanged(){return this.state.currentDate&&this.state.currentDate!==xc(this.options.pattern,kc())}_tooBig(){return this.state.currentSize>=this.options.maxSize}_roll(){return bc("_roll: closing the current stream"),new Promise(((e,t)=>{this.currentFileStream.end("",this.options.encoding,(()=>{this._moveOldFiles().then(e).catch(t)}))}))}async _moveOldFiles(){const e=await this._getExistingFiles();for(let t=(this.state.currentDate?e.filter((e=>e.date===this.state.currentDate)):e).length;t>=0;t--){bc(`_moveOldFiles: i = ${t}`);const e=this.fileFormatter({date:this.state.currentDate,index:t}),n=this.fileFormatter({date:this.state.currentDate,index:t+1}),r={compress:this.options.compress&&0===t,mode:this.options.mode};await Rc(e,n,r)}this.state.currentSize=0,this.state.currentDate=this.state.currentDate?xc(this.options.pattern,kc()):null,bc(`_moveOldFiles: finished rolling files. state=${JSON.stringify(this.state)}`),this._renewWriteStream(),await new Promise(((e,t)=>{this.currentFileStream.write("","utf8",(()=>{this._clean().then(e).catch(t)}))}))}async _getExistingFiles(){const e=await _c.readdir(this.fileObject.dir).catch((()=>[]));bc(`_getExistingFiles: files=${e}`);const t=e.map((e=>this.fileNameParser(e))).filter((e=>e)),n=e=>(e.timestamp?e.timestamp:kc().getTime())-e.index;return t.sort(((e,t)=>n(e)-n(t))),t}_renewWriteStream(){const e=this.fileFormatter({date:this.state.currentDate,index:0}),t=e=>{try{return _c.mkdirSync(e,{recursive:!0})}catch(n){if("ENOENT"===n.code)return t(Bc.dirname(e)),t(e);if("EEXIST"!==n.code&&"EROFS"!==n.code)throw n;try{if(_c.statSync(e).isDirectory())return e;throw n}catch(e){throw n}}};t(this.fileObject.dir);const n={flags:this.options.flags,encoding:this.options.encoding,mode:this.options.mode};var r,u;_c.appendFileSync(e,"",(r={...n},u="flags",r["flag"]=r[u],delete r[u],r)),this.currentFileStream=_c.createWriteStream(e,n),this.currentFileStream.on("error",(e=>{this.emit("error",e)}))}async _clean(){const e=await this._getExistingFiles();if(bc(`_clean: numToKeep = ${this.options.numToKeep}, existingFiles = ${e.length}`),bc("_clean: existing files are: ",e),this._tooManyFiles(e.length)){const n=e.slice(0,e.length-this.options.numToKeep).map((e=>Bc.format({dir:this.fileObject.dir,base:e.filename})));await(t=n,bc(`deleteFiles: files to delete: ${t}`),Promise.all(t.map((e=>_c.unlink(e).catch((t=>{bc(`deleteFiles: error when unlinking ${e}, ignoring. Error was ${t}`)}))))))}var t}_tooManyFiles(e){return this.options.numToKeep>0&&e>this.options.numToKeep}};const Lc=Mc;var jc=class extends Lc{constructor(e,t,n,r){r||(r={}),t&&(r.maxSize=t),r.numBackups||0===r.numBackups||(n||0===n||(n=1),r.numBackups=n),super(e,r),this.backups=r.numBackups,this.size=this.options.maxSize}get theStream(){return this.currentFileStream}};const $c=Mc;var Hc={RollingFileWriteStream:Mc,RollingFileStream:jc,DateRollingFileStream:class extends $c{constructor(e,t,n){t&&"object"==typeof t&&(n=t,t=null),n||(n={}),t||(t="yyyy-MM-dd"),n.pattern=t,n.numBackups||0===n.numBackups?n.daysToKeep=n.numBackups:(n.daysToKeep||0===n.daysToKeep?process.emitWarning("options.daysToKeep is deprecated due to the confusion it causes when used together with file size rolling. Please use options.numBackups instead.","DeprecationWarning","streamroller-DEP0001"):n.daysToKeep=1,n.numBackups=n.daysToKeep),super(e,n),this.mode=this.options.mode}get theStream(){return this.currentFileStream}}};const Jc=Nr.exports("log4js:file"),Gc=p.default,Vc=Hc,Uc=E.default.EOL;let Wc=!1;const zc=new Set;function Kc(){zc.forEach((e=>{e.sighupHandler()}))}function qc(e,t,n,r){const u=new Vc.RollingFileStream(e,t,n,r);return u.on("error",(t=>{console.error("log4js.fileAppender - Writing to file %s, error happened ",e,t)})),u.on("drain",(()=>{process.emit("log4js:pause",!1)})),u}Eo.configure=function(e,t){let n=t.basicLayout;return e.layout&&(n=t.layout(e.layout.type,e.layout)),e.mode=e.mode||384,function(e,t,n,r,u,o){e=Gc.normalize(e),Jc("Creating file appender (",e,", ",n,", ",r=r||0===r?r:5,", ",u,", ",o,")");let i=qc(e,n,r,u);const s=function(e){if(i.writable){if(!0===u.removeColor){const t=/\x1b[[0-9;]*m/g;e.data=e.data.map((e=>"string"==typeof e?e.replace(t,""):e))}i.write(t(e,o)+Uc,"utf8")||process.emit("log4js:pause",!0)}};return s.reopen=function(){i.end((()=>{i=qc(e,n,r,u)}))},s.sighupHandler=function(){Jc("SIGHUP handler called."),s.reopen()},s.shutdown=function(e){zc.delete(s),0===zc.size&&Wc&&(process.removeListener("SIGHUP",Kc),Wc=!1),i.end("","utf-8",e)},zc.add(s),Wc||(process.on("SIGHUP",Kc),Wc=!0),s}(e.filename,n,e.maxLogSize,e.backups,e,e.timezoneOffset)};var Yc={};const Xc=Hc,Zc=E.default.EOL;function Qc(e,t,n,r,u){r.maxSize=r.maxLogSize;const o=function(e,t,n){const r=new Xc.DateRollingFileStream(e,t,n);return r.on("error",(t=>{console.error("log4js.dateFileAppender - Writing to file %s, error happened ",e,t)})),r.on("drain",(()=>{process.emit("log4js:pause",!1)})),r}(e,t,r),i=function(e){o.writable&&(o.write(n(e,u)+Zc,"utf8")||process.emit("log4js:pause",!0))};return i.shutdown=function(e){o.end("","utf-8",e)},i}Yc.configure=function(e,t){let n=t.basicLayout;return e.layout&&(n=t.layout(e.layout.type,e.layout)),e.alwaysIncludePattern||(e.alwaysIncludePattern=!1),e.mode=e.mode||384,Qc(e.filename,e.pattern,n,e,e.timezoneOffset)};var ea={};const ta=Nr.exports("log4js:fileSync"),na=p.default,ra=D.default,ua=E.default.EOL||"\n";function oa(e,t){if(ra.existsSync(e))return;const n=ra.openSync(e,t.flags,t.mode);ra.closeSync(n)}class ia{constructor(e,t,n,r){ta("In RollingFileStream"),function(){if(!e||!t||t<=0)throw new Error("You must specify a filename and file size")}(),this.filename=e,this.size=t,this.backups=n,this.options=r,this.currentSize=0,this.currentSize=function(e){let t=0;try{t=ra.statSync(e).size}catch(t){oa(e,r)}return t}(this.filename)}shouldRoll(){return ta("should roll with current size %d, and max size %d",this.currentSize,this.size),this.currentSize>=this.size}roll(e){const t=this,n=new RegExp(`^${na.basename(e)}`);function r(e){return n.test(e)}function u(t){return parseInt(t.substring(`${na.basename(e)}.`.length),10)||0}function o(e,t){return u(e)>u(t)?1:u(e) ${e}.${r+1}`),ra.renameSync(na.join(na.dirname(e),n),`${e}.${r+1}`)}}ta("Rolling, rolling, rolling"),ta("Renaming the old files"),ra.readdirSync(na.dirname(e)).filter(r).sort(o).reverse().forEach(i)}write(e,t){const n=this;ta("in write"),this.shouldRoll()&&(this.currentSize=0,this.roll(this.filename)),ta("writing the chunk to the file"),n.currentSize+=e.length,ra.appendFileSync(n.filename,e)}}ea.configure=function(e,t){let n=t.basicLayout;e.layout&&(n=t.layout(e.layout.type,e.layout));const r={flags:e.flags||"a",encoding:e.encoding||"utf8",mode:e.mode||384};return function(e,t,n,r,u,o){ta("fileSync appender created");const i=function(e,t,n){let r;var u;return t?r=new ia(e,t,n,o):(oa(u=e,o),r={write(e){ra.appendFileSync(u,e)}}),r}(e=na.normalize(e),n,r=r||0===r?r:5);return e=>{i.write(t(e,u)+ua)}}(e.filename,n,e.maxLogSize,e.backups,e.timezoneOffset,r)};var sa={};const ca=Nr.exports("log4js:tcp"),aa=S.default;sa.configure=function(e,t){ca(`configure with config = ${e}`);let n=function(e){return e.serialise()};return e.layout&&(n=t.layout(e.layout.type,e.layout)),function(e,t){let n=!1;const r=[];let u,o=3,i="__LOG4JS__";function s(e){ca("Writing log event to socket"),n=u.write(`${t(e)}${i}`,"utf8")}function c(){let e;for(ca("emptying buffer");e=r.shift();)s(e)}function a(e){n?s(e):(ca("buffering log event because it cannot write at the moment"),r.push(e))}return function t(){ca(`appender creating socket to ${e.host||"localhost"}:${e.port||5e3}`),i=`${e.endMsg||"__LOG4JS__"}`,u=aa.createConnection(e.port||5e3,e.host||"localhost"),u.on("connect",(()=>{ca("socket connected"),c(),n=!0})),u.on("drain",(()=>{ca("drain event received, emptying buffer"),n=!0,c()})),u.on("timeout",u.end.bind(u)),u.on("error",(e=>{ca("connection error",e),n=!1,c()})),u.on("close",t)}(),a.shutdown=function(e){ca("shutdown called"),r.length&&o?(ca("buffer has items, waiting 100ms to empty"),o-=1,setTimeout((()=>{a.shutdown(e)}),100)):(u.removeAllListeners("close"),u.end(e))},a}(e,n)};const la=p.default,fa=Nr.exports("log4js:appenders"),da=tu,Da=eo,pa=gu,Ea=hu,ma=to,ha=new Map;ha.set("console",oo),ha.set("stdout",so),ha.set("stderr",co),ha.set("logLevelFilter",ao),ha.set("categoryFilter",lo),ha.set("noLogFilter",Do),ha.set("file",Eo),ha.set("dateFile",Yc),ha.set("fileSync",ea),ha.set("tcp",sa);const ya=new Map,Ca=(e,t)=>{fa("Loading module from ",e);try{return require(e)}catch(n){return void da.throwExceptionIf(t,"MODULE_NOT_FOUND"!==n.code,`appender "${e}" could not be loaded (error was: ${n})`)}},Fa=new Set,ga=(e,t)=>{if(ya.has(e))return ya.get(e);if(!t.appenders[e])return!1;if(Fa.has(e))throw new Error(`Dependency loop detected for appender ${e}.`);Fa.add(e),fa(`Creating appender ${e}`);const n=Aa(e,t);return Fa.delete(e),ya.set(e,n),n},Aa=(e,t)=>{const n=t.appenders[e],r=n.type.configure?n.type:((e,t)=>ha.get(e)||Ca(`./${e}`,t)||Ca(e,t)||require.main&&Ca(la.join(la.dirname(require.main.filename),e),t)||Ca(la.join(process.cwd(),e),t))(n.type,t);return da.throwExceptionIf(t,da.not(r),`appender "${e}" is not valid (type "${n.type}" could not be found)`),r.appender&&fa(`DEPRECATION: Appender ${n.type} exports an appender function.`),r.shutdown&&fa(`DEPRECATION: Appender ${n.type} exports a shutdown function.`),fa(`${e}: clustering.isMaster ? ${Da.isMaster()}`),fa(`${e}: appenderModule is ${F.default.inspect(r)}`),Da.onlyOnMaster((()=>(fa(`calling appenderModule.configure for ${e} / ${n.type}`),r.configure(ma.modifyConfig(n),Ea,(e=>ga(e,t)),pa))),(()=>{}))},va=e=>{ya.clear(),Fa.clear();const t=[];Object.values(e.categories).forEach((e=>{t.push(...e.appenders)})),Object.keys(e.appenders).forEach((n=>{(t.includes(n)||"tcp-server"===e.appenders[n].type)&&ga(n,e)}))},Sa=()=>{va({appenders:{out:{type:"stdout"}},categories:{default:{appenders:["out"],level:"trace"}}})};Sa(),da.addListener((e=>{da.throwExceptionIf(e,da.not(da.anObject(e.appenders)),'must have a property "appenders" of type object.');const t=Object.keys(e.appenders);da.throwExceptionIf(e,da.not(t.length),"must define at least one appender."),t.forEach((t=>{da.throwExceptionIf(e,da.not(e.appenders[t].type),`appender "${t}" is not valid (must be an object with property "type")`)}))})),da.addListener(va),Au.exports=ya,Au.exports.init=Sa;var wa={exports:{}};!function(e){const t=Nr.exports("log4js:categories"),n=tu,r=gu,u=Au.exports,o=new Map;function i(e,t,n){if(!1===t.inherit)return;const r=n.lastIndexOf(".");if(r<0)return;const u=n.substring(0,r);let o=e.categories[u];o||(o={inherit:!0,appenders:[]}),i(e,o,u),!e.categories[u]&&o.appenders&&o.appenders.length&&o.level&&(e.categories[u]=o),t.appenders=t.appenders||[],t.level=t.level||o.level,o.appenders.forEach((e=>{t.appenders.includes(e)||t.appenders.push(e)})),t.parent=o}function s(e){if(!e.categories)return;Object.keys(e.categories).forEach((t=>{const n=e.categories[t];i(e,n,t)}))}n.addPreProcessingListener((e=>s(e))),n.addListener((e=>{n.throwExceptionIf(e,n.not(n.anObject(e.categories)),'must have a property "categories" of type object.');const t=Object.keys(e.categories);n.throwExceptionIf(e,n.not(t.length),"must define at least one category."),t.forEach((t=>{const o=e.categories[t];n.throwExceptionIf(e,[n.not(o.appenders),n.not(o.level)],`category "${t}" is not valid (must be an object with properties "appenders" and "level")`),n.throwExceptionIf(e,n.not(Array.isArray(o.appenders)),`category "${t}" is not valid (appenders must be an array of appender names)`),n.throwExceptionIf(e,n.not(o.appenders.length),`category "${t}" is not valid (appenders must contain at least one appender name)`),Object.prototype.hasOwnProperty.call(o,"enableCallStack")&&n.throwExceptionIf(e,"boolean"!=typeof o.enableCallStack,`category "${t}" is not valid (enableCallStack must be boolean type)`),o.appenders.forEach((r=>{n.throwExceptionIf(e,n.not(u.get(r)),`category "${t}" is not valid (appender "${r}" is not defined)`)})),n.throwExceptionIf(e,n.not(r.getLevel(o.level)),`category "${t}" is not valid (level "${o.level}" not recognised; valid levels are ${r.levels.join(", ")})`)})),n.throwExceptionIf(e,n.not(e.categories.default),'must define a "default" category.')}));const c=e=>{o.clear();Object.keys(e.categories).forEach((n=>{const i=e.categories[n],s=[];i.appenders.forEach((e=>{s.push(u.get(e)),t(`Creating category ${n}`),o.set(n,{appenders:s,level:r.getLevel(i.level),enableCallStack:i.enableCallStack||!1})}))}))},a=()=>{c({categories:{default:{appenders:["out"],level:"OFF"}}})};a(),n.addListener(c);const l=e=>(t(`configForCategory: searching for config for ${e}`),o.has(e)?(t(`configForCategory: ${e} exists in config, returning it`),o.get(e)):e.indexOf(".")>0?(t(`configForCategory: ${e} has hierarchy, searching for parents`),l(e.substring(0,e.lastIndexOf(".")))):(t("configForCategory: returning config for default category"),l("default")));e.exports=o,e.exports=Object.assign(e.exports,{appendersForCategory:e=>l(e).appenders,getLevelForCategory:e=>l(e).level,setLevelForCategory:(e,n)=>{let r=o.get(e);if(t(`setLevelForCategory: found ${r} for ${e}`),!r){const n=l(e);t(`setLevelForCategory: no config found for category, found ${n} for parents of ${e}`),r={appenders:n.appenders}}r.level=n,o.set(e,r)},getEnableCallStackForCategory:e=>!0===l(e).enableCallStack,setEnableCallStackForCategory:(e,t)=>{l(e).enableCallStack=t},init:a})}(wa);const Oa=Nr.exports("log4js:logger"),ba=Hu,_a=gu,Ba=eo,Pa=wa.exports,ka=tu,xa=/at (?:(.+)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/;function Na(e,t=4){const n=e.stack.split("\n").slice(t),r=xa.exec(n[0]);return r&&6===r.length?{functionName:r[1],fileName:r[2],lineNumber:parseInt(r[3],10),columnNumber:parseInt(r[4],10),callStack:n.join("\n")}:null}class Ia{constructor(e){if(!e)throw new Error("No category provided.");this.category=e,this.context={},this.parseCallStack=Na,Oa(`Logger created (${this.category}, ${this.level})`)}get level(){return _a.getLevel(Pa.getLevelForCategory(this.category),_a.TRACE)}set level(e){Pa.setLevelForCategory(this.category,_a.getLevel(e,this.level))}get useCallStack(){return Pa.getEnableCallStackForCategory(this.category)}set useCallStack(e){Pa.setEnableCallStackForCategory(this.category,!0===e)}log(e,...t){let n=_a.getLevel(e);n||(this._log(_a.WARN,"log4js:logger.log: invalid value for log-level as first parameter given: ",e),n=_a.INFO),this.isLevelEnabled(n)&&this._log(n,t)}isLevelEnabled(e){return this.level.isLessThanOrEqualTo(e)}_log(e,t){Oa(`sending log data (${e}) to appenders`);const n=new ba(this.category,e,t,this.context,this.useCallStack&&this.parseCallStack(new Error));Ba.send(n)}addContext(e,t){this.context[e]=t}removeContext(e){delete this.context[e]}clearContext(){this.context={}}setParseCallStackFunction(e){this.parseCallStack=e}}function Ta(e){const t=_a.getLevel(e),n=t.toString().toLowerCase().replace(/_([a-z])/g,(e=>e[1].toUpperCase())),r=n[0].toUpperCase()+n.slice(1);Ia.prototype[`is${r}Enabled`]=function(){return this.isLevelEnabled(t)},Ia.prototype[n]=function(...e){this.log(t,...e)}}_a.levels.forEach(Ta),ka.addListener((()=>{_a.levels.forEach(Ta)}));var Ra=Ia;const Ma=gu;function La(e){return e.originalUrl||e.url}function ja(e,t){for(let n=0;ne.source?e.source:e));t=new RegExp(n.join("|"))}return t}(t.nolog);return(e,i,s)=>{if(e._logging)return s();if(o&&o.test(e.originalUrl))return s();if(n.isLevelEnabled(r)||"auto"===t.level){const o=new Date,{writeHead:s}=i;e._logging=!0,i.writeHead=(e,t)=>{i.writeHead=s,i.writeHead(e,t),i.__statusCode=e,i.__headers=t||{}},i.on("finish",(()=>{i.responseTime=new Date-o,i.statusCode&&"auto"===t.level&&(r=Ma.INFO,i.statusCode>=300&&(r=Ma.WARN),i.statusCode>=400&&(r=Ma.ERROR)),r=function(e,t,n){let r=t;if(n){const t=n.find((t=>{let n=!1;return n=t.from&&t.to?e>=t.from&&e<=t.to:-1!==t.codes.indexOf(e),n}));t&&(r=Ma.getLevel(t.level,r))}return r}(i.statusCode,r,t.statusRules);const s=function(e,t,n){const r=[];return r.push({token:":url",replacement:La(e)}),r.push({token:":protocol",replacement:e.protocol}),r.push({token:":hostname",replacement:e.hostname}),r.push({token:":method",replacement:e.method}),r.push({token:":status",replacement:t.__statusCode||t.statusCode}),r.push({token:":response-time",replacement:t.responseTime}),r.push({token:":date",replacement:(new Date).toUTCString()}),r.push({token:":referrer",replacement:e.headers.referer||e.headers.referrer||""}),r.push({token:":http-version",replacement:`${e.httpVersionMajor}.${e.httpVersionMinor}`}),r.push({token:":remote-addr",replacement:e.headers["x-forwarded-for"]||e.ip||e._remoteAddress||e.socket&&(e.socket.remoteAddress||e.socket.socket&&e.socket.socket.remoteAddress)}),r.push({token:":user-agent",replacement:e.headers["user-agent"]}),r.push({token:":content-length",replacement:t.getHeader("content-length")||t.__headers&&t.__headers["Content-Length"]||"-"}),r.push({token:/:req\[([^\]]+)]/g,replacement:(t,n)=>e.headers[n.toLowerCase()]}),r.push({token:/:res\[([^\]]+)]/g,replacement:(e,n)=>t.getHeader(n.toLowerCase())||t.__headers&&t.__headers[n]}),(e=>{const t=e.concat();for(let e=0;eja(e,s)));t&&n.log(r,t)}else n.log(r,ja(u,s));t.context&&n.removeContext("res")}))}return s()}},nl=Va;let rl=!1;function ul(e){if(!rl)return;Ua("Received log event ",e);Za.appendersForCategory(e.categoryName).forEach((t=>{t(e)}))}function ol(e){rl&&il();let t=e;return"string"==typeof t&&(t=function(e){Ua(`Loading configuration from ${e}`);try{return JSON.parse(Wa.readFileSync(e,"utf8"))}catch(t){throw new Error(`Problem reading config from file "${e}". Error was ${t.message}`,t)}}(e)),Ua(`Configuration is ${t}`),Ka.configure(za(t)),el.onMessage(ul),rl=!0,sl}function il(e){Ua("Shutdown called. Disabling all log writing."),rl=!1;const t=Array.from(Xa.values());Xa.init(),Za.init();const n=t.reduceRight(((e,t)=>t.shutdown?e+1:e),0);if(0===n)return Ua("No appenders with shutdown functions found."),void 0!==e&&e();let r,u=0;function o(t){r=r||t,u+=1,Ua(`Appender shutdowns complete: ${u} / ${n}`),u>=n&&(Ua("All shutdown functions completed."),e&&e(r))}return Ua(`Found ${n} appenders with shutdown functions.`),t.filter((e=>e.shutdown)).forEach((e=>e.shutdown(o))),null}const sl={getLogger:function(e){return rl||ol(process.env.LOG4JS_CONFIG||{appenders:{out:{type:"stdout"}},categories:{default:{appenders:["out"],level:"OFF"}}}),new Qa(e||"default")},configure:ol,shutdown:il,connectLogger:tl,levels:Ya,addLayout:qa.addLayout,recording:function(){return nl}};var cl=sl,al={};Object.defineProperty(al,"__esModule",{value:!0}),al.levelMap=al.getLevel=al.setCategoriesLevel=al.getConfiguration=al.setConfiguration=void 0;const ll=cl;let fl={appenders:{debug:{type:"stdout",layout:{type:"pattern",pattern:"[%d] > hvigor %p %c %[%m%]"}},info:{type:"stdout",layout:{type:"pattern",pattern:"[%d] > hvigor %[%m%]"}},"no-pattern-info":{type:"stdout",layout:{type:"pattern",pattern:"%m"}},wrong:{type:"stderr",layout:{type:"pattern",pattern:"[%d] > hvigor %[%p: %m%]"}},"just-debug":{type:"logLevelFilter",appender:"debug",level:"debug",maxLevel:"debug"},"just-info":{type:"logLevelFilter",appender:"info",level:"info",maxLevel:"info"},"just-wrong":{type:"logLevelFilter",appender:"wrong",level:"warn",maxLevel:"error"}},categories:{default:{appenders:["just-debug","just-info","just-wrong"],level:"debug"},"no-pattern-info":{appenders:["no-pattern-info"],level:"info"}}};al.setConfiguration=e=>{fl=e};al.getConfiguration=()=>fl;let dl=ll.levels.DEBUG;al.setCategoriesLevel=(e,t)=>{dl=e;const n=fl.categories;for(const r in n)(null==t?void 0:t.includes(r))||Object.prototype.hasOwnProperty.call(n,r)&&(n[r].level=e.levelStr)};al.getLevel=()=>dl,al.levelMap=new Map([["ALL",ll.levels.ALL],["MARK",ll.levels.MARK],["TRACE",ll.levels.TRACE],["DEBUG",ll.levels.DEBUG],["INFO",ll.levels.INFO],["WARN",ll.levels.WARN],["ERROR",ll.levels.ERROR],["FATAL",ll.levels.FATAL],["OFF",ll.levels.OFF]]);var Dl=w&&w.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var u=Object.getOwnPropertyDescriptor(t,n);u&&!("get"in u?!t.__esModule:u.writable||u.configurable)||(u={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,u)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),pl=w&&w.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),El=w&&w.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&Dl(t,e,n);return pl(t,e),t};Object.defineProperty(xr,"__esModule",{value:!0}),xr.evaluateLogLevel=xr.HvigorLogger=void 0;const ml=El(cl),hl=cl,yl=El(F.default),Cl=al;class Fl{constructor(e){ml.configure((0,Cl.getConfiguration)()),this._logger=ml.getLogger(e),this._logger.level=(0,Cl.getLevel)()}static getLogger(e){return new Fl(e)}log(e,...t){this._logger.log(e,...t)}debug(e,...t){this._logger.debug(e,...t)}info(e,...t){this._logger.info(e,...t)}warn(e,...t){void 0!==e&&""!==e&&this._logger.warn(e,...t)}error(e,...t){this._logger.error(e,...t)}_printTaskExecuteInfo(e,t){this.info(`Finished :${e}... after ${t}`)}_printFailedTaskInfo(e){this.error(`Failed :${e}... `)}_printDisabledTaskInfo(e){this.info(`Disabled :${e}... `)}_printUpToDateTaskInfo(e){this.info(`UP-TO-DATE :${e}... `)}errorMessageExit(e,...t){throw new Error(yl.format(e,...t))}errorExit(e,t,...n){t&&this._logger.error(t,n),this._logger.error(e.stack)}setLevel(e,t){(0,Cl.setCategoriesLevel)(e,t),ml.shutdown(),ml.configure((0,Cl.getConfiguration)())}getLevel(){return this._logger.level}configure(e){const t=(0,Cl.getConfiguration)(),n={appenders:{...t.appenders,...e.appenders},categories:{...t.categories,...e.categories}};(0,Cl.setConfiguration)(n),ml.shutdown(),ml.configure(n)}}xr.HvigorLogger=Fl,xr.evaluateLogLevel=function(e,t){t.debug?e.setLevel(hl.levels.DEBUG):t.warn?e.setLevel(hl.levels.WARN):t.error?e.setLevel(hl.levels.ERROR):e.setLevel(hl.levels.INFO)};var gl=w&&w.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(X,"__esModule",{value:!0}),X.parseJsonText=X.parseJsonFile=void 0;const Al=Z,vl=gl(kr),Sl=gl(p.default),wl=gl(E.default),Ol=xr.HvigorLogger.getLogger("parse-json-util");var bl;!function(e){e[e.Char=0]="Char",e[e.EOF=1]="EOF",e[e.Identifier=2]="Identifier"}(bl||(bl={}));let _l,Bl,Pl,kl,xl,Nl,Il="start",Tl=[],Rl=0,Ml=1,Ll=0,jl=!1,$l="default",Hl="'",Jl=1;function Gl(e,t=!1){Bl=String(e),Il="start",Tl=[],Rl=0,Ml=1,Ll=0,kl=void 0,jl=t;do{_l=Vl(),Xl[Il]()}while("eof"!==_l.type);return kl}function Vl(){for($l="default",xl="",Hl="'",Jl=1;;){Nl=Ul();const e=zl[$l]();if(e)return e}}function Ul(){if(Bl[Rl])return String.fromCodePoint(Bl.codePointAt(Rl))}function Wl(){const e=Ul();return"\n"===e?(Ml++,Ll=0):e?Ll+=e.length:Ll++,e&&(Rl+=e.length),e}X.parseJsonFile=function(e,t=!1,n="utf-8"){const r=vl.default.readFileSync(Sl.default.resolve(e),{encoding:n});try{return Gl(r,t)}catch(t){if(t instanceof SyntaxError){const n=t.message.split("at");2===n.length&&Ol.errorMessageExit(`${n[0].trim()}${wl.default.EOL}\t at ${e}:${n[1].trim()}`)}Ol.errorMessageExit(`${e} is not in valid JSON/JSON5 format.`)}},X.parseJsonText=Gl;const zl={default(){switch(Nl){case"/":return Wl(),void($l="comment");case void 0:return Wl(),Kl("eof")}if(!Al.JudgeUtil.isIgnoreChar(Nl)&&!Al.JudgeUtil.isSpaceSeparator(Nl))return zl[Il]();Wl()},start(){$l="value"},beforePropertyName(){switch(Nl){case"$":case"_":return xl=Wl(),void($l="identifierName");case"\\":return Wl(),void($l="identifierNameStartEscape");case"}":return Kl("punctuator",Wl());case'"':case"'":return Hl=Nl,Wl(),void($l="string")}if(Al.JudgeUtil.isIdStartChar(Nl))return xl+=Wl(),void($l="identifierName");throw tf(bl.Char,Wl())},afterPropertyName(){if(":"===Nl)return Kl("punctuator",Wl());throw tf(bl.Char,Wl())},beforePropertyValue(){$l="value"},afterPropertyValue(){switch(Nl){case",":case"}":return Kl("punctuator",Wl())}throw tf(bl.Char,Wl())},beforeArrayValue(){if("]"===Nl)return Kl("punctuator",Wl());$l="value"},afterArrayValue(){switch(Nl){case",":case"]":return Kl("punctuator",Wl())}throw tf(bl.Char,Wl())},end(){throw tf(bl.Char,Wl())},comment(){switch(Nl){case"*":return Wl(),void($l="multiLineComment");case"/":return Wl(),void($l="singleLineComment")}throw tf(bl.Char,Wl())},multiLineComment(){switch(Nl){case"*":return Wl(),void($l="multiLineCommentAsterisk");case void 0:throw tf(bl.Char,Wl())}Wl()},multiLineCommentAsterisk(){switch(Nl){case"*":return void Wl();case"/":return Wl(),void($l="default");case void 0:throw tf(bl.Char,Wl())}Wl(),$l="multiLineComment"},singleLineComment(){switch(Nl){case"\n":case"\r":case"\u2028":case"\u2029":return Wl(),void($l="default");case void 0:return Wl(),Kl("eof")}Wl()},value(){switch(Nl){case"{":case"[":return Kl("punctuator",Wl());case"n":return Wl(),ql("ull"),Kl("null",null);case"t":return Wl(),ql("rue"),Kl("boolean",!0);case"f":return Wl(),ql("alse"),Kl("boolean",!1);case"-":case"+":return"-"===Wl()&&(Jl=-1),void($l="numerical");case".":case"0":case"I":case"N":return void($l="numerical");case'"':case"'":return Hl=Nl,Wl(),xl="",void($l="string")}if(void 0===Nl||!Al.JudgeUtil.isDigitWithoutZero(Nl))throw tf(bl.Char,Wl());$l="numerical"},numerical(){switch(Nl){case".":return xl=Wl(),void($l="decimalPointLeading");case"0":return xl=Wl(),void($l="zero");case"I":return Wl(),ql("nfinity"),Kl("numeric",Jl*(1/0));case"N":return Wl(),ql("aN"),Kl("numeric",NaN)}if(void 0!==Nl&&Al.JudgeUtil.isDigitWithoutZero(Nl))return xl=Wl(),void($l="decimalInteger");throw tf(bl.Char,Wl())},zero(){switch(Nl){case".":case"e":case"E":return void($l="decimal");case"x":case"X":return xl+=Wl(),void($l="hexadecimal")}return Kl("numeric",0)},decimalInteger(){switch(Nl){case".":case"e":case"E":return void($l="decimal")}if(!Al.JudgeUtil.isDigit(Nl))return Kl("numeric",Jl*Number(xl));xl+=Wl()},decimal(){switch(Nl){case".":xl+=Wl(),$l="decimalFraction";break;case"e":case"E":xl+=Wl(),$l="decimalExponent"}},decimalPointLeading(){if(Al.JudgeUtil.isDigit(Nl))return xl+=Wl(),void($l="decimalFraction");throw tf(bl.Char,Wl())},decimalFraction(){switch(Nl){case"e":case"E":return xl+=Wl(),void($l="decimalExponent")}if(!Al.JudgeUtil.isDigit(Nl))return Kl("numeric",Jl*Number(xl));xl+=Wl()},decimalExponent(){switch(Nl){case"+":case"-":return xl+=Wl(),void($l="decimalExponentSign")}if(Al.JudgeUtil.isDigit(Nl))return xl+=Wl(),void($l="decimalExponentInteger");throw tf(bl.Char,Wl())},decimalExponentSign(){if(Al.JudgeUtil.isDigit(Nl))return xl+=Wl(),void($l="decimalExponentInteger");throw tf(bl.Char,Wl())},decimalExponentInteger(){if(!Al.JudgeUtil.isDigit(Nl))return Kl("numeric",Jl*Number(xl));xl+=Wl()},hexadecimal(){if(Al.JudgeUtil.isHexDigit(Nl))return xl+=Wl(),void($l="hexadecimalInteger");throw tf(bl.Char,Wl())},hexadecimalInteger(){if(!Al.JudgeUtil.isHexDigit(Nl))return Kl("numeric",Jl*Number(xl));xl+=Wl()},identifierNameStartEscape(){if("u"!==Nl)throw tf(bl.Char,Wl());Wl();const e=Yl();switch(e){case"$":case"_":break;default:if(!Al.JudgeUtil.isIdStartChar(e))throw tf(bl.Identifier)}xl+=e,$l="identifierName"},identifierName(){switch(Nl){case"$":case"_":case"‌":case"‍":return void(xl+=Wl());case"\\":return Wl(),void($l="identifierNameEscape")}if(!Al.JudgeUtil.isIdContinueChar(Nl))return Kl("identifier",xl);xl+=Wl()},identifierNameEscape(){if("u"!==Nl)throw tf(bl.Char,Wl());Wl();const e=Yl();switch(e){case"$":case"_":case"‌":case"‍":break;default:if(!Al.JudgeUtil.isIdContinueChar(e))throw tf(bl.Identifier)}xl+=e,$l="identifierName"},string(){switch(Nl){case"\\":return Wl(),void(xl+=function(){const e=Ul(),t=function(){switch(Ul()){case"b":return Wl(),"\b";case"f":return Wl(),"\f";case"n":return Wl(),"\n";case"r":return Wl(),"\r";case"t":return Wl(),"\t";case"v":return Wl(),"\v"}return}();if(t)return t;switch(e){case"0":if(Wl(),Al.JudgeUtil.isDigit(Ul()))throw tf(bl.Char,Wl());return"\0";case"x":return Wl(),function(){let e="",t=Ul();if(!Al.JudgeUtil.isHexDigit(t))throw tf(bl.Char,Wl());if(e+=Wl(),t=Ul(),!Al.JudgeUtil.isHexDigit(t))throw tf(bl.Char,Wl());return e+=Wl(),String.fromCodePoint(parseInt(e,16))}();case"u":return Wl(),Yl();case"\n":case"\u2028":case"\u2029":return Wl(),"";case"\r":return Wl(),"\n"===Ul()&&Wl(),""}if(void 0===e||Al.JudgeUtil.isDigitWithoutZero(e))throw tf(bl.Char,Wl());return Wl()}());case'"':case"'":if(Nl===Hl){const e=Kl("string",xl);return Wl(),e}return void(xl+=Wl());case"\n":case"\r":case void 0:throw tf(bl.Char,Wl());case"\u2028":case"\u2029":!function(e){Ol.warn(`JSON5: '${ef(e)}' in strings is not valid ECMAScript; consider escaping.`)}(Nl)}xl+=Wl()}};function Kl(e,t){return{type:e,value:t,line:Ml,column:Ll}}function ql(e){for(const t of e){if(Ul()!==t)throw tf(bl.Char,Wl());Wl()}}function Yl(){let e="",t=4;for(;t-- >0;){const t=Ul();if(!Al.JudgeUtil.isHexDigit(t))throw tf(bl.Char,Wl());e+=Wl()}return String.fromCodePoint(parseInt(e,16))}const Xl={start(){if("eof"===_l.type)throw tf(bl.EOF);Zl()},beforePropertyName(){switch(_l.type){case"identifier":case"string":return Pl=_l.value,void(Il="afterPropertyName");case"punctuator":return void Ql();case"eof":throw tf(bl.EOF)}},afterPropertyName(){if("eof"===_l.type)throw tf(bl.EOF);Il="beforePropertyValue"},beforePropertyValue(){if("eof"===_l.type)throw tf(bl.EOF);Zl()},afterPropertyValue(){if("eof"===_l.type)throw tf(bl.EOF);switch(_l.value){case",":return void(Il="beforePropertyName");case"}":Ql()}},beforeArrayValue(){if("eof"===_l.type)throw tf(bl.EOF);"punctuator"!==_l.type||"]"!==_l.value?Zl():Ql()},afterArrayValue(){if("eof"===_l.type)throw tf(bl.EOF);switch(_l.value){case",":return void(Il="beforeArrayValue");case"]":Ql()}},end(){}};function Zl(){const e=function(){let e;switch(_l.type){case"punctuator":switch(_l.value){case"{":e={};break;case"[":e=[]}break;case"null":case"boolean":case"numeric":case"string":e=_l.value}return e}();if(jl&&"object"==typeof e&&(e._line=Ml,e._column=Ll),void 0===kl)kl=e;else{const t=Tl[Tl.length-1];Array.isArray(t)?jl&&"object"!=typeof e?t.push({value:e,_line:Ml,_column:Ll}):t.push(e):t[Pl]=jl&&"object"!=typeof e?{value:e,_line:Ml,_column:Ll}:e}!function(e){if(e&&"object"==typeof e)Tl.push(e),Il=Array.isArray(e)?"beforeArrayValue":"beforePropertyName";else{const e=Tl[Tl.length-1];Il=e?Array.isArray(e)?"afterArrayValue":"afterPropertyValue":"end"}}(e)}function Ql(){Tl.pop();const e=Tl[Tl.length-1];Il=e?Array.isArray(e)?"afterArrayValue":"afterPropertyValue":"end"}function ef(e){const t={"'":"\\'",'"':'\\"',"\\":"\\\\","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\v":"\\v","\0":"\\0","\u2028":"\\u2028","\u2029":"\\u2029"};if(t[e])return t[e];if(e<" "){const t=e.charCodeAt(0).toString(16);return`\\x${`00${t}`.substring(t.length)}`}return e}function tf(e,t){let n="";switch(e){case bl.Char:n=void 0===t?`JSON5: invalid end of input at ${Ml}:${Ll}`:`JSON5: invalid character '${ef(t)}' at ${Ml}:${Ll}`;break;case bl.EOF:n=`JSON5: invalid end of input at ${Ml}:${Ll}`;break;case bl.Identifier:Ll-=5,n=`JSON5: invalid identifier character at ${Ml}:${Ll}`}const r=new nf(n);return r.lineNumber=Ml,r.columnNumber=Ll,r}class nf extends SyntaxError{}var rf=w&&w.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var u=Object.getOwnPropertyDescriptor(t,n);u&&!("get"in u?!t.__esModule:u.writable||u.configurable)||(u={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,u)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),uf=w&&w.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),of=w&&w.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&rf(t,e,n);return uf(t,e),t};Object.defineProperty(Y,"__esModule",{value:!0});var sf=Y.cleanWorkSpace=Ff=Y.executeInstallHvigor=yf=Y.isHvigorInstalled=mf=Y.isAllDependenciesInstalled=void 0;const cf=of(D.default),af=of(p.default),lf=b,ff=j,df=$,Df=X;let pf,Ef;var mf=Y.isAllDependenciesInstalled=function(){function e(e){const t=null==e?void 0:e.dependencies;return void 0===t?0:Object.getOwnPropertyNames(t).length}if(pf=gf(),Ef=Af(),e(pf)+1!==e(Ef))return!1;for(const e in null==pf?void 0:pf.dependencies)if(!(0,ff.hasNpmPackInPaths)(e,[lf.HVIGOR_PROJECT_DEPENDENCIES_HOME])||!hf(e,pf,Ef))return!1;return!0};function hf(e,t,n){return void 0!==n.dependencies&&(0,ff.offlinePluginConversion)(lf.HVIGOR_PROJECT_ROOT_DIR,t.dependencies[e])===n.dependencies[e]}var yf=Y.isHvigorInstalled=function(){return pf=gf(),Ef=Af(),(0,ff.hasNpmPackInPaths)(lf.HVIGOR_ENGINE_PACKAGE_NAME,[lf.HVIGOR_PROJECT_DEPENDENCIES_HOME])&&(0,ff.offlinePluginConversion)(lf.HVIGOR_PROJECT_ROOT_DIR,pf.hvigorVersion)===Ef.dependencies[lf.HVIGOR_ENGINE_PACKAGE_NAME]};const Cf={cwd:lf.HVIGOR_PROJECT_DEPENDENCIES_HOME,stdio:["inherit","inherit","inherit"]};var Ff=Y.executeInstallHvigor=function(){(0,df.logInfoPrintConsole)("Hvigor installing...");const e={dependencies:{}};e.dependencies[lf.HVIGOR_ENGINE_PACKAGE_NAME]=(0,ff.offlinePluginConversion)(lf.HVIGOR_PROJECT_ROOT_DIR,pf.hvigorVersion);try{cf.mkdirSync(lf.HVIGOR_PROJECT_DEPENDENCIES_HOME,{recursive:!0});const t=af.resolve(lf.HVIGOR_PROJECT_DEPENDENCIES_HOME,lf.DEFAULT_PACKAGE_JSON);cf.writeFileSync(t,JSON.stringify(e))}catch(e){(0,df.logErrorAndExit)(e)}!function(){const e=["config","set","store-dir",lf.HVIGOR_PNPM_STORE_PATH];(0,ff.executeCommand)(lf.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH,e,Cf)}(),(0,ff.executeCommand)(lf.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH,["install"],Cf)};function gf(){const e=af.resolve(lf.HVIGOR_PROJECT_WRAPPER_HOME,lf.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME);return cf.existsSync(e)||(0,df.logErrorAndExit)(`Error: Hvigor config file ${e} does not exist.`),(0,Df.parseJsonFile)(e)}function Af(){return cf.existsSync(lf.HVIGOR_PROJECT_DEPENDENCY_PACKAGE_JSON_PATH)?(0,Df.parseJsonFile)(lf.HVIGOR_PROJECT_DEPENDENCY_PACKAGE_JSON_PATH):{dependencies:{}}}sf=Y.cleanWorkSpace=function(){if((0,df.logInfoPrintConsole)("Hvigor cleaning..."),!cf.existsSync(lf.HVIGOR_PROJECT_DEPENDENCIES_HOME))return;const e=cf.readdirSync(lf.HVIGOR_PROJECT_DEPENDENCIES_HOME);if(e&&0!==e.length){cf.existsSync(lf.HVIGOR_BOOT_JS_FILE_PATH)&&(0,ff.executeCommand)(process.argv[0],[lf.HVIGOR_BOOT_JS_FILE_PATH,"--stop-daemon"],{});try{e.forEach((e=>{cf.rmSync(af.resolve(lf.HVIGOR_PROJECT_DEPENDENCIES_HOME,e),{recursive:!0})}))}catch(e){(0,df.logErrorAndExit)(`The hvigor build tool cannot be installed. Please manually clear the workspace directory and synchronize the project again.\n\n Workspace Path: ${lf.HVIGOR_PROJECT_DEPENDENCIES_HOME}.`)}}};var vf={},Sf=w&&w.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var u=Object.getOwnPropertyDescriptor(t,n);u&&!("get"in u?!t.__esModule:u.writable||u.configurable)||(u={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,u)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),wf=w&&w.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),Of=w&&w.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&Sf(t,e,n);return wf(t,e),t};Object.defineProperty(vf,"__esModule",{value:!0});var bf=vf.executeBuild=void 0;const _f=b,Bf=Of(D.default),Pf=Of(p.default),kf=$;bf=vf.executeBuild=function(){const e=Pf.resolve(_f.HVIGOR_PROJECT_DEPENDENCIES_HOME,"node_modules","@ohos","hvigor","bin","hvigor.js");try{const t=Bf.realpathSync(e);require(t)}catch(t){(0,kf.logErrorAndExit)(`Error: ENOENT: no such file ${e},delete ${_f.HVIGOR_PROJECT_DEPENDENCIES_HOME} and retry.`)}},function(){if(O.checkNpmConifg(),O.environmentHandler(),O.isPnpmAvailable()||O.executeInstallPnpm(),yf()&&mf())bf();else{sf();try{Ff()}catch(e){return void sf()}bf()}}(); \ No newline at end of file +"use strict";var u=require("path"),D=require("os"),e=require("fs"),t=require("crypto"),r=require("child_process"),n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},i={},C={},F=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(C,"__esModule",{value:!0}),C.maxPathLength=C.isMac=C.isLinux=C.isWindows=void 0;const E=F(D),A="Windows_NT",o="Darwin";function a(){return E.default.type()===A}function c(){return E.default.type()===o}C.isWindows=a,C.isLinux=function(){return"Linux"===E.default.type()},C.isMac=c,C.maxPathLength=function(){return c()?1016:a()?259:4095},function(e){var t=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),r=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),i=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&t(D,u,e);return r(D,u),D};Object.defineProperty(e,"__esModule",{value:!0}),e.WORK_SPACE=e.HVIGOR_PROJECT_WRAPPER_HOME=e.HVIGOR_PROJECT_ROOT_DIR=e.HVIGOR_PROJECT_CACHES_HOME=e.HVIGOR_PNPM_STORE_PATH=e.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH=e.PROJECT_CACHES=e.HVIGOR_WRAPPER_TOOLS_HOME=e.HVIGOR_USER_HOME=e.DEFAULT_PACKAGE_JSON=e.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME=e.PNPM=e.HVIGOR=e.NPM_TOOL=e.PNPM_TOOL=e.HVIGOR_ENGINE_PACKAGE_NAME=void 0;const F=i(D),E=i(u),A=C;e.HVIGOR_ENGINE_PACKAGE_NAME="@ohos/hvigor",e.PNPM_TOOL=(0,A.isWindows)()?"pnpm.cmd":"pnpm",e.NPM_TOOL=(0,A.isWindows)()?"npm.cmd":"npm",e.HVIGOR="hvigor",e.PNPM="pnpm",e.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME="hvigor-config.json5",e.DEFAULT_PACKAGE_JSON="package.json",e.HVIGOR_USER_HOME=E.resolve(F.homedir(),".hvigor"),e.HVIGOR_WRAPPER_TOOLS_HOME=E.resolve(e.HVIGOR_USER_HOME,"wrapper","tools"),e.PROJECT_CACHES="project_caches",e.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH=E.resolve(e.HVIGOR_WRAPPER_TOOLS_HOME,"node_modules",".bin",e.PNPM_TOOL),e.HVIGOR_PNPM_STORE_PATH=E.resolve(e.HVIGOR_USER_HOME,"caches"),e.HVIGOR_PROJECT_CACHES_HOME=E.resolve(e.HVIGOR_USER_HOME,e.PROJECT_CACHES),e.HVIGOR_PROJECT_ROOT_DIR=process.cwd(),e.HVIGOR_PROJECT_WRAPPER_HOME=E.resolve(e.HVIGOR_PROJECT_ROOT_DIR,e.HVIGOR),e.WORK_SPACE="workspace"}(i);var s={},l={};Object.defineProperty(l,"__esModule",{value:!0}),l.logInfoPrintConsole=l.logErrorAndExit=void 0,l.logErrorAndExit=function(u){u instanceof Error?console.error(u.message):console.error(u),process.exit(-1)},l.logInfoPrintConsole=function(u){console.log(u)};var B=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),d=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),f=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&B(D,u,e);return d(D,u),D};Object.defineProperty(s,"__esModule",{value:!0});var _=s.executeBuild=void 0;const p=f(e),O=f(u),h=l;_=s.executeBuild=function(u){const D=O.resolve(u,"node_modules","@ohos","hvigor","bin","hvigor.js");try{const u=p.realpathSync(D);require(u)}catch(e){(0,h.logErrorAndExit)(`Error: ENOENT: no such file ${D},delete ${u} and retry.`)}};var P={},v={};!function(u){var D=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(u,"__esModule",{value:!0}),u.hashFile=u.hash=u.createHash=void 0;const r=D(t),i=D(e);u.createHash=(u="MD5")=>r.default.createHash(u);u.hash=(D,e)=>(0,u.createHash)(e).update(D).digest("hex");u.hashFile=(D,e)=>{if(i.default.existsSync(D))return(0,u.hash)(i.default.readFileSync(D,"utf-8"),e)}}(v);var g={},m={},R={};Object.defineProperty(R,"__esModule",{value:!0}),R.Unicode=void 0;class y{}R.Unicode=y,y.SPACE_SEPARATOR=/[\u1680\u2000-\u200A\u202F\u205F\u3000]/,y.ID_START=/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]/,y.ID_CONTINUE=/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u08D4-\u08E1\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u09FC\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9-\u0AFF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C80-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D00-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D54-\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1CD0-\u1CD2\u1CD4-\u1CF9\u1D00-\u1DF9\u1DFB-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE3E\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC00-\uDC4A\uDC50-\uDC59\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDE00-\uDE3E\uDE47\uDE50-\uDE83\uDE86-\uDE99\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC40\uDC50-\uDC59\uDC72-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD47\uDD50-\uDD59]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6\uDD00-\uDD4A\uDD50-\uDD59]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/,Object.defineProperty(m,"__esModule",{value:!0}),m.JudgeUtil=void 0;const I=R;m.JudgeUtil=class{static isIgnoreChar(u){return"string"==typeof u&&("\t"===u||"\v"===u||"\f"===u||" "===u||" "===u||"\ufeff"===u||"\n"===u||"\r"===u||"\u2028"===u||"\u2029"===u)}static isSpaceSeparator(u){return"string"==typeof u&&I.Unicode.SPACE_SEPARATOR.test(u)}static isIdStartChar(u){return"string"==typeof u&&(u>="a"&&u<="z"||u>="A"&&u<="Z"||"$"===u||"_"===u||I.Unicode.ID_START.test(u))}static isIdContinueChar(u){return"string"==typeof u&&(u>="a"&&u<="z"||u>="A"&&u<="Z"||u>="0"&&u<="9"||"$"===u||"_"===u||"‌"===u||"‍"===u||I.Unicode.ID_CONTINUE.test(u))}static isDigitWithoutZero(u){return/[1-9]/.test(u)}static isDigit(u){return"string"==typeof u&&/[0-9]/.test(u)}static isHexDigit(u){return"string"==typeof u&&/[0-9A-Fa-f]/.test(u)}};var N=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(g,"__esModule",{value:!0}),g.parseJsonText=g.parseJsonFile=void 0;const b=N(e),S=N(D),w=N(u),H=m;var x;!function(u){u[u.Char=0]="Char",u[u.EOF=1]="EOF",u[u.Identifier=2]="Identifier"}(x||(x={}));let M,T,V,G,j,J,W="start",U=[],L=0,$=1,k=0,K=!1,z="default",q="'",Z=1;function X(u,D=!1){T=String(u),W="start",U=[],L=0,$=1,k=0,G=void 0,K=D;do{M=Q(),nu[W]()}while("eof"!==M.type);return G}function Q(){for(z="default",j="",q="'",Z=1;;){J=Y();const u=Du[z]();if(u)return u}}function Y(){if(T[L])return String.fromCodePoint(T.codePointAt(L))}function uu(){const u=Y();return"\n"===u?($++,k=0):u?k+=u.length:k++,u&&(L+=u.length),u}g.parseJsonFile=function(u,D=!1,e="utf-8"){const t=b.default.readFileSync(w.default.resolve(u),{encoding:e});try{return X(t,D)}catch(D){if(D instanceof SyntaxError){const e=D.message.split("at");if(2===e.length)throw new Error(`${e[0].trim()}${S.default.EOL}\t at ${u}:${e[1].trim()}`)}throw new Error(`${u} is not in valid JSON/JSON5 format.`)}},g.parseJsonText=X;const Du={default(){switch(J){case"/":return uu(),void(z="comment");case void 0:return uu(),eu("eof")}if(!H.JudgeUtil.isIgnoreChar(J)&&!H.JudgeUtil.isSpaceSeparator(J))return Du[W]();uu()},start(){z="value"},beforePropertyName(){switch(J){case"$":case"_":return j=uu(),void(z="identifierName");case"\\":return uu(),void(z="identifierNameStartEscape");case"}":return eu("punctuator",uu());case'"':case"'":return q=J,uu(),void(z="string")}if(H.JudgeUtil.isIdStartChar(J))return j+=uu(),void(z="identifierName");throw Eu(x.Char,uu())},afterPropertyName(){if(":"===J)return eu("punctuator",uu());throw Eu(x.Char,uu())},beforePropertyValue(){z="value"},afterPropertyValue(){switch(J){case",":case"}":return eu("punctuator",uu())}throw Eu(x.Char,uu())},beforeArrayValue(){if("]"===J)return eu("punctuator",uu());z="value"},afterArrayValue(){switch(J){case",":case"]":return eu("punctuator",uu())}throw Eu(x.Char,uu())},end(){throw Eu(x.Char,uu())},comment(){switch(J){case"*":return uu(),void(z="multiLineComment");case"/":return uu(),void(z="singleLineComment")}throw Eu(x.Char,uu())},multiLineComment(){switch(J){case"*":return uu(),void(z="multiLineCommentAsterisk");case void 0:throw Eu(x.Char,uu())}uu()},multiLineCommentAsterisk(){switch(J){case"*":return void uu();case"/":return uu(),void(z="default");case void 0:throw Eu(x.Char,uu())}uu(),z="multiLineComment"},singleLineComment(){switch(J){case"\n":case"\r":case"\u2028":case"\u2029":return uu(),void(z="default");case void 0:return uu(),eu("eof")}uu()},value(){switch(J){case"{":case"[":return eu("punctuator",uu());case"n":return uu(),tu("ull"),eu("null",null);case"t":return uu(),tu("rue"),eu("boolean",!0);case"f":return uu(),tu("alse"),eu("boolean",!1);case"-":case"+":return"-"===uu()&&(Z=-1),void(z="numerical");case".":case"0":case"I":case"N":return void(z="numerical");case'"':case"'":return q=J,uu(),j="",void(z="string")}if(void 0===J||!H.JudgeUtil.isDigitWithoutZero(J))throw Eu(x.Char,uu());z="numerical"},numerical(){switch(J){case".":return j=uu(),void(z="decimalPointLeading");case"0":return j=uu(),void(z="zero");case"I":return uu(),tu("nfinity"),eu("numeric",Z*(1/0));case"N":return uu(),tu("aN"),eu("numeric",NaN)}if(void 0!==J&&H.JudgeUtil.isDigitWithoutZero(J))return j=uu(),void(z="decimalInteger");throw Eu(x.Char,uu())},zero(){switch(J){case".":case"e":case"E":return void(z="decimal");case"x":case"X":return j+=uu(),void(z="hexadecimal")}return eu("numeric",0)},decimalInteger(){switch(J){case".":case"e":case"E":return void(z="decimal")}if(!H.JudgeUtil.isDigit(J))return eu("numeric",Z*Number(j));j+=uu()},decimal(){switch(J){case".":j+=uu(),z="decimalFraction";break;case"e":case"E":j+=uu(),z="decimalExponent"}},decimalPointLeading(){if(H.JudgeUtil.isDigit(J))return j+=uu(),void(z="decimalFraction");throw Eu(x.Char,uu())},decimalFraction(){switch(J){case"e":case"E":return j+=uu(),void(z="decimalExponent")}if(!H.JudgeUtil.isDigit(J))return eu("numeric",Z*Number(j));j+=uu()},decimalExponent(){switch(J){case"+":case"-":return j+=uu(),void(z="decimalExponentSign")}if(H.JudgeUtil.isDigit(J))return j+=uu(),void(z="decimalExponentInteger");throw Eu(x.Char,uu())},decimalExponentSign(){if(H.JudgeUtil.isDigit(J))return j+=uu(),void(z="decimalExponentInteger");throw Eu(x.Char,uu())},decimalExponentInteger(){if(!H.JudgeUtil.isDigit(J))return eu("numeric",Z*Number(j));j+=uu()},hexadecimal(){if(H.JudgeUtil.isHexDigit(J))return j+=uu(),void(z="hexadecimalInteger");throw Eu(x.Char,uu())},hexadecimalInteger(){if(!H.JudgeUtil.isHexDigit(J))return eu("numeric",Z*Number(j));j+=uu()},identifierNameStartEscape(){if("u"!==J)throw Eu(x.Char,uu());uu();const u=ru();switch(u){case"$":case"_":break;default:if(!H.JudgeUtil.isIdStartChar(u))throw Eu(x.Identifier)}j+=u,z="identifierName"},identifierName(){switch(J){case"$":case"_":case"‌":case"‍":return void(j+=uu());case"\\":return uu(),void(z="identifierNameEscape")}if(!H.JudgeUtil.isIdContinueChar(J))return eu("identifier",j);j+=uu()},identifierNameEscape(){if("u"!==J)throw Eu(x.Char,uu());uu();const u=ru();switch(u){case"$":case"_":case"‌":case"‍":break;default:if(!H.JudgeUtil.isIdContinueChar(u))throw Eu(x.Identifier)}j+=u,z="identifierName"},string(){switch(J){case"\\":return uu(),void(j+=function(){const u=Y(),D=function(){switch(Y()){case"b":return uu(),"\b";case"f":return uu(),"\f";case"n":return uu(),"\n";case"r":return uu(),"\r";case"t":return uu(),"\t";case"v":return uu(),"\v"}return}();if(D)return D;switch(u){case"0":if(uu(),H.JudgeUtil.isDigit(Y()))throw Eu(x.Char,uu());return"\0";case"x":return uu(),function(){let u="",D=Y();if(!H.JudgeUtil.isHexDigit(D))throw Eu(x.Char,uu());if(u+=uu(),D=Y(),!H.JudgeUtil.isHexDigit(D))throw Eu(x.Char,uu());return u+=uu(),String.fromCodePoint(parseInt(u,16))}();case"u":return uu(),ru();case"\n":case"\u2028":case"\u2029":return uu(),"";case"\r":return uu(),"\n"===Y()&&uu(),""}if(void 0===u||H.JudgeUtil.isDigitWithoutZero(u))throw Eu(x.Char,uu());return uu()}());case'"':case"'":if(J===q){const u=eu("string",j);return uu(),u}return void(j+=uu());case"\n":case"\r":case void 0:throw Eu(x.Char,uu());case"\u2028":case"\u2029":!function(u){console.warn(`JSON5: '${Fu(u)}' in strings is not valid ECMAScript; consider escaping.`)}(J)}j+=uu()}};function eu(u,D){return{type:u,value:D,line:$,column:k}}function tu(u){for(const D of u){if(Y()!==D)throw Eu(x.Char,uu());uu()}}function ru(){let u="",D=4;for(;D-- >0;){const D=Y();if(!H.JudgeUtil.isHexDigit(D))throw Eu(x.Char,uu());u+=uu()}return String.fromCodePoint(parseInt(u,16))}const nu={start(){if("eof"===M.type)throw Eu(x.EOF);iu()},beforePropertyName(){switch(M.type){case"identifier":case"string":return V=M.value,void(W="afterPropertyName");case"punctuator":return void Cu();case"eof":throw Eu(x.EOF)}},afterPropertyName(){if("eof"===M.type)throw Eu(x.EOF);W="beforePropertyValue"},beforePropertyValue(){if("eof"===M.type)throw Eu(x.EOF);iu()},afterPropertyValue(){if("eof"===M.type)throw Eu(x.EOF);switch(M.value){case",":return void(W="beforePropertyName");case"}":Cu()}},beforeArrayValue(){if("eof"===M.type)throw Eu(x.EOF);"punctuator"!==M.type||"]"!==M.value?iu():Cu()},afterArrayValue(){if("eof"===M.type)throw Eu(x.EOF);switch(M.value){case",":return void(W="beforeArrayValue");case"]":Cu()}},end(){}};function iu(){const u=function(){let u;switch(M.type){case"punctuator":switch(M.value){case"{":u={};break;case"[":u=[]}break;case"null":case"boolean":case"numeric":case"string":u=M.value}return u}();if(K&&"object"==typeof u&&(u._line=$,u._column=k),void 0===G)G=u;else{const D=U[U.length-1];Array.isArray(D)?K&&"object"!=typeof u?D.push({value:u,_line:$,_column:k}):D.push(u):D[V]=K&&"object"!=typeof u?{value:u,_line:$,_column:k}:u}!function(u){if(u&&"object"==typeof u)U.push(u),W=Array.isArray(u)?"beforeArrayValue":"beforePropertyName";else{const u=U[U.length-1];W=u?Array.isArray(u)?"afterArrayValue":"afterPropertyValue":"end"}}(u)}function Cu(){U.pop();const u=U[U.length-1];W=u?Array.isArray(u)?"afterArrayValue":"afterPropertyValue":"end"}function Fu(u){const D={"'":"\\'",'"':'\\"',"\\":"\\\\","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\v":"\\v","\0":"\\0","\u2028":"\\u2028","\u2029":"\\u2029"};if(D[u])return D[u];if(u<" "){const D=u.charCodeAt(0).toString(16);return`\\x${`00${D}`.substring(D.length)}`}return u}function Eu(u,D){let e="";switch(u){case x.Char:e=void 0===D?`JSON5: invalid end of input at ${$}:${k}`:`JSON5: invalid character '${Fu(D)}' at ${$}:${k}`;break;case x.EOF:e=`JSON5: invalid end of input at ${$}:${k}`;break;case x.Identifier:k-=5,e=`JSON5: invalid identifier character at ${$}:${k}`}const t=new Au(e);return t.lineNumber=$,t.columnNumber=k,t}class Au extends SyntaxError{}var ou={},au=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),cu=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),su=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&au(D,u,e);return cu(D,u),D},lu=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(ou,"__esModule",{value:!0}),ou.isFileExists=ou.offlinePluginConversion=ou.executeCommand=ou.getNpmPath=ou.hasNpmPackInPaths=void 0;const Bu=r,du=lu(e),fu=su(u),_u=i,pu=l;ou.hasNpmPackInPaths=function(u,D){try{return require.resolve(u,{paths:[...D]}),!0}catch(u){return!1}},ou.getNpmPath=function(){const u=process.execPath;return fu.join(fu.dirname(u),_u.NPM_TOOL)},ou.executeCommand=function(u,D,e){0!==(0,Bu.spawnSync)(u,D,e).status&&(0,pu.logErrorAndExit)(`Error: ${u} ${D} execute failed.See above for details.`)},ou.offlinePluginConversion=function(u,D){return D.startsWith("file:")||D.endsWith(".tgz")?fu.resolve(u,_u.HVIGOR,D.replace("file:","")):D},ou.isFileExists=function(u){return du.default.existsSync(u)&&du.default.statSync(u).isFile()};var Ou=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),hu=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),Pu=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&Ou(D,u,e);return hu(D,u),D},vu=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(P,"__esModule",{value:!0});var gu=P.initProjectWorkSpace=void 0;const mu=Pu(e),Ru=vu(D),yu=Pu(u),Iu=v,Nu=i,bu=g,Su=l,wu=ou;let Hu,xu,Mu;function Tu(u,D,e){return void 0!==e.dependencies&&(0,wu.offlinePluginConversion)(Nu.HVIGOR_PROJECT_ROOT_DIR,D.dependencies[u])===yu.normalize(e.dependencies[u])}function Vu(){const u=yu.join(Mu,Nu.WORK_SPACE);if((0,Su.logInfoPrintConsole)("Hvigor cleaning..."),!mu.existsSync(u))return;const D=mu.readdirSync(u);if(!D||0===D.length)return;const e=yu.resolve(Mu,"node_modules","@ohos","hvigor","bin","hvigor.js");mu.existsSync(e)&&(0,wu.executeCommand)(process.argv[0],[e,"--stop-daemon"],{});try{D.forEach((D=>{mu.rmSync(yu.resolve(u,D),{recursive:!0})}))}catch(D){(0,Su.logErrorAndExit)(`The hvigor build tool cannot be installed. Please manually clear the workspace directory and synchronize the project again.\n\n Workspace Path: ${u}.`)}}gu=P.initProjectWorkSpace=function(){if(Hu=function(){const u=yu.resolve(Nu.HVIGOR_PROJECT_WRAPPER_HOME,Nu.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME);mu.existsSync(u)||(0,Su.logErrorAndExit)(`Error: Hvigor config file ${u} does not exist.`);return(0,bu.parseJsonFile)(u)}(),Mu=function(u){let D;D=function(u){let D=u.hvigorVersion;if(D.startsWith("file:")||D.endsWith(".tgz"))return!1;const e=u.dependencies,t=Object.getOwnPropertyNames(e);for(const u of t){const D=e[u];if(D.startsWith("file:")||D.endsWith(".tgz"))return!1}if(1===t.length&&"@ohos/hvigor-ohos-plugin"===t[0])return D>"2.5.0";return!1}(u)?function(u){let D=`${Nu.HVIGOR_ENGINE_PACKAGE_NAME}@${u.hvigorVersion}`;const e=u.dependencies;if(e){Object.getOwnPropertyNames(e).sort().forEach((u=>{D+=`,${u}@${e[u]}`}))}return(0,Iu.hash)(D)}(u):(0,Iu.hash)(process.cwd());return yu.resolve(Ru.default.homedir(),".hvigor","project_caches",D)}(Hu),xu=function(){const u=yu.resolve(Mu,Nu.WORK_SPACE,Nu.DEFAULT_PACKAGE_JSON);return mu.existsSync(u)?(0,bu.parseJsonFile)(u):{dependencies:{}}}(),!(0,wu.hasNpmPackInPaths)(Nu.HVIGOR_ENGINE_PACKAGE_NAME,[yu.join(Mu,Nu.WORK_SPACE)])||(0,wu.offlinePluginConversion)(Nu.HVIGOR_PROJECT_ROOT_DIR,Hu.hvigorVersion)!==xu.dependencies[Nu.HVIGOR_ENGINE_PACKAGE_NAME]||!function(){function u(u){const D=null==u?void 0:u.dependencies;return void 0===D?0:Object.getOwnPropertyNames(D).length}const D=u(Hu),e=u(xu);if(D+1!==e)return!1;for(const u in null==Hu?void 0:Hu.dependencies)if(!(0,wu.hasNpmPackInPaths)(u,[yu.join(Mu,Nu.WORK_SPACE)])||!Tu(u,Hu,xu))return!1;return!0}()){Vu();try{!function(){(0,Su.logInfoPrintConsole)("Hvigor installing...");for(const u in Hu.dependencies)Hu.dependencies[u]&&(Hu.dependencies[u]=(0,wu.offlinePluginConversion)(Nu.HVIGOR_PROJECT_ROOT_DIR,Hu.dependencies[u]));const u={dependencies:{...Hu.dependencies}};u.dependencies[Nu.HVIGOR_ENGINE_PACKAGE_NAME]=(0,wu.offlinePluginConversion)(Nu.HVIGOR_PROJECT_ROOT_DIR,Hu.hvigorVersion);const D=yu.join(Mu,Nu.WORK_SPACE);try{mu.mkdirSync(D,{recursive:!0});const e=yu.resolve(D,Nu.DEFAULT_PACKAGE_JSON);mu.writeFileSync(e,JSON.stringify(u))}catch(u){(0,Su.logErrorAndExit)(u)}(function(){const u=["config","set","store-dir",Nu.HVIGOR_PNPM_STORE_PATH],D={cwd:yu.join(Mu,Nu.WORK_SPACE),stdio:["inherit","inherit","inherit"]};(0,wu.executeCommand)(Nu.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH,u,D)})(),function(){const u=["install"],D={cwd:yu.join(Mu,Nu.WORK_SPACE),stdio:["inherit","inherit","inherit"]};(0,wu.executeCommand)(Nu.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH,u,D)}(),(0,Su.logInfoPrintConsole)("Hvigor install success.")}()}catch(u){Vu()}}return Mu};var Gu={};!function(t){var C=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),F=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),E=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&C(D,u,e);return F(D,u),D},A=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(t,"__esModule",{value:!0}),t.executeInstallPnpm=t.isPnpmInstalled=t.environmentHandler=t.checkNpmConifg=t.PNPM_VERSION=void 0;const o=r,a=E(e),c=A(D),s=E(u),B=i,d=l,f=ou;t.PNPM_VERSION="7.30.0",t.checkNpmConifg=function(){const u=s.resolve(B.HVIGOR_PROJECT_ROOT_DIR,".npmrc"),D=s.resolve(c.default.homedir(),".npmrc");if((0,f.isFileExists)(u)||(0,f.isFileExists)(D))return;const e=(0,f.getNpmPath)(),t=(0,o.spawnSync)(e,["config","get","prefix"],{cwd:B.HVIGOR_PROJECT_ROOT_DIR});if(0!==t.status||!t.stdout)return void(0,d.logErrorAndExit)("Error: The hvigor depends on the npmrc file. Configure the npmrc file first.");const r=s.resolve(`${t.stdout}`.replace(/[\r\n]/gi,""),".npmrc");(0,f.isFileExists)(r)||(0,d.logErrorAndExit)("Error: The hvigor depends on the npmrc file. Configure the npmrc file first.")},t.environmentHandler=function(){process.env["npm_config_update-notifier"]="false"},t.isPnpmInstalled=function(){return!!a.existsSync(B.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH)&&(0,f.hasNpmPackInPaths)("pnpm",[B.HVIGOR_WRAPPER_TOOLS_HOME])},t.executeInstallPnpm=function(){(0,d.logInfoPrintConsole)(`Installing pnpm@${t.PNPM_VERSION}...`);const u=(0,f.getNpmPath)();!function(){const u=s.resolve(B.HVIGOR_WRAPPER_TOOLS_HOME,B.DEFAULT_PACKAGE_JSON);try{a.existsSync(B.HVIGOR_WRAPPER_TOOLS_HOME)||a.mkdirSync(B.HVIGOR_WRAPPER_TOOLS_HOME,{recursive:!0});const D={dependencies:{}};D.dependencies[B.PNPM]=t.PNPM_VERSION,a.writeFileSync(u,JSON.stringify(D))}catch(D){(0,d.logErrorAndExit)(`Error: EPERM: operation not permitted,create ${u} failed.`)}}(),(0,f.executeCommand)(u,["install","pnpm"],{cwd:B.HVIGOR_WRAPPER_TOOLS_HOME,stdio:["inherit","inherit","inherit"],env:process.env}),(0,d.logInfoPrintConsole)("Pnpm install success.")}}(Gu),function(){Gu.checkNpmConifg(),Gu.environmentHandler(),Gu.isPnpmInstalled()||Gu.executeInstallPnpm();const D=gu();_(u.join(D,i.WORK_SPACE))}(); \ No newline at end of file diff --git a/Distributed/DistributedNewsClient/oh-package.json5 b/Distributed/DistributedNewsClient/oh-package.json5 index b041e9578f047a484a5b6014a3a508cb5933a4ef..23b306fbc49f3250007969d4e85ee9b4b62c91a1 100644 --- a/Distributed/DistributedNewsClient/oh-package.json5 +++ b/Distributed/DistributedNewsClient/oh-package.json5 @@ -8,5 +8,6 @@ "description": "Please describe the basic information.", "main": "", "version": "1.0.0", + "dynamicDependencies": {}, "dependencies": {} } diff --git a/ETSUI/AnimateRefresh/README.md b/ETSUI/AnimateRefresh/README.md index ee56091d9282ccad717a61797188faab67b41ffc..a5067d71d8c191b4acd86189396155145a99d648 100644 --- a/ETSUI/AnimateRefresh/README.md +++ b/ETSUI/AnimateRefresh/README.md @@ -2,7 +2,7 @@ ## 介绍 -基于ArkTS的声明式开发范式,使用OpenHarmony属性动画实现自定义下拉刷新动画组件的示例。本篇Codelab主要介绍组件动画animation属性设置。自定义属性动画头部组件结合下拉刷新场景,丰富下拉刷新样式,通过属性动画中的动画时长、动画速率和播放模式等相关属性的设置,效果如图所示: +本篇Codelab主要介绍组件动画animation属性设置。当组件的某些通用属性变化时,可以通过属性动画实现渐变效果,提升用户体验。效果如图所示: ![](figures/AnimateRefresh.gif) @@ -17,13 +17,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -46,7 +46,7 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 @@ -55,16 +55,20 @@ │ │ │ ├──CommonConstants.ets // 公共常量类 │ │ │ └──RefreshConstants.ets // 下拉刷新常量类 │ │ └──utils -│ │ └──DimensionUtil.ets // 屏幕适配工具类 +│ │ ├──DimensionUtil.ets // 屏幕适配工具类 +│ │ └──GlobalContext.ets // 全局上下文工具类 │ ├──entryability │ │ └──EntryAbility.ts // 程序入口类 │ ├──pages │ │ ├──FileManagerIndex.ets // 文件管理Tab页 │ │ └──TabIndex.ets // Tab管理页 -│ └──view -│ ├──RefreshAnimHeader.ets // 动画刷新组件 -│ ├──RefreshComponent.ets // 下拉刷新组件 -│ └──RefreshDefaultHeader.ets // 默认刷新组件 +│ ├──view +│ │ ├──RefreshAnimHeader.ets // 动画刷新组件 +│ │ ├──RefreshComponent.ets // 下拉刷新组件 +│ │ └──RefreshDefaultHeader.ets // 默认刷新组件 +│ └──viewmodel +│ ├──AnimationModel.ets // 动画封装模型 +│ └──CardModel.ets // 页签封装模型 └──entry/src/main/resources // 资源文件目录 ``` @@ -73,9 +77,12 @@ 自定义下拉刷新通过自定义List组件RefreshComponent实现。在List容器中添加自定义刷新头部组件和其它的需要刷新部件,RefreshComponent提供了头部样式设置,刷新部件样式设置和刷新回调方法设置。 ```typescript +// FileManagerIndex.ets RefreshComponent({ headerStyle: RefreshHeaderStyle.CLOUD, // 头部样式设置 itemLayout: () => this.ContentBody(), // 刷新部件样式 + displayHeight: ( + px2vp(this.deviceDisplay.height) - DimensionUtil.getVp($r('app.float.file_index_title_height'))), onRefresh: () => { // 刷新回调方法 ...... } @@ -87,6 +94,7 @@ RefreshComponent({ 本Codelab提供了DEFAULT默认刷新样式和CLOUD云朵动画刷新样式设置,在RefreshComponent组件初始化时,判断当前刷新样式进行渲染。 ```typescript + // RefreshComponent.ets if (this.headerStyle === RefreshHeaderStyle.DEFAULT) { RefreshDefaultHeader().height(RefreshConstants.REFRESH_HEADER_HEIGHT) } else if (this.headerStyle === RefreshHeaderStyle.CLOUD) { @@ -99,6 +107,7 @@ RefreshComponent({ 刷新部件样式itemLayout为嵌入RefreshComponent组件中的元素,通过@BuilderParam装饰符定义,可根据具体业务需求,当前为默认的Image组件样式。 ```typescript + // FileManagerIndex.ets @Builder ContentBody() { Image($r('app.media.bg_content')) .width(CommonConstants.FULL_LENGTH) @@ -114,7 +123,9 @@ RefreshComponent({ 1.设置RefreshComponent刷新组件state状态的更新。 ```typescript + // RefreshComponent.ets @Consume(RefreshConstants.REFRESH_STATE_TAG) @Watch('onStateChanged') state: RefreshState; + @BuilderParam itemLayout: () => void; private onStateChanged() { switch (this.state) { @@ -131,6 +142,7 @@ RefreshComponent({ 2.监听RefreshComponent组件的触摸事件,当手指松开且List组件下拉距离超出可刷新距离时,修改当前状态为REFRESHING,回调“onStateChanged”方法触发外部传入的onRefresh事件。 ```typescript + // RefreshComponent.ets case TouchType.Move: if (this.state === RefreshState.DRAGGING && this.listController.currentOffset().yOffset <= -RefreshConstants.REFRESH_EFFECTIVE_HEIGHT) { @@ -148,6 +160,7 @@ RefreshComponent({ 3.本Codelab中onRefresh事件没有做相关刷新动作,只做了模拟延时操作,开发者可以自行加入真实网络加载动作。 ```typescript + // RefreshComponent.ets onRefresh: () => { setTimeout(() => { this.state = RefreshState.COMPLETE; @@ -162,7 +175,8 @@ RefreshComponent({ 1. 每个Image通过iconItem参数分别设置各自的x轴偏移量和延时播放的属性动画效果。 ```typescript - @Builder AttrAnimIcons(iconItem) { + // RefreshAnimHeader.ets + @Builder AttrAnimIcons(iconItem: ClassifyModel) { Image(iconItem.imgRes) .width(px2vp(DimensionUtil.adaptDimension(this.iconWidth))) .position({ x: iconItem.posX }) @@ -173,7 +187,7 @@ RefreshComponent({ delay: iconItem.delay, curve: Curve.Linear, playMode: PlayMode.Alternate, - iterations: CommonConstants.REFRESH_HEADER_ITEM_ANIM_ITERATIONS, + iterations: CommonConstants.REFRESH_HEADER_ITEM_ANIM_ITERATIONS }) } ``` @@ -181,7 +195,9 @@ RefreshComponent({ 2. 监听RefreshComponent刷新组件state状态的变化,当前状态为REFRESHING状态时,启动动画效果。 ```typescript + // RefreshAnimHeader.ets @Consume(RefreshConstants.REFRESH_STATE_TAG) @Watch('onStateCheck') state: RefreshState; + @State iconWidth: number = CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH; private onStateCheck() { if (this.state === RefreshState.REFRESHING) { diff --git a/ETSUI/AnimateRefresh/entry/src/main/ets/common/constants/CommonConstants.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/common/constants/CommonConstants.ets index 15d40c8f6989a2902f4e7616c48d894390718eb8..c879ab511e2939b6d27d9f0dd8b4e5d708770d7e 100644 --- a/ETSUI/AnimateRefresh/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/common/constants/CommonConstants.ets @@ -16,6 +16,12 @@ /** * constant about common feature */ +import display from '@ohos.display'; +import ClassifyModel from '../../viewmodel/AnimationModel'; +import CardModel from '../../viewmodel/CardModel'; +import { GlobalContext } from '../utils/GlobalContext'; + +let deviceDisplay: display.Display = GlobalContext.getContext().getObject('display') as display.Display; export default class CommonConstants { /** @@ -56,32 +62,12 @@ export default class CommonConstants { /** * refresh header item feature */ - static readonly REFRESH_HEADER_FEATURE = [ - { - imgRes: $r('app.media.ic_loading_game'), - posX: (px2vp(globalThis.display.width) / 2 - CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH / 2) - 100, - delay: 400 - }, - { - imgRes: $r('app.media.ic_loading_heart'), - posX: (px2vp(globalThis.display.width) / 2 - CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH / 2) - 50, - delay: 800 - }, - { - imgRes: $r('app.media.ic_loading_louder'), - posX: px2vp(globalThis.display.width) / 2 - CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH / 2, - delay: 1200 - }, - { - imgRes: $r('app.media.ic_loading_bag'), - posX: (px2vp(globalThis.display.width) / 2 - CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH / 2) + 50, - delay: 1600 - }, - { - imgRes: $r('app.media.ic_loading_file'), - posX: (px2vp(globalThis.display.width) / 2 - CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH / 2) + 100, - delay: 2000 - } + static readonly REFRESH_HEADER_FEATURE: ClassifyModel[] = [ + new ClassifyModel($r('app.media.ic_loading_game'), (px2vp(deviceDisplay.width) / 2 - CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH / 2) - 100, 400), + new ClassifyModel($r('app.media.ic_loading_heart'), (px2vp(deviceDisplay.width) / 2 - CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH / 2) - 50, 800), + new ClassifyModel($r('app.media.ic_loading_louder'), (px2vp(deviceDisplay.width) / 2 - CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH / 2) , 1200), + new ClassifyModel($r('app.media.ic_loading_bag'), (px2vp(deviceDisplay.width) / 2 - CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH / 2) + 50, 1600), + new ClassifyModel($r('app.media.ic_loading_file'), (px2vp(deviceDisplay.width) / 2 - CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH / 2) + 100, 2000), ]; /** @@ -98,30 +84,10 @@ export default class CommonConstants { * index tab item feature */ static readonly INDEX_TAB = [ - { - selectedIcon: $r('app.media.ic_tab_main_select'), - defaultIcon: $r('app.media.ic_tab_main_default'), - content: '首页' - }, - { - selectedIcon: $r('app.media.ic_tab_file_select'), - defaultIcon: $r('app.media.ic_tab_file_default'), - content: '文件' - }, - { - selectedIcon: $r('app.media.ic_tab_cloud_select'), - defaultIcon: $r('app.media.ic_tab_cloud_default'), - content: '云村' - }, - { - selectedIcon: $r('app.media.ic_tab_copy_select'), - defaultIcon: $r('app.media.ic_tab_copy_default'), - content: '备份' - }, - { - selectedIcon: $r('app.media.ic_tab_mine_select'), - defaultIcon: $r('app.media.ic_tab_mine_default'), - content: '我的' - } + new CardModel($r('app.media.ic_tab_main_select'),$r('app.media.ic_tab_main_default'),'首页'), + new CardModel($r('app.media.ic_tab_file_select'),$r('app.media.ic_tab_file_default'),'文件'), + new CardModel($r('app.media.ic_tab_cloud_select'),$r('app.media.ic_tab_cloud_default'),'云村'), + new CardModel($r('app.media.ic_tab_copy_select'),$r('app.media.ic_tab_copy_default'),'备份'), + new CardModel($r('app.media.ic_tab_mine_select'),$r('app.media.ic_tab_mine_default'),'我的') ]; } \ No newline at end of file diff --git a/ETSUI/AnimateRefresh/entry/src/main/ets/common/constants/RefreshConstants.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/common/constants/RefreshConstants.ets index 2644a8e8caf70ff6bc7960abf0f082e574a44884..10687cac5a8ed645f53455e6744b21404bac9a2d 100644 --- a/ETSUI/AnimateRefresh/entry/src/main/ets/common/constants/RefreshConstants.ets +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/common/constants/RefreshConstants.ets @@ -47,12 +47,12 @@ export class RefreshConstants { /** * refresh state enum */ -export const RefreshState = { - IDLE: 0, - DRAGGING: 1, - DRAGGING_REFRESHABLE: 2, - REFRESHING: 3, - COMPLETE: 4 +export enum RefreshState { + IDLE = 0, + DRAGGING = 1, + DRAGGING_REFRESHABLE = 2, + REFRESHING = 3, + COMPLETE = 4 } /** diff --git a/ETSUI/AnimateRefresh/entry/src/main/ets/common/utils/DimensionUtil.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/common/utils/DimensionUtil.ets index e5d9c5b0eda72d7a78e26bc059b807c81808bf10..f51067734bdb50c4613055964675fa10148e19b6 100644 --- a/ETSUI/AnimateRefresh/entry/src/main/ets/common/utils/DimensionUtil.ets +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/common/utils/DimensionUtil.ets @@ -12,6 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import display from '@ohos.display'; +import { GlobalContext } from './GlobalContext'; let context = getContext(this); const DESIGN_WIDTH = 360; @@ -22,7 +24,7 @@ const DESIGN_HEIGHT = 780; */ export default class DimensionUtil { static adaptDimension(value: number): number { - let deviceDisplay = globalThis.display; + let deviceDisplay: display.Display = GlobalContext.getContext().getObject('display') as display.Display; let widthScale = deviceDisplay.width / DESIGN_WIDTH; let virtualHeight = widthScale * DESIGN_HEIGHT; let designDim = Math.sqrt(DESIGN_WIDTH * DESIGN_WIDTH + DESIGN_HEIGHT * DESIGN_HEIGHT); @@ -35,7 +37,7 @@ export default class DimensionUtil { */ static getPx(value: Resource): number { let beforeVp = context.resourceManager.getNumber(value.id); - return this.adaptDimension(beforeVp); + return DimensionUtil.adaptDimension(beforeVp); } /** @@ -43,7 +45,7 @@ export default class DimensionUtil { */ static getVp(value: Resource): number { let beforeVp = context.resourceManager.getNumber(value.id); - return px2vp(this.adaptDimension(beforeVp)); + return px2vp(DimensionUtil.adaptDimension(beforeVp)); } /** @@ -51,6 +53,6 @@ export default class DimensionUtil { */ static getFp(value: Resource): number { let beforeFp = context.resourceManager.getNumber(value.id); - return px2fp(this.adaptDimension(beforeFp)); + return px2fp(DimensionUtil.adaptDimension(beforeFp)); } } \ No newline at end of file diff --git a/ETSUI/AnimateRefresh/entry/src/main/ets/common/utils/GlobalContext.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/common/utils/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..165acc447b53a0191d85662c63fbfa7258de4db0 --- /dev/null +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/common/utils/GlobalContext.ets @@ -0,0 +1,36 @@ + +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { } + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/ETSUI/AnimateRefresh/entry/src/main/ets/entryAbility/EntryAbility.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/entryAbility/EntryAbility.ets index 703ea77a734b014e3d59473d20e25e74314b8545..694de84505377c60b05c19948baddd08affafb84 100644 --- a/ETSUI/AnimateRefresh/entry/src/main/ets/entryAbility/EntryAbility.ets +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/entryAbility/EntryAbility.ets @@ -15,15 +15,17 @@ import window from '@ohos.window'; import display from '@ohos.display'; +import Want from '@ohos.app.ability.Want'; import Ability from '@ohos.app.ability.UIAbility'; +import { GlobalContext } from '../common/utils/GlobalContext'; export default class EntryAbility extends Ability { - onCreate(want) { - globalThis.abilityWant = want; + onCreate(want: Want) { + GlobalContext.getContext().setObject('abilityWant', want); } async onWindowStageCreate(windowStage: window.WindowStage) { - globalThis.display = await display.getDefaultDisplaySync(); + GlobalContext.getContext().setObject('display', await display.getDefaultDisplaySync()); windowStage.loadContent('pages/TabIndex'); } }; diff --git a/ETSUI/AnimateRefresh/entry/src/main/ets/pages/FileManagerIndex.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/pages/FileManagerIndex.ets index 2102364594ec0f716f0181b0240af3c241976a08..c43155237dfe3a8aac05adc1f98879069526d262 100644 --- a/ETSUI/AnimateRefresh/entry/src/main/ets/pages/FileManagerIndex.ets +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/pages/FileManagerIndex.ets @@ -13,10 +13,12 @@ * limitations under the License. */ +import display from '@ohos.display'; import RefreshComponent from '../view/RefreshComponent'; import { RefreshHeaderStyle, RefreshState, RefreshConstants } from '../common/constants/RefreshConstants'; import CommonConstants from '../common/constants/CommonConstants'; import DimensionUtil from '../common/utils/DimensionUtil'; +import { GlobalContext } from '../common/utils/GlobalContext'; /** * File Management Entry. @@ -24,6 +26,7 @@ import DimensionUtil from '../common/utils/DimensionUtil'; @Component export default struct FileManagerIndex { @Provide(RefreshConstants.REFRESH_STATE_TAG) state: number = RefreshState.REFRESHING; + private deviceDisplay: display.Display = GlobalContext.getContext().getObject('display') as display.Display; @Builder ContentBody() { Image($r('app.media.bg_content')) @@ -44,9 +47,9 @@ export default struct FileManagerIndex { .zIndex(CommonConstants.FILE_MANAGER_Z_INDEX) RefreshComponent({ headerStyle: RefreshHeaderStyle.CLOUD, - itemLayout: () => this.ContentBody(), + itemLayout: (): void => this.ContentBody(), displayHeight: ( - px2vp(globalThis.display.height) - DimensionUtil.getVp($r('app.float.file_index_title_height'))), + px2vp(this.deviceDisplay.height) - DimensionUtil.getVp($r('app.float.file_index_title_height'))), onRefresh: () => { setTimeout(() => { this.state = RefreshState.COMPLETE; diff --git a/ETSUI/AnimateRefresh/entry/src/main/ets/pages/TabIndex.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/pages/TabIndex.ets index 004684f89e70745a6c3e280c92413ee35f944858..05db1c08862c4f60af73552def3362b6a035182b 100644 --- a/ETSUI/AnimateRefresh/entry/src/main/ets/pages/TabIndex.ets +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/pages/TabIndex.ets @@ -16,6 +16,7 @@ import FileManagerIndex from './FileManagerIndex'; import CommonConstants from '../common/constants/CommonConstants'; import DimensionUtil from '../common/utils/DimensionUtil'; +import CardModel from '../viewmodel/CardModel'; /** * Navigation path on the home page. @@ -25,7 +26,7 @@ import DimensionUtil from '../common/utils/DimensionUtil'; struct TabIndex { @State currentPage: number = CommonConstants.INDEX_DEFAULT_SELECT; - @Builder TabBuilder(item, index) { + @Builder TabBuilder(item: CardModel, index: number | undefined) { Column() { Image(this.currentPage === index ? item.selectedIcon : item.defaultIcon) .width(DimensionUtil.getVp($r('app.float.index_tab_icon_size'))) @@ -46,14 +47,14 @@ struct TabIndex { build() { Tabs({ barPosition: BarPosition.End, index: this.currentPage }) { - ForEach(CommonConstants.INDEX_TAB, (item, index) => { + ForEach(CommonConstants.INDEX_TAB, (item: CardModel, index: number | undefined) => { TabContent() { if (index === CommonConstants.INDEX_DEFAULT_SELECT) { FileManagerIndex() } } .tabBar(this.TabBuilder(item, index)) - }, item => JSON.stringify(item)) + }, (item: CardModel) => JSON.stringify(item)) } .width(CommonConstants.FULL_LENGTH) .height(CommonConstants.FULL_LENGTH) diff --git a/ETSUI/AnimateRefresh/entry/src/main/ets/view/RefreshAnimHeader.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/view/RefreshAnimHeader.ets index a3a4bdee3217a34dfa22b742c2d022b277b4acbc..7f3a2a574bdc65961e67e7a3acecd02787ae155c 100644 --- a/ETSUI/AnimateRefresh/entry/src/main/ets/view/RefreshAnimHeader.ets +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/view/RefreshAnimHeader.ets @@ -16,6 +16,7 @@ import { RefreshState, RefreshConstants } from '../common/constants/RefreshConstants'; import CommonConstants from '../common/constants/CommonConstants'; import DimensionUtil from '../common/utils/DimensionUtil'; +import ClassifyModel from '../viewmodel/AnimationModel'; @Component export default struct RefreshAnimHeader { @@ -30,7 +31,7 @@ export default struct RefreshAnimHeader { } } - @Builder AttrAnimIcons(iconItem) { + @Builder AttrAnimIcons(iconItem: ClassifyModel) { Image(iconItem.imgRes) .width(px2vp(DimensionUtil.adaptDimension(this.iconWidth))) .position({ x: iconItem.posX }) @@ -41,16 +42,16 @@ export default struct RefreshAnimHeader { delay: iconItem.delay, curve: Curve.Linear, playMode: PlayMode.Alternate, - iterations: CommonConstants.REFRESH_HEADER_ITEM_ANIM_ITERATIONS, + iterations: CommonConstants.REFRESH_HEADER_ITEM_ANIM_ITERATIONS }) } build() { Row() { if (this.state !== RefreshState.IDLE) { // stop animation when idle state. - ForEach(CommonConstants.REFRESH_HEADER_FEATURE, (iconItem) => { + ForEach(CommonConstants.REFRESH_HEADER_FEATURE, (iconItem: ClassifyModel) => { this.AttrAnimIcons(iconItem) - }, item => JSON.stringify(item)) + }, (item: ClassifyModel) => JSON.stringify(item)) } } .width(CommonConstants.FULL_LENGTH) diff --git a/ETSUI/AnimateRefresh/entry/src/main/ets/view/RefreshComponent.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/view/RefreshComponent.ets index dcf66f523b469b1970a879704a3d6a839b46c8ae..a542f372dc8236c573bd02f0b3140389301ed507 100644 --- a/ETSUI/AnimateRefresh/entry/src/main/ets/view/RefreshComponent.ets +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/view/RefreshComponent.ets @@ -21,9 +21,9 @@ import { RefreshConstants, RefreshState, RefreshHeaderStyle } from '../common/co @Component export default struct RefreshComponent { private headerStyle: RefreshHeaderStyle = RefreshHeaderStyle.DEFAULT; - private displayHeight: number; + private displayHeight: number = 0; private listController: Scroller = new Scroller(); - private onRefresh: () => void; + private onRefresh?: () => void; @State headerOffset: number = 0; @Consume(RefreshConstants.REFRESH_STATE_TAG) @Watch('onStateChanged') state: number; @BuilderParam itemLayout: () => void; @@ -31,7 +31,7 @@ export default struct RefreshComponent { private onStateChanged() { switch (this.state) { case RefreshState.REFRESHING: - if (this.onRefresh !== null) { + if (this.onRefresh !== undefined) { this.onRefresh(); } break; @@ -84,7 +84,10 @@ export default struct RefreshComponent { } } }) - .onTouch((event) => { + .onTouch((event?: TouchEvent) => { + if (!event) { + return; + } switch (event.type) { case TouchType.Down: if (this.state === RefreshState.IDLE) { diff --git a/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/TaskListItemModel.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/viewmodel/AnimationModel.ets similarity index 55% rename from ETSUI/TargetManagement/entry/src/main/ets/viewmodel/TaskListItemModel.ets rename to ETSUI/AnimateRefresh/entry/src/main/ets/viewmodel/AnimationModel.ets index 6027799c70a1c5d2b24457dbf8044e5f586ad9e0..bcb2f1d2dd8537b2fd2981629066971a1ed48248 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/TaskListItemModel.ets +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/viewmodel/AnimationModel.ets @@ -13,20 +13,17 @@ * limitations under the License. */ -import getCurrentTime from '../common/utils/DateUtil'; -import DataModel from '../viewmodel/DataModel'; - /** - * Save the adjustment progress. - * - * @param progress progress value saved. + * Animation model. */ -export function changeProgress(progress: number) { - this.latestProgress = progress; - this.updateDate = getCurrentTime(); - let result = DataModel.updateProgress(this.index, this.latestProgress, this.updateDate); - if (result) { - this.overAllProgressChanged = !this.overAllProgressChanged; +export default class ClassifyModel { + imgRes: Resource; + posX: number; + delay: number; + + constructor(imgRes: Resource, posX: number, delay: number) { + this.imgRes = imgRes; + this.posX = posX; + this.delay = delay; } - this.isExpanded = false; } \ No newline at end of file diff --git a/ETSUI/AnimateRefresh/entry/src/main/ets/viewmodel/CardModel.ets b/ETSUI/AnimateRefresh/entry/src/main/ets/viewmodel/CardModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..45cb7761555e3ad049f355f5cb2ffee057f354c4 --- /dev/null +++ b/ETSUI/AnimateRefresh/entry/src/main/ets/viewmodel/CardModel.ets @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Card model. + */ +export default class CardModel { + selectedIcon: Resource; + defaultIcon: Resource; + content: string; + + constructor(selectedIcon: Resource, defaultIcon: Resource, content: string) { + this.selectedIcon = selectedIcon; + this.defaultIcon = defaultIcon; + this.content = content; + } +} \ No newline at end of file diff --git a/ETSUI/Animation/README.md b/ETSUI/Animation/README.md index 263108b9dd0a59d4ec0923475eb309d6142bf17b..b683e2864a5021fe8e1a3a01066ebb95a24085cf 100644 --- a/ETSUI/Animation/README.md +++ b/ETSUI/Animation/README.md @@ -8,21 +8,23 @@ ### 相关概念 -- [显式动画](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-explicit-animation.md):提供全局animateTo显式动画接口来指定有闭包代码导致的状态变化插入过渡动画效果。 -- [属性动画](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-animatorproperty.md):组件的通用属性发生变化时,可以创建属性动画进行渐变,提升用户体验。 -- [Slider](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-slider.md):滑动条组件,用来快速调节设置值,如音量、亮度等。 +- [显式动画](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-explicit-animation.md):提供全局animateTo显式动画接口来指定有闭包代码导致的状态变化插入过渡动画效果。 + +- [属性动画](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-animatorproperty.md):组件的通用属性发生变化时,可以创建属性动画进行渐变,提升用户体验。 + +- [Slider](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-slider.md):滑动条组件,用来快速调节设置值,如音量、亮度等。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -44,14 +46,11 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ | ├──IconItem.ets // 图标类 -│ │ │ └──Point.ets // 图标坐标类 │ │ └──constants │ │ └──Const.ets // 常量类 │ ├──entryability @@ -63,8 +62,9 @@ │ │ ├──CountController.ets // 图标数量控制组件 │ │ └──IconAnimation.ets // 图标属性动画组件 │ └──viewmodel -│ ├──AxisModel.ets // 坐标计算数据模型 -│ └──IconsModel.ets // 图标数据模型 +│ ├──IconItem.ets // 图标类 +│ ├──IconsModel.ets // 图标数据模型 +│ └──Point.ets // 图标坐标类 └──entry/src/main/resources // 资源文件 ``` @@ -75,27 +75,25 @@ 其中CountController通过Slider滑动控制quantity(动效图标数量);AnimationWidgets根据quantity展示相应数量的图标,点击组件按钮后通过在animateTo的event闭包函数中改变mainFlag状态,跟mainFlag相关的样式属性的变化都会产生动画效果,代码如下所示: ```typescript +// Index.ets @Entry @Component struct Index { @State quantity: number = Common.IMAGES_MIN; - @State axis: AxisModel = new AxisModel(Common.OFFSET_RADIUS, this.quantity); - @State iconModel: IconsModel = new IconsModel(this.quantity); + @Provide iconModel: IconsModel = new IconsModel(this.quantity, Common.OFFSET_RADIUS); build() { Column() { // 动画组件 AnimationWidgets({ - quantity: $quantity, - axis: $axis, - iconModel: $iconModel + quantity: $quantity }) // 图标数量控制组件 CountController({ quantity: $quantity }) } - ... +... } } ``` @@ -103,6 +101,7 @@ struct Index { CountController组件通过Slilder滑动控制动效图标的数量,最少3个图标,最多6个图标,示例代码如下所示: ```typescript +// CountController.ets @Component export struct CountController { @Link quantity: number; @@ -148,21 +147,26 @@ export struct CountController { 在animationTo的回调中修改mainFlag状态,所有跟mainFlag状态相关的属性变化都会产生过渡动画效果。代码如下所示: ```typescript +// AnimationWidgets.ets +import { IconsModel } from '../viewmodel/IconsModel'; +import { IconAnimation } from './IconAnimation'; +import Common from '../common/constants/Const'; +import IconItem from '../viewmodel/IconItem'; + +@Component export struct AnimationWidgets { @State mainFlag: boolean = false; @Link @Watch('onQuantityChange') quantity: number; - @Link axis: AxisModel; - @Link iconModel: IconsModel; + @Consume iconModel: IconsModel; - onQuantityChange() { // 监听图标数量的变化,并修改图标数据以及对应的坐标位置 + onQuantityChange() { this.iconModel.addImage(this.quantity); - this.axis.addPoints(this.quantity); } aboutToAppear() { this.onQuantityChange(); } - + animate() { animateTo( { @@ -173,45 +177,58 @@ export struct AnimationWidgets { curve: Curve.Smooth, playMode: PlayMode.Normal }, () => { - this.mainFlag = !this.mainFlag; - }) - } - + this.mainFlag = !this.mainFlag; + }) + } + build() { Stack() { Stack() { ForEach(this.iconModel.imagerArr, (item: IconItem) => { IconAnimation({ item: item, - point: this.axis.points[item.index], mainFlag: $mainFlag }) - }, item => JSON.stringify(item)) + }, (item: IconItem) => JSON.stringify(item.index)) } + .width(Common.DEFAULT_FULL_WIDTH) + .height(Common.DEFAULT_FULL_HEIGHT) .rotate({ x: 0, y: 0, z: 1, angle: this.mainFlag ? Common.ROTATE_ANGLE_360 : 0 }) - - ... - - Image( - this.mainFlag - ? $r("app.media.imgActive") - : $r("app.media.imgInit") - ) - .scale({ - x: this.mainFlag ? Common.INIT_SCALE : 1, - y: this.mainFlag ? Common.INIT_SCALE : 1 - }) - .onClick(() => { - this.iconModel.reset(); // 重置图标激活状态 - this.animate(); // 启动显式动画 - }) - ... + + Image( + this.mainFlag + ? $r("app.media.imgActive") + : $r("app.media.imgInit") + ) + .width($r('app.float.size_64')) + .height($r('app.float.size_64')) + .objectFit(ImageFit.Contain) + .scale({ + x: this.mainFlag ? Common.INIT_SCALE : 1, + y: this.mainFlag ? Common.INIT_SCALE : 1 + }) + .onClick(() => { + this.iconModel.reset(); + this.animate(); + }) + + Text($r('app.string.please_click_button')) + .fontSize($r('app.float.size_16')) + .opacity(Common.OPACITY_06) + .fontColor($r('app.color.fontGrayColor')) + .fontWeight(Common.FONT_WEIGHT_500) + .margin({ + top: $r('app.float.size_100') + }) } + .width(Common.DEFAULT_FULL_WIDTH) + .layoutWeight(1) + } } ``` @@ -225,10 +242,10 @@ export struct AnimationWidgets { 当组件由animation动画属性修饰时,如果自身属性发生变化会产生过渡动画效果。本示例中当点击小图标时会触发自身clicked状态的变化,所有跟clicked相关的属性变化(如translate、rotate、scale、opacity)都会被增加动画效果。代码如下所示: ```typescript +// IconAnimation.ets export struct IconAnimation { @Link mainFlag: boolean; - @State point: Point = new Point(0, 0); - @State item: IconItem = new IconItem(0, $r('app.media.badge1'), false); + @ObjectLink item: IconItem; build() { Image(this.item.image) @@ -236,9 +253,9 @@ export struct IconAnimation { .height(Common.ICON_HEIGHT) .objectFit(ImageFit.Contain) .translate( - this.mainFlag - ? { x: this.point.x, y: this.point.y } - : { x: 0, y: 0 } + this.mainFlag + ? { x: this.item.point.x, y: this.item.point.y } + : { x: 0, y: 0 } ) .rotate({ x: 0, @@ -247,7 +264,7 @@ export struct IconAnimation { angle: this.item.clicked ? Common.ROTATE_ANGLE_360 : 0 }) .scale( - this.item.clicked + this.item.clicked ? { x: Common.SCALE_RATIO, y: Common.SCALE_RATIO } : { x: 1, y: 1 } ) @@ -271,25 +288,58 @@ export struct IconAnimation { 根据图标数量计算图标位置代码如下所示: ```typescript +// IconsModel.ets +import Common from '../common/constants/Const'; +import IconItem from './IconItem'; +import Point from './Point'; + const TWO_PI: number = 2 * Math.PI; -export class AxisModel { +@Observed +export class IconsModel { + public imagerArr: Array = []; + private num: number = Common.IMAGES_MIN; private radius: number; - private num: number; - public points: Point[] = []; - constructor(radius: number, num: number) { + constructor(num: number, radius: number) { this.radius = radius; - this.addPoints(num); + this.addImage(num); } - addPoints(num: number) { - this.points = []; + public addImage(num: number) { this.num = num; + if (this.imagerArr.length == num) { + return; + } + if (this.imagerArr.length > num) { + this.imagerArr.splice(num, this.imagerArr.length - num); + } else { + for (let i = this.imagerArr.length; i < num; i++) { + const point = this.genPointByIndex(i); + this.imagerArr.push(new IconItem(i, Common.IMAGE_RESOURCE[i], false, point)); + } + } + + this.refreshPoint(num); + } + + public refreshPoint(num: number) { for (let i = 0; i < num; i++) { - let x = this.radius * Math.cos(TWO_PI * i / this.num); - let y = this.radius * Math.sin(TWO_PI * i / this.num); - this.points.push(new Point(x, y)); + this.imagerArr[i].point = this.genPointByIndex(i); + } + } + + public genPointByIndex(index: number): Point { + const x = this.radius * Math.cos(TWO_PI * index / this.num); + const y = this.radius * Math.sin(TWO_PI * index / this.num); + return new Point(x, y); + } + + public reset() { + for (let i = 0; i < this.num; i++) { + if (this.imagerArr[i].clicked) { + this.imagerArr[i].clicked = false; + } } } } diff --git a/ETSUI/Animation/entry/src/main/ets/view/AnimationWidgets.ets b/ETSUI/Animation/entry/src/main/ets/view/AnimationWidgets.ets index 2da7fb364cd66ee6f34e3c075f2d17099b696935..191551177e4d63a8146063d9f349e7b6b6ec5c5c 100644 --- a/ETSUI/Animation/entry/src/main/ets/view/AnimationWidgets.ets +++ b/ETSUI/Animation/entry/src/main/ets/view/AnimationWidgets.ets @@ -16,7 +16,7 @@ import { IconsModel } from '../viewmodel/IconsModel'; import { IconAnimation } from './IconAnimation'; import Common from '../common/constants/Const'; -import IconItem from '../common/bean/IconItem'; +import IconItem from '../viewmodel/IconItem'; @Component export struct AnimationWidgets { @@ -54,7 +54,7 @@ export struct AnimationWidgets { item: item, mainFlag: $mainFlag }) - }, item => JSON.stringify(item.index)) + }, (item: IconItem) => JSON.stringify(item.index)) } .width(Common.DEFAULT_FULL_WIDTH) .height(Common.DEFAULT_FULL_HEIGHT) diff --git a/ETSUI/Animation/entry/src/main/ets/view/IconAnimation.ets b/ETSUI/Animation/entry/src/main/ets/view/IconAnimation.ets index 2f13356d6d022029f5ac77d9e885872ea8cfb2c9..965936b8a3ff72583050592433264c775798e0a9 100644 --- a/ETSUI/Animation/entry/src/main/ets/view/IconAnimation.ets +++ b/ETSUI/Animation/entry/src/main/ets/view/IconAnimation.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import IconItem from '../common/bean/IconItem'; +import IconItem from '../viewmodel/IconItem'; import Common from '../common/constants/Const'; @Component diff --git a/ETSUI/Animation/entry/src/main/ets/common/bean/IconItem.ets b/ETSUI/Animation/entry/src/main/ets/viewmodel/IconItem.ets similarity index 100% rename from ETSUI/Animation/entry/src/main/ets/common/bean/IconItem.ets rename to ETSUI/Animation/entry/src/main/ets/viewmodel/IconItem.ets diff --git a/ETSUI/Animation/entry/src/main/ets/viewmodel/IconsModel.ets b/ETSUI/Animation/entry/src/main/ets/viewmodel/IconsModel.ets index 61f515ac926c365ebf6a4994c982516227b6fbc7..1421a1fe094968970eef1445c2148b829cd63ede 100644 --- a/ETSUI/Animation/entry/src/main/ets/viewmodel/IconsModel.ets +++ b/ETSUI/Animation/entry/src/main/ets/viewmodel/IconsModel.ets @@ -14,8 +14,8 @@ */ import Common from '../common/constants/Const'; -import IconItem from '../common/bean/IconItem'; -import Point from '../common/bean/Point'; +import IconItem from './IconItem'; +import Point from './Point'; const TWO_PI: number = 2 * Math.PI; @@ -25,12 +25,12 @@ export class IconsModel { private num: number = Common.IMAGES_MIN; private radius: number; - constructor(num: number, radius) { + constructor(num: number, radius: number) { this.radius = radius; this.addImage(num); } - public addImage(num) { + public addImage(num: number) { this.num = num; if (this.imagerArr.length == num) { return; @@ -47,7 +47,7 @@ export class IconsModel { this.refreshPoint(num); } - public refreshPoint(num) { + public refreshPoint(num: number) { for (let i = 0; i < num; i++) { this.imagerArr[i].point = this.genPointByIndex(i); } diff --git a/ETSUI/Animation/entry/src/main/ets/common/bean/Point.ets b/ETSUI/Animation/entry/src/main/ets/viewmodel/Point.ets similarity index 100% rename from ETSUI/Animation/entry/src/main/ets/common/bean/Point.ets rename to ETSUI/Animation/entry/src/main/ets/viewmodel/Point.ets diff --git a/ETSUI/Animation/hvigor/hvigor-config.json5 b/ETSUI/Animation/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/ETSUI/Animation/hvigor/hvigor-config.json5 +++ b/ETSUI/Animation/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/ETSUI/ArkTSComponents/README.md b/ETSUI/ArkTSComponents/README.md index 387af5393bbc6ffba38a9cbde102fee4739e2d9d..88f36eeab235fd0a08b792bab95c4142628d7456 100644 --- a/ETSUI/ArkTSComponents/README.md +++ b/ETSUI/ArkTSComponents/README.md @@ -2,7 +2,7 @@ ## 介绍 -OpenHarmony ArkUI提供了丰富多样的UI组件,您可以使用这些组件轻松地编写出更加丰富、漂亮的界面。在本篇Codelab中,您将通过一个简单的购物社交应用示例,学习如何使用常用的基础组件和容器组件。 +HarmonyOS ArkUI提供了丰富多样的UI组件,您可以使用这些组件轻松地编写出更加丰富、漂亮的界面。在本篇Codelab中,您将通过一个简单的购物社交应用示例,学习如何使用常用的基础组件和容器组件。 本示例主要包含:“登录”、“首页”、“我的”三个页面,效果图如下: @@ -26,13 +26,13 @@ OpenHarmony ArkUI提供了丰富多样的UI组件,您可以使用这些组件 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -55,13 +55,11 @@ OpenHarmony ArkUI提供了丰富多样的UI组件,您可以使用这些组件 ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在附件下载和gitee源码中提供下载方式。 ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ └──ItemData.ets // 列表数据实体类 │ │ └──constants │ │ └──CommonConstants.ets // 公共常量类 │ ├──entryability @@ -73,6 +71,7 @@ OpenHarmony ArkUI提供了丰富多样的UI组件,您可以使用这些组件 │ │ ├──Home.ets // 首页 │ │ └──Setting.ets // 设置页 │ └──viewmodel +│ ├──ItemData.ets // 列表数据实体类 │ └──MainViewModel.ets // 主界面视图Model └──entry/src/main/resources // 应用资源目录 ``` @@ -85,6 +84,7 @@ OpenHarmony ArkUI提供了丰富多样的UI组件,您可以使用这些组件 界面使用Column容器组件布局,由Image、Text、TextInput、Button、LoadingProgress等基础组件构成,主要代码如下: ```typescript +// LoginPage.ets @Entry @Component struct LoginPage { @@ -139,6 +139,7 @@ struct LoginPage { 当用户登录前,需要获取用户输入的帐号和密码才能执行登录逻辑。给TextInput设置onChange事件,在onChange事件里面实时获取用户输入的文本信息。 ```typescript +// LoginPage.ets TextInput({ placeholder: $r('app.string.account') }) .maxLength(CommonConstants.INPUT_ACCOUNT_LENGTH) .type(InputType.Number) @@ -153,6 +154,7 @@ TextInput({ placeholder: $r('app.string.account') }) 给登录按钮绑定onClick事件,调用login方法模拟登录。定义变量isShowProgress结合条件渲染if用来控制LoadingProgress的显示和隐藏。当用户点击按钮时设置isShowProgress为true,即显示LoadingProgress;使用定时器setTimeout设置isShowProgress 2秒后为false,即隐藏LoadingProgress,然后执行跳转到首页的逻辑。 ```typescript +// LoginPage.ets @Entry @Component struct LoginPage { @@ -213,6 +215,7 @@ struct LoginPage { 页面间的跳转可以使用router模块相关API来实现,使用前需要先导入该模块,然后使用router.replace\(\)方法实现页面跳转。 ```typescript +// LoginPage.ets import router from '@ohos.router'; login() { @@ -220,10 +223,10 @@ login() { ... } else { this.isShowProgress = true; - if (this.timeOutId === null) { + if (this.timeOutId === -1) { this.timeOutId = setTimeout(() => { this.isShowProgress = false; - this.timeOutId = null; + this.timeOutId = -1; router.replaceUrl({ url: 'pages/MainPage' }); }, CommonConstants.LOGIN_DELAY_TIME); } @@ -239,7 +242,7 @@ login() { ```typescript // ItemData.ets - export default class PageResourcce { +export default class PageResource { title: Resource; img?: Resource; others?: Resource; @@ -251,7 +254,7 @@ login() { } // MainViewModel.ets -import ItemData from '../common/bean/ItemData'; +import ItemData from './temData'; export class MainViewModel { ... getFirstGridData(): Array { @@ -272,6 +275,7 @@ export default new MainViewModel(); 从前面介绍章节的示意图可以看出,本示例由两个tab页组成,使用Tabs组件来实现,提取tabBar的公共样式,同时设置TabContent和Tabs的backgroundColor来实现底部tabBar栏背景色突出的效果。 ```typescript +// MainPage.ets Tabs({ barPosition: BarPosition.End, controller: this.tabsController @@ -285,7 +289,9 @@ Tabs({ $r('app.media.home_selected'), $r('app.media.home_normal'))) ... } +... .backgroundColor(Color.White) // 底部tabBar栏背景色 +... .onChange((index: number) => { this.currentIndex = index; }) @@ -301,18 +307,21 @@ Tabs({ 从上面效果如可以看出“首页”由三部分内容组成分别是轮播图、2\*4栅格图、4\*4栅格图。首先使用Swiper组件实现轮播图,无需设置图片大小。 ```typescript +// Home.ets Swiper(this.swiperController) { ForEach(mainViewModel.getSwiperImages(), (img: Resource) => { Image(img).borderRadius($r('app.float.home_swiper_borderRadius')) - }, img => img.id) + }, (img: Resource) => JSON.stringify(img.id)) } ... .autoPlay(true) +... ``` 然后使用Grid组件实现2\*4栅格图,代码如下 ```typescript +// Home.ets Grid() { ForEach(mainViewModel.getFirstGridData(), (item: ItemData) => { GridItem() { @@ -325,7 +334,7 @@ Grid() { .margin({ top: $r('app.float.home_homeCell_margin') }) } } - }, item => JSON.stringify(item)) + }, (item: ItemData) => JSON.stringify(item)) } .columnsTemplate('1fr 1fr 1fr 1fr') .rowsTemplate('1fr 1fr') @@ -335,6 +344,7 @@ Grid() { 使用Grid组件实现4\*4栅格列表栏,其中单个栅格中有一张背景图片和两行字体不同的文本,因此在Column组件中放置两个Text组件,并设置背景图,注意Grid组件必须设置高度,否则可能出现页面空白。 ```typescript +// Home.ets Grid() { ForEach(mainViewModel.getSecondGridData(), (secondItem: ItemData) => { GridItem() { @@ -350,7 +360,7 @@ Grid() { .backgroundImage(secondItem.img) .backgroundImageSize(ImageSize.Cover) ... - }, secondItem => JSON.stringify(secondItem)) + }, (secondItem: ItemData) => JSON.stringify(secondItem)) } ... .height($r('app.float.home_secondGrid_height')) @@ -368,13 +378,14 @@ Grid() { 使用List组件结合ForEach语句来实现页面列表内容,其中引用了settingCell子组件,列表间的灰色分割线可以使用Divider属性实现,代码实现如下: ```typescript +// Setting.ets List() { ForEach(mainViewModel.getSettingListData(), (item: ItemData) => { ListItem() { this.settingCell(item) } .height($r('app.float.setting_list_height')) - }, item => JSON.stringify(item)) + }, (item: ItemData) => JSON.stringify(item)) } ... .divider({ // 设置分隔线 diff --git a/ETSUI/ArkTSComponents/entry/src/main/ets/pages/LoginPage.ets b/ETSUI/ArkTSComponents/entry/src/main/ets/pages/LoginPage.ets index b1eca42b47ace9e02ca6a05d469c25030b05d4f4..638b0f559d6137fb7410acb64a30c79c71b372a3 100644 --- a/ETSUI/ArkTSComponents/entry/src/main/ets/pages/LoginPage.ets +++ b/ETSUI/ArkTSComponents/entry/src/main/ets/pages/LoginPage.ets @@ -48,7 +48,7 @@ struct LoginPage { @State account: string = ''; @State password: string = ''; @State isShowProgress: boolean = false; - private timeOutId = null; + private timeOutId: number = -1; @Builder imageButton(src: Resource) { Button({ type: ButtonType.Circle, stateEffect: true }) { @@ -66,10 +66,10 @@ struct LoginPage { }) } else { this.isShowProgress = true; - if (this.timeOutId === null) { + if (this.timeOutId === -1) { this.timeOutId = setTimeout(() => { this.isShowProgress = false; - this.timeOutId = null; + this.timeOutId = -1; router.replaceUrl({ url: 'pages/MainPage' }); }, CommonConstants.LOGIN_DELAY_TIME); } @@ -78,7 +78,7 @@ struct LoginPage { aboutToDisappear() { clearTimeout(this.timeOutId); - this.timeOutId = null; + this.timeOutId = -1; } build() { diff --git a/ETSUI/ArkTSComponents/entry/src/main/ets/view/Home.ets b/ETSUI/ArkTSComponents/entry/src/main/ets/view/Home.ets index 6f6004de71b8b16286b8fad0b91d81a23df1173a..bf0a4fb528cceac43ede51d87722176294a5b4dc 100644 --- a/ETSUI/ArkTSComponents/entry/src/main/ets/view/Home.ets +++ b/ETSUI/ArkTSComponents/entry/src/main/ets/view/Home.ets @@ -15,7 +15,7 @@ import CommonConstants from '../common/constants/CommonConstants'; import mainViewModel from '../viewmodel/MainViewModel'; -import ItemData from '../common/bean/ItemData'; +import ItemData from '../viewmodel/ItemData'; /** * Home tab content @@ -40,7 +40,7 @@ export default struct Home { Swiper(this.swiperController) { ForEach(mainViewModel.getSwiperImages(), (img: Resource) => { Image(img).borderRadius($r('app.float.home_swiper_borderRadius')) - }, img => img.id) + }, (img: Resource) => JSON.stringify(img.id)) } .margin({ top: $r('app.float.home_swiper_margin') }) .autoPlay(true) @@ -57,7 +57,7 @@ export default struct Home { .margin({ top: $r('app.float.home_homeCell_margin') }) } } - }, item => JSON.stringify(item)) + }, (item: ItemData) => JSON.stringify(item)) } .columnsTemplate('1fr 1fr 1fr 1fr') .rowsTemplate('1fr 1fr') @@ -95,7 +95,7 @@ export default struct Home { .backgroundImageSize(ImageSize.Cover) .width(CommonConstants.FULL_PARENT) .height(CommonConstants.FULL_PARENT) - }, secondItem => JSON.stringify(secondItem)) + }, (secondItem: ItemData) => JSON.stringify(secondItem)) } .width(CommonConstants.FULL_PARENT) .height($r('app.float.home_secondGrid_height')) diff --git a/ETSUI/ArkTSComponents/entry/src/main/ets/view/Setting.ets b/ETSUI/ArkTSComponents/entry/src/main/ets/view/Setting.ets index 02fe7fdfab3629dddc17f8bf55ba0716f188af20..37c560b19996b8d3bf7110da3ca0da9bfaeb899c 100644 --- a/ETSUI/ArkTSComponents/entry/src/main/ets/view/Setting.ets +++ b/ETSUI/ArkTSComponents/entry/src/main/ets/view/Setting.ets @@ -14,7 +14,7 @@ */ import CommonConstants from '../common/constants/CommonConstants'; -import ItemData from '../common/bean/ItemData'; +import ItemData from '../viewmodel/ItemData'; import mainViewModel from '../viewmodel/MainViewModel'; /** @@ -89,7 +89,7 @@ export default struct Setting { this.settingCell(item) } .height($r('app.float.setting_list_height')) - }, item => JSON.stringify(item)) + }, (item: ItemData) => JSON.stringify(item)) } .backgroundColor(Color.White) .divider({ diff --git a/ETSUI/ArkTSComponents/entry/src/main/ets/common/bean/ItemData.ets b/ETSUI/ArkTSComponents/entry/src/main/ets/viewmodel/ItemData.ets similarity index 91% rename from ETSUI/ArkTSComponents/entry/src/main/ets/common/bean/ItemData.ets rename to ETSUI/ArkTSComponents/entry/src/main/ets/viewmodel/ItemData.ets index 812526a31a159f5ceae85f66273e040036d1a575..63b1d8921fdbe6524c7f3b62326af1aaededc083 100644 --- a/ETSUI/ArkTSComponents/entry/src/main/ets/common/bean/ItemData.ets +++ b/ETSUI/ArkTSComponents/entry/src/main/ets/viewmodel/ItemData.ets @@ -24,13 +24,13 @@ export default class PageResource { /** * Image of list item. */ - img?: Resource; + img: Resource; /** * Other resource of list item. */ others?: Resource; - constructor(title: Resource, img?: Resource, others?: Resource) { + constructor(title: Resource, img: Resource, others?: Resource) { this.title = title; this.img = img; this.others = others; diff --git a/ETSUI/ArkTSComponents/entry/src/main/ets/viewmodel/MainViewModel.ets b/ETSUI/ArkTSComponents/entry/src/main/ets/viewmodel/MainViewModel.ets index 672b2e72eed544287d88df2e7cf67fea36795128..74175da80b5590d0c748c0cd13edad8171c39d63 100644 --- a/ETSUI/ArkTSComponents/entry/src/main/ets/viewmodel/MainViewModel.ets +++ b/ETSUI/ArkTSComponents/entry/src/main/ets/viewmodel/MainViewModel.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import ItemData from '../common/bean/ItemData'; +import ItemData from './ItemData'; /** * Binds data to components and provides interfaces. @@ -79,11 +79,11 @@ export class MainViewModel { getSettingListData(): Array { let settingListData: ItemData[] = [ new ItemData($r('app.string.setting_list_news'), $r("app.media.news"), $r("app.string.setting_toggle")), - new ItemData($r('app.string.setting_list_data'), $r("app.media.data"), null), - new ItemData($r('app.string.setting_list_menu'), $r("app.media.menu"), null), - new ItemData($r('app.string.setting_list_about'), $r("app.media.about"), null), - new ItemData($r('app.string.setting_list_storage'), $r("app.media.storage"), null), - new ItemData($r('app.string.setting_list_privacy'), $r("app.media.privacy"), null) + new ItemData($r('app.string.setting_list_data'), $r("app.media.data")), + new ItemData($r('app.string.setting_list_menu'), $r("app.media.menu")), + new ItemData($r('app.string.setting_list_about'), $r("app.media.about")), + new ItemData($r('app.string.setting_list_storage'), $r("app.media.storage")), + new ItemData($r('app.string.setting_list_privacy'), $r("app.media.privacy")) ]; return settingListData; } diff --git a/ETSUI/ArkTSComponents/hvigor/hvigor-config.json5 b/ETSUI/ArkTSComponents/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/ETSUI/ArkTSComponents/hvigor/hvigor-config.json5 +++ b/ETSUI/ArkTSComponents/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/ETSUI/CanvasComponent/README.md b/ETSUI/CanvasComponent/README.md index 8f3eb02dc417e4cd48326642171e5bb27bf20ffa..58dc85a45ae92c598dadd974d73600dc77bc3eb2 100644 --- a/ETSUI/CanvasComponent/README.md +++ b/ETSUI/CanvasComponent/README.md @@ -22,13 +22,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -56,9 +56,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──FillArcData.ets // 绘制圆弧数据实体类 -│ │ │ └──PrizeData.ets // 中奖信息实体类 │ │ ├──constants │ │ │ ├──ColorConstants.ets // 颜色常量类 │ │ │ ├──CommonConstants.ets // 公共常量类 @@ -73,7 +70,9 @@ │ ├──view │ │ └──PrizeDialog.ets // 中奖信息弹窗类 │ └──viewmodel -│ └──DrawModel.ets // 画布相关方法类 +│ ├──DrawModel.ets // 画布相关方法类 +│ ├──FillArcData.ets // 绘制圆弧数据实体类 +│ └──PrizeData.ets // 中奖信息实体类 └──entry/src/main/resources // 资源文件目录 ``` @@ -98,7 +97,7 @@ aboutToAppear() { this.screenWidth = px2vp(windowProperties.windowRect.width); this.screenHeight = px2vp(windowProperties.windowRect.height); }) - .catch((error) => { + .catch((error: Error) => { Logger.error('Failed to obtain the window size. Cause: ' + JSON.stringify(error)); }) } @@ -172,15 +171,15 @@ drawFlower() { const radius = this.screenWidth * CommonConstants.FLOWER_RADIUS_RATIOS; const innerRadius = this.screenWidth * CommonConstants.FLOWER_INNER_RATIOS; for (let i = 0; i < CommonConstants.COUNT; i++) { - this.canvasContext.save(); - this.canvasContext.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); + this.canvasContext?.save(); + this.canvasContext?.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); this.fillArc(new FillArcData(0, -pointY, radius, 0, Math.PI * CommonConstants.TWO), ColorConstants.FLOWER_OUT_COLOR); this.fillArc(new FillArcData(0, -pointY, innerRadius, 0, Math.PI * CommonConstants.TWO), ColorConstants.FLOWER_INNER_COLOR); beginAngle += this.avgAngle; - this.canvasContext.restore(); + this.canvasContext?.restore(); } } @@ -190,11 +189,13 @@ fillArc(fillArcData: FillArcData, fillColor: string) { Logger.error('[DrawModel][fillArc] fillArcData or fillColor is empty.'); return; } - this.canvasContext.beginPath(); - this.canvasContext.fillStyle = fillColor; - this.canvasContext.arc(fillArcData.x, fillArcData.y, fillArcData.radius, - fillArcData.startAngle, fillArcData.endAngle); - this.canvasContext.fill(); + if (this.canvasContext !== undefined) { + this.canvasContext.beginPath(); + this.canvasContext.fillStyle = fillColor; + this.canvasContext.arc(fillArcData.x, fillArcData.y, fillArcData.radius, + fillArcData.startAngle, fillArcData.endAngle); + this.canvasContext.fill(); + } } ``` @@ -210,13 +211,13 @@ drawOutCircle() { let beginAngle = this.startAngle; // 画小圆圈 for (let i = 0; i < CommonConstants.SMALL_CIRCLE_COUNT; i++) { - this.canvasContext.save(); - this.canvasContext.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); + this.canvasContext?.save(); + this.canvasContext?.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); this.fillArc(new FillArcData(this.screenWidth * CommonConstants.SMALL_CIRCLE_RATIOS, 0, CommonConstants.SMALL_CIRCLE_RADIUS, 0, Math.PI * CommonConstants.TWO), ColorConstants.WHITE_COLOR); beginAngle = beginAngle + CommonConstants.CIRCLE / CommonConstants.SMALL_CIRCLE_COUNT; - this.canvasContext.restore(); + this.canvasContext?.restore(); } } ``` @@ -247,8 +248,8 @@ drawInnerArc() { for (let i = 0; i < CommonConstants.COUNT; i++) { this.fillArc(new FillArcData(0, 0, radius, this.startAngle * Math.PI / CommonConstants.HALF_CIRCLE, (this.startAngle + this.avgAngle) * Math.PI / CommonConstants.HALF_CIRCLE), colors[i]); - this.canvasContext.lineTo(0, 0); - this.canvasContext.fill(); + this.canvasContext?.lineTo(0, 0); + this.canvasContext?.fill(); this.startAngle += this.avgAngle; } } @@ -260,10 +261,12 @@ drawInnerArc() { // DrawModel.ets // 画内部扇形区域文字 drawArcText() { - this.canvasContext.textAlign = CommonConstants.TEXT_ALIGN; - this.canvasContext.textBaseline = CommonConstants.TEXT_BASE_LINE; - this.canvasContext.fillStyle = ColorConstants.TEXT_COLOR; - this.canvasContext.font = StyleConstants.ARC_TEXT_SIZE + CommonConstants.CANVAS_FONT; + if (this.canvasContext !== undefined) { + this.canvasContext.textAlign = CommonConstants.TEXT_ALIGN; + this.canvasContext.textBaseline = CommonConstants.TEXT_BASE_LINE; + this.canvasContext.fillStyle = ColorConstants.TEXT_COLOR; + this.canvasContext.font = StyleConstants.ARC_TEXT_SIZE + CommonConstants.CANVAS_FONT; + } // 需要绘制的文本数组集合 let textArrays = [ $r('app.string.text_smile'), @@ -289,7 +292,12 @@ drawCircularText(textString: string, startAngle: number, endAngle: number) { Logger.error('[DrawModel][drawCircularText] textString is empty.'); return; } - let circleText = { + class CircleText { + x: number = 0; + y: number = 0; + radius: number = 0; + } + let circleText: CircleText = { x: 0, y: 0, radius: this.screenWidth * CommonConstants.INNER_ARC_RATIOS @@ -300,19 +308,19 @@ drawCircularText(textString: string, startAngle: number, endAngle: number) { let angleDecrement = (startAngle - endAngle) / (textString.length - 1); let angle = startAngle; let index = 0; - let character; + let character: string; while (index < textString.length) { character = textString.charAt(index); - this.canvasContext.save(); - this.canvasContext.beginPath(); - this.canvasContext.translate(circleText.x + Math.cos(angle) * radius, + this.canvasContext?.save(); + this.canvasContext?.beginPath(); + this.canvasContext?.translate(circleText.x + Math.cos(angle) * radius, circleText.y - Math.sin(angle) * radius); - this.canvasContext.rotate(Math.PI / CommonConstants.TWO - angle); - this.canvasContext.fillText(character, 0, 0); + this.canvasContext?.rotate(Math.PI / CommonConstants.TWO - angle); + this.canvasContext?.fillText(character, 0, 0); angle -= angleDecrement; index++; - this.canvasContext.restore(); + this.canvasContext?.restore(); } } ``` @@ -331,13 +339,13 @@ drawImage() { ]; for (let i = 0; i < CommonConstants.COUNT; i++) { let image = new ImageBitmap(imageSrc[i]); - this.canvasContext.save(); - this.canvasContext.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); - this.canvasContext.drawImage(image, this.screenWidth * CommonConstants.IMAGE_DX_RATIOS, + this.canvasContext?.save(); + this.canvasContext?.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); + this.canvasContext?.drawImage(image, this.screenWidth * CommonConstants.IMAGE_DX_RATIOS, this.screenWidth * CommonConstants.IMAGE_DY_RATIOS, CommonConstants.IMAGE_SIZE, CommonConstants.IMAGE_SIZE); beginAngle += this.avgAngle; - this.canvasContext.restore(); + this.canvasContext?.restore(); } } ``` @@ -370,7 +378,7 @@ Stack({ alignContent: Alignment.Center }) { .onClick(() => { this.enableFlag = !this.enableFlag; // 开始抽奖 - startAnimator.call(this); + this.startAnimator(); }) } ... @@ -388,7 +396,7 @@ dialogController: CustomDialogController = new CustomDialogController({ autoCancel: false }); -// DrawModel.ets +// CanvasPage.ets // 开始抽奖 startAnimator() { let randomAngle = Math.round(Math.random() * CommonConstants.CIRCLE); @@ -421,7 +429,7 @@ startAnimator() { export default struct PrizeDialog { @Link prizeData: PrizeData; @Link enableFlag: boolean; - private controller: CustomDialogController; + private controller?: CustomDialogController; build() { Column() { @@ -435,7 +443,7 @@ export default struct PrizeDialog { ... .onClick(() => { // 关闭自定义弹窗 - this.controller.close(); + this.controller?.close(); this.enableFlag = !this.enableFlag; }) } diff --git a/ETSUI/CanvasComponent/entry/src/main/ets/common/utils/CheckEmptyUtils.ets b/ETSUI/CanvasComponent/entry/src/main/ets/common/utils/CheckEmptyUtils.ets index 9405ed49629183629d530af84528083fdb9e5549..5fe3b794c173778d8de83f86fefbaaa8a9473b02 100644 --- a/ETSUI/CanvasComponent/entry/src/main/ets/common/utils/CheckEmptyUtils.ets +++ b/ETSUI/CanvasComponent/entry/src/main/ets/common/utils/CheckEmptyUtils.ets @@ -23,7 +23,7 @@ class CheckEmptyUtils { * @param {object} obj * @return {boolean} true(empty) */ - isEmptyObj(obj) { + isEmptyObj(obj: object | string) { return (typeof obj === 'undefined' || obj === null || obj === ''); } @@ -33,7 +33,7 @@ class CheckEmptyUtils { * @param {string} str * @return {boolean} true(empty) */ - isEmptyStr(str) { + isEmptyStr(str: string) { return str.trim().length === 0; } @@ -43,7 +43,7 @@ class CheckEmptyUtils { * @param {Array}arr * @return {boolean} true(empty) */ - isEmptyArr(arr) { + isEmptyArr(arr: Array) { return arr.length === 0; } } diff --git a/ETSUI/CanvasComponent/entry/src/main/ets/common/utils/Logger.ets b/ETSUI/CanvasComponent/entry/src/main/ets/common/utils/Logger.ets index ec5bb8ad6a71e0cd1366aa41ffa520b9391b8496..3f90b617cfc1afb748f72ce3ba9e64d6dbc4172f 100644 --- a/ETSUI/CanvasComponent/entry/src/main/ets/common/utils/Logger.ets +++ b/ETSUI/CanvasComponent/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/ETSUI/CanvasComponent/entry/src/main/ets/pages/CanvasPage.ets b/ETSUI/CanvasComponent/entry/src/main/ets/pages/CanvasPage.ets index b2f5eadde559b8619ef75f36c7bc852c2b0d01ef..c979c6878a095f4d1f5351911f5df735ac131d81 100644 --- a/ETSUI/CanvasComponent/entry/src/main/ets/pages/CanvasPage.ets +++ b/ETSUI/CanvasComponent/entry/src/main/ets/pages/CanvasPage.ets @@ -17,10 +17,9 @@ import window from '@ohos.window'; import Logger from '../common/utils/Logger'; import DrawModel from '../viewmodel/DrawModel'; import PrizeDialog from '../view/PrizeDialog'; -import PrizeData from '../common/bean/PrizeData'; +import PrizeData from '../viewmodel//PrizeData'; import StyleConstants from '../common/constants/StyleConstants'; import CommonConstants from '../common/constants/CommonConstants'; -import { startAnimator } from '../viewmodel/DrawModel'; // Get context. let context = getContext(this); @@ -52,7 +51,7 @@ struct CanvasPage { this.screenWidth = px2vp(windowProperties.windowRect.width); this.screenHeight = px2vp(windowProperties.windowRect.height); }) - .catch((error) => { + .catch((error: Error) => { Logger.error('Failed to obtain the window size. Cause: ' + JSON.stringify(error)); }) } @@ -80,7 +79,7 @@ struct CanvasPage { .enabled(this.enableFlag) .onClick(() => { this.enableFlag = !this.enableFlag; - startAnimator.call(this); + this.startAnimator(); }) } .width(StyleConstants.FULL_PERCENT) @@ -91,4 +90,29 @@ struct CanvasPage { height: StyleConstants.BACKGROUND_IMAGE_SIZE }) } + + /** + * Start animator. + */ + startAnimator() { + let randomAngle = Math.round(Math.random() * CommonConstants.CIRCLE); + // Obtaining prize information. + this.prizeData = this.drawModel.showPrizeData(randomAngle); + + animateTo({ + duration: CommonConstants.DURATION, + curve: Curve.Ease, + delay: 0, + iterations: 1, + playMode: PlayMode.Normal, + onFinish: () => { + this.rotateDegree = CommonConstants.ANGLE - randomAngle; + // Display prize information pop-up window. + this.dialogController.open(); + } + }, () => { + this.rotateDegree = CommonConstants.CIRCLE * CommonConstants.FIVE + + CommonConstants.ANGLE - randomAngle; + }) + } } \ No newline at end of file diff --git a/ETSUI/CanvasComponent/entry/src/main/ets/view/PrizeDialog.ets b/ETSUI/CanvasComponent/entry/src/main/ets/view/PrizeDialog.ets index d23fa0bc097b97a6a55f2215da5e7cf5458ddb83..9e6cb3ca94122636b61a5289bd3f5dc7c237c7db 100644 --- a/ETSUI/CanvasComponent/entry/src/main/ets/view/PrizeDialog.ets +++ b/ETSUI/CanvasComponent/entry/src/main/ets/view/PrizeDialog.ets @@ -14,7 +14,7 @@ */ import matrix4 from '@ohos.matrix4'; -import PrizeData from '../common/bean/PrizeData'; +import PrizeData from '../viewmodel/PrizeData'; import StyleConstants from '../common/constants/StyleConstants'; import CommonConstants from '../common/constants/CommonConstants'; @@ -22,7 +22,7 @@ import CommonConstants from '../common/constants/CommonConstants'; export default struct PrizeDialog { @Link prizeData: PrizeData; @Link enableFlag: boolean; - private controller: CustomDialogController; + private controller?: CustomDialogController; build() { Column() { @@ -51,7 +51,7 @@ export default struct PrizeDialog { .fontSize($r('app.float.dialog_font_size')) .textAlign(TextAlign.Center) .onClick(() => { - this.controller.close(); + this.controller?.close(); this.enableFlag = !this.enableFlag; }) } diff --git a/ETSUI/CanvasComponent/entry/src/main/ets/viewmodel/DrawModel.ets b/ETSUI/CanvasComponent/entry/src/main/ets/viewmodel/DrawModel.ets index e4e3d7d5bafe36c05c79432599783beda76b3a87..9f1c040173684138642af7fd5d9f3468102e2e46 100644 --- a/ETSUI/CanvasComponent/entry/src/main/ets/viewmodel/DrawModel.ets +++ b/ETSUI/CanvasComponent/entry/src/main/ets/viewmodel/DrawModel.ets @@ -16,8 +16,8 @@ import CommonConstants from '../common/constants/CommonConstants'; import ColorConstants from '../common/constants/ColorConstants'; import StyleConstants from '../common/constants/StyleConstants'; -import PrizeData from '../common/bean/PrizeData'; -import FillArcData from '../common/bean/FillArcData'; +import PrizeData from '../viewmodel/PrizeData'; +import FillArcData from '../viewmodel//FillArcData'; import Logger from '../common/utils/Logger'; import CheckEmptyUtils from '../common/utils/CheckEmptyUtils'; @@ -28,7 +28,7 @@ export default class DrawModel { private startAngle: number = 0; private avgAngle: number = CommonConstants.CIRCLE / CommonConstants.COUNT; private screenWidth: number = 0; - private canvasContext: CanvasRenderingContext2D; + private canvasContext?: CanvasRenderingContext2D; /** * Draw the raffle round turntable. @@ -75,11 +75,13 @@ export default class DrawModel { Logger.error('[DrawModel][fillArc] fillArcData or fillColor is empty.'); return; } - this.canvasContext.beginPath(); - this.canvasContext.fillStyle = fillColor; - this.canvasContext.arc(fillArcData.x, fillArcData.y, fillArcData.radius, - fillArcData.startAngle, fillArcData.endAngle); - this.canvasContext.fill(); + if (this.canvasContext !== undefined) { + this.canvasContext.beginPath(); + this.canvasContext.fillStyle = fillColor; + this.canvasContext.arc(fillArcData.x, fillArcData.y, fillArcData.radius, + fillArcData.startAngle, fillArcData.endAngle); + this.canvasContext.fill(); + } } /** @@ -91,15 +93,15 @@ export default class DrawModel { const radius = this.screenWidth * CommonConstants.FLOWER_RADIUS_RATIOS; const innerRadius = this.screenWidth * CommonConstants.FLOWER_INNER_RATIOS; for (let i = 0; i < CommonConstants.COUNT; i++) { - this.canvasContext.save(); - this.canvasContext.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); + this.canvasContext?.save(); + this.canvasContext?.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); this.fillArc(new FillArcData(0, -pointY, radius, 0, Math.PI * CommonConstants.TWO), ColorConstants.FLOWER_OUT_COLOR); this.fillArc(new FillArcData(0, -pointY, innerRadius, 0, Math.PI * CommonConstants.TWO), ColorConstants.FLOWER_INNER_COLOR); beginAngle += this.avgAngle; - this.canvasContext.restore(); + this.canvasContext?.restore(); } } @@ -114,13 +116,13 @@ export default class DrawModel { let beginAngle = this.startAngle; // Draw small circle. for (let i = 0; i < CommonConstants.SMALL_CIRCLE_COUNT; i++) { - this.canvasContext.save(); - this.canvasContext.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); + this.canvasContext?.save(); + this.canvasContext?.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); this.fillArc(new FillArcData(this.screenWidth * CommonConstants.SMALL_CIRCLE_RATIOS, 0, CommonConstants.SMALL_CIRCLE_RADIUS, 0, Math.PI * CommonConstants.TWO), ColorConstants.WHITE_COLOR); beginAngle = beginAngle + CommonConstants.CIRCLE / CommonConstants.SMALL_CIRCLE_COUNT; - this.canvasContext.restore(); + this.canvasContext?.restore(); } } @@ -147,8 +149,8 @@ export default class DrawModel { for (let i = 0; i < CommonConstants.COUNT; i++) { this.fillArc(new FillArcData(0, 0, radius, this.startAngle * Math.PI / CommonConstants.HALF_CIRCLE, (this.startAngle + this.avgAngle) * Math.PI / CommonConstants.HALF_CIRCLE), colors[i]); - this.canvasContext.lineTo(0, 0); - this.canvasContext.fill(); + this.canvasContext?.lineTo(0, 0); + this.canvasContext?.fill(); this.startAngle += this.avgAngle; } } @@ -157,10 +159,12 @@ export default class DrawModel { * Draw text in the internal fan area. */ drawArcText() { - this.canvasContext.textAlign = CommonConstants.TEXT_ALIGN; - this.canvasContext.textBaseline = CommonConstants.TEXT_BASE_LINE; - this.canvasContext.fillStyle = ColorConstants.TEXT_COLOR; - this.canvasContext.font = StyleConstants.ARC_TEXT_SIZE + CommonConstants.CANVAS_FONT; + if (this.canvasContext !== undefined) { + this.canvasContext.textAlign = CommonConstants.TEXT_ALIGN; + this.canvasContext.textBaseline = CommonConstants.TEXT_BASE_LINE; + this.canvasContext.fillStyle = ColorConstants.TEXT_COLOR; + this.canvasContext.font = StyleConstants.ARC_TEXT_SIZE + CommonConstants.CANVAS_FONT; + } let textArrays = [ $r('app.string.text_smile'), $r('app.string.text_hamburger'), @@ -187,14 +191,13 @@ export default class DrawModel { getResourceString(resource: Resource): string { if (CheckEmptyUtils.isEmptyObj(resource)) { Logger.error('[DrawModel][getResourceString] resource is empty.') - return; + return ''; } let resourceString: string = ''; try { resourceString = getContext(this).resourceManager.getStringSync(resource.id); } catch (error) { - Logger.error(`[DrawModel][getResourceString]getStringSync failed, - error code: ${error.code}, message: ${error.message}.`); + Logger.error(`[DrawModel][getResourceString]getStringSync failed, error : ${JSON.stringify(error)}.`); } return resourceString; } @@ -211,7 +214,12 @@ export default class DrawModel { Logger.error('[DrawModel][drawCircularText] textString is empty.') return; } - let circleText = { + class CircleText { + x: number = 0; + y: number = 0; + radius: number = 0; + } + let circleText: CircleText = { x: 0, y: 0, radius: this.screenWidth * CommonConstants.INNER_ARC_RATIOS @@ -222,19 +230,19 @@ export default class DrawModel { let angleDecrement = (startAngle - endAngle) / (textString.length - 1); let angle = startAngle; let index = 0; - let character; + let character: string; while (index < textString.length) { character = textString.charAt(index); - this.canvasContext.save(); - this.canvasContext.beginPath(); - this.canvasContext.translate(circleText.x + Math.cos(angle) * radius, + this.canvasContext?.save(); + this.canvasContext?.beginPath(); + this.canvasContext?.translate(circleText.x + Math.cos(angle) * radius, circleText.y - Math.sin(angle) * radius); - this.canvasContext.rotate(Math.PI / CommonConstants.TWO - angle); - this.canvasContext.fillText(character, 0, 0); + this.canvasContext?.rotate(Math.PI / CommonConstants.TWO - angle); + this.canvasContext?.fillText(character, 0, 0); angle -= angleDecrement; index++; - this.canvasContext.restore(); + this.canvasContext?.restore(); } } @@ -250,13 +258,13 @@ export default class DrawModel { ]; for (let i = 0; i < CommonConstants.COUNT; i++) { let image = new ImageBitmap(imageSrc[i]); - this.canvasContext.save(); - this.canvasContext.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); - this.canvasContext.drawImage(image, this.screenWidth * CommonConstants.IMAGE_DX_RATIOS, + this.canvasContext?.save(); + this.canvasContext?.rotate(beginAngle * Math.PI / CommonConstants.HALF_CIRCLE); + this.canvasContext?.drawImage(image, this.screenWidth * CommonConstants.IMAGE_DX_RATIOS, this.screenWidth * CommonConstants.IMAGE_DY_RATIOS, CommonConstants.IMAGE_SIZE, CommonConstants.IMAGE_SIZE); beginAngle += this.avgAngle; - this.canvasContext.restore(); + this.canvasContext?.restore(); } } @@ -312,29 +320,4 @@ export default class DrawModel { } return prizeData; } -} - -/** - * Start animator. - */ -export function startAnimator() { - let randomAngle = Math.round(Math.random() * CommonConstants.CIRCLE); - // Obtaining prize information. - this.prizeData = this.drawModel.showPrizeData(randomAngle); - - animateTo({ - duration: CommonConstants.DURATION, - curve: Curve.Ease, - delay: 0, - iterations: 1, - playMode: PlayMode.Normal, - onFinish: () => { - this.rotateDegree = CommonConstants.ANGLE - randomAngle; - // Display prize information pop-up window. - this.dialogController.open(); - } - }, () => { - this.rotateDegree = CommonConstants.CIRCLE * CommonConstants.FIVE + - CommonConstants.ANGLE - randomAngle; - }) } \ No newline at end of file diff --git a/ETSUI/CanvasComponent/entry/src/main/ets/common/bean/FillArcData.ets b/ETSUI/CanvasComponent/entry/src/main/ets/viewmodel/FillArcData.ets similarity index 100% rename from ETSUI/CanvasComponent/entry/src/main/ets/common/bean/FillArcData.ets rename to ETSUI/CanvasComponent/entry/src/main/ets/viewmodel/FillArcData.ets diff --git a/ETSUI/CanvasComponent/entry/src/main/ets/common/bean/PrizeData.ets b/ETSUI/CanvasComponent/entry/src/main/ets/viewmodel/PrizeData.ets similarity index 94% rename from ETSUI/CanvasComponent/entry/src/main/ets/common/bean/PrizeData.ets rename to ETSUI/CanvasComponent/entry/src/main/ets/viewmodel/PrizeData.ets index 7b8253dd32b804c48f86de5d6f75d47a67bc79b7..7fa1b048dacb26f46be37bb026ca84d4b59ec609 100644 --- a/ETSUI/CanvasComponent/entry/src/main/ets/common/bean/PrizeData.ets +++ b/ETSUI/CanvasComponent/entry/src/main/ets/viewmodel/PrizeData.ets @@ -20,10 +20,10 @@ export default class PrizeData { /** * The prize message. */ - message: Resource; + message?: Resource; /** * Image src. */ - imageSrc: string; + imageSrc?: string; } diff --git a/ETSUI/CanvasComponent/hvigor/hvigor-config.json5 b/ETSUI/CanvasComponent/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/CanvasComponent/hvigor/hvigor-config.json5 +++ b/ETSUI/CanvasComponent/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } -} +} \ No newline at end of file diff --git a/ETSUI/CustomDialog/README.md b/ETSUI/CustomDialog/README.md index 786b85d074883cf8f7184e51339f33b5227bd252..a55b2d6a709eb778b127cda82b0e16fda1dee589 100644 --- a/ETSUI/CustomDialog/README.md +++ b/ETSUI/CustomDialog/README.md @@ -15,13 +15,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -51,6 +51,8 @@ │ ├──common │ │ └──constants │ │ └──StyleConstants.ets // 抽离样式 +│ │ └──utils +│ │ └──Logger.ets // 日志工具类 │ ├──entryability │ │ └──EntryAbility.ts // 程序入口类 │ ├──pages @@ -69,15 +71,15 @@ ### 公共弹窗组件 -首先创建Index.ets作为主界面,公共弹窗组件直接使用AlertDialog的show方法拉起,效果如图所示: +首先创建DialogPage.ets作为主界面,公共弹窗组件直接使用AlertDialog的show方法拉起,效果如图所示: ![](figures/自定义弹窗1.gif) ```typescript -// Index.ets +// DialogPage.ets @Entry @Component -struct Index { +struct DialogPage { ... build() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { @@ -98,7 +100,7 @@ struct Index { Logger.info('Closed callbacks'); } } - ) + ); }) .height(StyleConstants.BUTTON_HEIGHT) .width(StyleConstants.BUTTON_WIDTH) @@ -117,7 +119,7 @@ struct Index { // DialogPage.ets @Entry @Component -struct Index { +struct DialogPage { dialogControllerExample: CustomDialogController = new CustomDialogController({ builder: ConfirmDialog({ cancel: this.onCancel, confirm: this.onAccept }), cancel: this.existApp, @@ -125,7 +127,7 @@ struct Index { alignment: DialogAlignment.Bottom, customStyle: true, offset: { dx: $r('app.float.dialog_offset_x'), dy: $r('app.float.dialog_offset_y') } - }); + }); dialogControllerAlert: CustomDialogController = new CustomDialogController({ builder: CustomAlertDialog({ cancel: this.onCancel, confirm: this.onAccept }), cancel: this.existApp, @@ -133,7 +135,7 @@ struct Index { alignment: DialogAlignment.Bottom, customStyle: true, offset: { dx: $r('app.float.dialog_offset_x'), dy: $r('app.float.dialog_offset_y') } - }); + }); ... build() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { diff --git a/ETSUI/CustomDialog/entry/src/main/ets/common/utils/Logger.ets b/ETSUI/CustomDialog/entry/src/main/ets/common/utils/Logger.ets index b2614451fbbcd3aabfd08ae6efbd8321fc96a9b7..6a74e450657a7b1c8d2fcae5c74e8d8a61ebb79d 100644 --- a/ETSUI/CustomDialog/entry/src/main/ets/common/utils/Logger.ets +++ b/ETSUI/CustomDialog/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: Object[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: Object[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: Object[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: Object[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/ETSUI/CustomDialog/entry/src/main/ets/view/ConfirmDialog.ets b/ETSUI/CustomDialog/entry/src/main/ets/view/ConfirmDialog.ets index 7e99d0885f97584679f835390926826dd7042c4b..f43a7d2505d1679d156dc68df22ca428eeaf2974 100644 --- a/ETSUI/CustomDialog/entry/src/main/ets/view/ConfirmDialog.ets +++ b/ETSUI/CustomDialog/entry/src/main/ets/view/ConfirmDialog.ets @@ -17,9 +17,11 @@ import StyleConstants from '../common/constants/StyleConstants'; @CustomDialog export default struct ConfirmDialog { - controller: CustomDialogController; - cancel: () => void; - confirm: () => void; + controller?: CustomDialogController; + cancel: () => void = () => { + }; + confirm: () => void = () => { + }; build() { Column() { @@ -33,6 +35,9 @@ export default struct ConfirmDialog { Flex({ justifyContent: FlexAlign.SpaceAround, alignItems: ItemAlign.Center }) { Button($r('app.string.cancel_txt')) .onClick(() => { + if (!this.controller) { + return; + } this.controller.close(); this.cancel(); }) @@ -46,6 +51,9 @@ export default struct ConfirmDialog { .height($r('app.float.diver_height')) Button($r('app.string.custom_dialog_confirm_txt')) .onClick(() => { + if (!this.controller) { + return; + } this.controller.close(); this.confirm(); }) diff --git a/ETSUI/CustomDialog/entry/src/main/ets/view/CustomAlertDialog.ets b/ETSUI/CustomDialog/entry/src/main/ets/view/CustomAlertDialog.ets index 2bc45f96255727e23d1d65c0c46fe228c6f6773e..e0436e39316d81b19eda909d7be875257eb110ff 100644 --- a/ETSUI/CustomDialog/entry/src/main/ets/view/CustomAlertDialog.ets +++ b/ETSUI/CustomDialog/entry/src/main/ets/view/CustomAlertDialog.ets @@ -17,9 +17,11 @@ import StyleConstants from '../common/constants/StyleConstants'; @CustomDialog export default struct CustomAlertDialog { - controller: CustomDialogController; - cancel: () => void; - confirm: () => void; + controller?: CustomDialogController; + cancel: () => void = () => { + }; + confirm: () => void = () => { + }; build() { Column() { @@ -29,8 +31,11 @@ export default struct CustomAlertDialog { Flex({ justifyContent: FlexAlign.SpaceAround, alignItems: ItemAlign.Center }) { Button($r('app.string.cancel_txt')) .onClick(() => { - this.controller.close(); this.cancel(); + if (!this.controller) { + return; + } + this.controller.close(); }) .backgroundColor($r('app.color.dialog_button_background_color')) .fontColor($r('app.color.font_color_blue')) @@ -42,8 +47,11 @@ export default struct CustomAlertDialog { .height($r('app.float.diver_height')) Button($r('app.string.confirm_txt')) .onClick(() => { - this.controller.close(); this.confirm(); + if (!this.controller) { + return; + } + this.controller.close(); }) .backgroundColor($r('app.color.dialog_button_background_color')) .fontColor($r('app.color.font_color_blue')) diff --git a/ETSUI/CustomDialog/hvigor/hvigor-config.json5 b/ETSUI/CustomDialog/hvigor/hvigor-config.json5 index dd6d7a66b580d1a50c108144878558f98ae6837f..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/CustomDialog/hvigor/hvigor-config.json5 +++ b/ETSUI/CustomDialog/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.1.1", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.1.1" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/ETSUI/ElectronicAlbum/README.md b/ETSUI/ElectronicAlbum/README.md index 9a03e2e9c62ea891ca66131453268fd15d020ab7..118613116474520d5bc9940e9d0a20740e83df7d 100644 --- a/ETSUI/ElectronicAlbum/README.md +++ b/ETSUI/ElectronicAlbum/README.md @@ -22,13 +22,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -91,7 +91,7 @@ Column() { Image(item) ... } - }, (item, index) => JSON.stringify(item) + index) + }, (item: Resource, index: number) => JSON.stringify(item) + index) } ... @@ -105,9 +105,11 @@ Column() { router.pushUrl({ url: Constants.URL_LIST_PAGE, params: { photoArr: JSON.stringify(photoArr) } + }).catch((error: Error) => { + Logger.error(Constants.TAG_INDEX_PAGE, JSON.stringify(error)); }); }) - }, (item, index) => JSON.stringify(item) + index) + }, (item: Array, index: number) => JSON.stringify(item) + index) } ... .layoutWeight(1) @@ -128,18 +130,20 @@ Navigation() { GridItem() { Image(img) .onClick(() => { - this.selectedIndex.set(index); + this.selectedIndex = index; router.pushUrl({ url: Constants.URL_DETAIL_LIST_PAGE, params: { photoArr: JSON.stringify(this.photoArr), } - }) + }).catch((error: Error) => { + Logger.error(Constants.TAG_LIST_PAGE, JSON.stringify(error)); + }); }) } ... .aspectRatio(1) - }, item => JSON.stringify(item)) + }, (item: Resource) => JSON.stringify(item)) } .columnsTemplate(Constants.GRID_COLUMNS_TEMPLATE) .layoutWeight(1) @@ -153,18 +157,18 @@ Navigation() { ![](figures/oh_list_360.gif) ```typescript -// ListDetailPage.ets +// DetailListPage.ets Stack({ alignContent: Alignment.Bottom }) { - List({ scroller: this.bigScroller, initialIndex: this.selectedIndex.get() }) { + List({ scroller: this.bigScroller, initialIndex: this.selectedIndex }) { ForEach(this.photoArr, (img: Resource, index: number) => { ListItem() { Image(img) ... .gesture(PinchGesture({ fingers: Constants.DOUBLE_NUMBER }) - .onActionStart(this.goDetailPage.bind(this))) - .onClick(this.goDetailPage.bind(this)) + .onActionStart(() => this.goDetailPage())) + .onClick(() => this.goDetailPage()) } - }, item => JSON.stringify(item)) + }, (item: Resource) => JSON.stringify(item)) } ... .onScroll((scrollOffset, scrollState) => { @@ -174,12 +178,12 @@ Stack({ alignContent: Alignment.Bottom }) { }) .onScrollStop(() => this.bigScrollAction(scrollTypeEnum.STOP)) - List({ scroller: this.smallScroller, space: Constants.LIST_ITEM_SPACE, initialIndex: this.selectedIndex.get() }) { + List({ scroller: this.smallScroller, space: Constants.LIST_ITEM_SPACE, initialIndex: this.selectedIndex }) { ForEach(this.smallPhotoArr, (img: Resource, index: number) => { ListItem() { this.SmallImgItemBuilder(img, index) } - }, item => JSON.stringify(item)) + }, (item: Resource, index: number) => JSON.stringify(item) + index) } ... .listDirection(Axis.Horizontal) @@ -201,8 +205,8 @@ Stack({ alignContent: Alignment.Bottom }) { ```typescript // DetailPage.ets Stack() { - List({ scroller: this.scroller }) { - ForEach(this.photoArr, (img: Resource, index: number) => { + List({ scroller: this.scroller, initialIndex: this.selectedIndex }) { + ForEach(this.photoArr, (img: Resource) => { ListItem() { Image(img) ... @@ -211,23 +215,37 @@ Stack() { } .gesture(PinchGesture({ fingers: Constants.DOUBLE_NUMBER }) .onActionStart(() => { - this.selectedIndex.set(index); this.resetImg(); this.isScaling = true; + this.imgOffSetX = 0; + this.imgOffSetY = 0; + }) + .onActionUpdate((event: GestureEvent) => { + this.imgScale = this.currentScale * event.scale; + }) + .onActionEnd(() => { + if (this.imgScale < 1) { + this.resetImg(); + this.imgOffSetX = 0; + this.imgOffSetY = 0; + } else { + this.currentScale = this.imgScale; + } }) ) - }, item => JSON.stringify(item)) + }, (item: Resource) => JSON.stringify(item)) } ... .onScrollStop(() => { let currentIndex = Math.round((this.scroller.currentOffset() .xOffset + (this.imageWidth / Constants.DOUBLE_NUMBER)) / this.imageWidth); + this.selectedIndex = currentIndex; this.scroller.scrollTo({ xOffset: currentIndex * this.imageWidth, yOffset: 0 }); }) .visibility(this.isScaling ? Visibility.Hidden : Visibility.Visible) Row() { - Image(this.photoArr[this.selectedIndex.get()]) + Image(this.photoArr[this.selectedIndex]) ... } .visibility(this.isScaling ? Visibility.Visible : Visibility.Hidden) @@ -241,20 +259,22 @@ Stack() { ```typescript // DetailPage.ets Row() { - Image(this.photoArr[this.selectedIndex.get()]) + Image(this.photoArr[this.selectedIndex]) .position({ x: this.imgOffSetX, y: this.imgOffSetY }) .scale({ x: this.imgScale, y: this.imgScale }) } - .gesture(GestureGroup(GestureMode.Parallel, + .gesture(GestureGroup(GestureMode.Exclusive, PinchGesture({ fingers: Constants.DOUBLE_NUMBER }) .onActionUpdate((event: GestureEvent) => { - this.imgScale = event.scale; + this.imgScale = this.currentScale * event.scale; }) .onActionEnd(() => { if (this.imgScale < 1) { this.resetImg(); this.imgOffSetX = 0; this.imgOffSetY = 0; + } else { + this.currentScale = this.imgScale; } }), PanGesture() @@ -266,7 +286,7 @@ Row() { this.imgOffSetX = this.preOffsetX + event.offsetX; this.imgOffSetY = this.preOffsetY + event.offsetY; }) - .onActionEnd(this.handlePanEnd.bind(this)) + .onActionEnd(() => this.handlePanEnd()) )) ``` diff --git a/ETSUI/ElectronicAlbum/entry/src/main/ets/common/constants/Constants.ets b/ETSUI/ElectronicAlbum/entry/src/main/ets/common/constants/Constants.ets index dfb30a7cdbd723a7753163ad24324af6724e6ece..ea9970f095057a5cd78c41659598a9c1677698eb 100644 --- a/ETSUI/ElectronicAlbum/entry/src/main/ets/common/constants/Constants.ets +++ b/ETSUI/ElectronicAlbum/entry/src/main/ets/common/constants/Constants.ets @@ -67,9 +67,9 @@ export default class Constants { * index page img arr */ static readonly IMG_ARR: Resource[][] = [ - [...Constants.SCENE_LIST, ...Constants.LIFE_LIST, ...Constants.MEN_LIST, ...Constants.FOOD_LIST, ...Constants.BANNER_IMG_LIST], + [...Constants.SCENE_LIST, ...Constants.LIFE_LIST, ...Constants.MEN_LIST, ...Constants.FOOD_LIST], [...Constants.MEN_LIST, ...Constants.LIFE_LIST, ...Constants.SCENE_LIST], - [...Constants.FOOD_LIST, ...Constants.SCENE_LIST, ...Constants.SCENE_LIST], + [...Constants.FOOD_LIST, ...Constants.SCENE_LIST, ...Constants.LIFE_LIST], [...Constants.LIFE_LIST, ...Constants.FOOD_LIST, ...Constants.MEN_LIST] ]; @@ -123,11 +123,6 @@ export default class Constants { */ static readonly PARAM_PHOTO_ARR_KEY: string = 'photoArr'; - /** - * selected index - */ - static readonly SELECTED_INDEX_KEY: string = 'selectedIndex'; - /** * grid column template */ diff --git a/ETSUI/ElectronicAlbum/entry/src/main/ets/common/utils/Logger.ets b/ETSUI/ElectronicAlbum/entry/src/main/ets/common/utils/Logger.ets index 695b2e6cf562ac7f3de2a9fd8c5de2dfe0cb3ca5..67799e7ce0fc9a541b0f339476352f2f5318d1df 100644 --- a/ETSUI/ElectronicAlbum/entry/src/main/ets/common/utils/Logger.ets +++ b/ETSUI/ElectronicAlbum/entry/src/main/ets/common/utils/Logger.ets @@ -36,19 +36,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: Object[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: Object[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: Object[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: Object[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/DetailListPage.ets b/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/DetailListPage.ets index 4d082237e88b5175261ad1bb0b2b899eedc2339d..4b3c3322bb9a0a32dad33b9fc47c090351497322 100644 --- a/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/DetailListPage.ets +++ b/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/DetailListPage.ets @@ -30,17 +30,19 @@ struct DetailListPage { private bigScroller: Scroller = new Scroller(); @State deviceWidth: number = Constants.DEFAULT_WIDTH; @State smallImgWidth: number = (this.deviceWidth - Constants.LIST_ITEM_SPACE * (Constants.SHOW_COUNT - 1)) / - Constants.SHOW_COUNT; + Constants.SHOW_COUNT; @State imageWidth: number = this.deviceWidth + this.smallImgWidth; - private photoArr: Array = router.getParams()[`${Constants.PARAM_PHOTO_ARR_KEY}`]; + private photoArr: Array = + (router.getParams() as Record>)[`${Constants.PARAM_PHOTO_ARR_KEY}`]; private smallPhotoArr: Array = [ ...Constants.CACHE_IMG_LIST, - ...router.getParams()[`${Constants.PARAM_PHOTO_ARR_KEY}`], + ...(router.getParams() as Record>)[`${Constants.PARAM_PHOTO_ARR_KEY}`], ...Constants.CACHE_IMG_LIST ]; - @State selectedIndex: SubscribedAbstractProperty = AppStorage.Link(`${Constants.SELECTED_INDEX_KEY}`); + @StorageLink('selectedIndex') selectedIndex: number = 0; - @Builder SmallImgItemBuilder(img: Resource, index: number) { + @Builder + SmallImgItemBuilder(img: Resource, index: number) { if (index > (Constants.CACHE_IMG_SIZE - 1) && index < (this.smallPhotoArr.length - Constants.CACHE_IMG_SIZE)) { Image(img) .onClick(() => this.smallImgClickAction(index)) @@ -56,50 +58,50 @@ struct DetailListPage { } onPageShow() { - this.smallScroller.scrollToIndex(this.selectedIndex.get()); - this.bigScroller.scrollToIndex(this.selectedIndex.get()); + this.smallScroller.scrollToIndex(this.selectedIndex); + this.bigScroller.scrollToIndex(this.selectedIndex); } goDetailPage() { router.pushUrl({ url: Constants.URL_DETAIL_PAGE, params: { photoArr: this.photoArr } - }).catch((error) => { - Logger.error(Constants.TAG_DETAIL_PAGE, JSON.stringify(error)); + }).catch((error: Error) => { + Logger.error(Constants.URL_DETAIL_LIST_PAGE, JSON.stringify(error)); }); } smallImgClickAction(index: number) { - this.selectedIndex.set(index - Constants.CACHE_IMG_SIZE); - this.smallScroller.scrollToIndex(this.selectedIndex.get()); - this.bigScroller.scrollToIndex(this.selectedIndex.get()); + this.selectedIndex = index - Constants.CACHE_IMG_SIZE; + this.smallScroller.scrollToIndex(this.selectedIndex); + this.bigScroller.scrollToIndex(this.selectedIndex); } smallScrollAction(type: scrollTypeEnum) { - this.selectedIndex.set(Math.round((this.smallScroller.currentOffset().xOffset + - this.smallImgWidth / Constants.DOUBLE_NUMBER) / (this.smallImgWidth + Constants.LIST_ITEM_SPACE))); + this.selectedIndex = Math.round((this.smallScroller.currentOffset().xOffset + + this.smallImgWidth / Constants.DOUBLE_NUMBER) / (this.smallImgWidth + Constants.LIST_ITEM_SPACE)); if (type === scrollTypeEnum.SCROLL) { - this.bigScroller.scrollTo({ xOffset: this.selectedIndex.get() * this.imageWidth, yOffset: 0 }); + this.bigScroller.scrollTo({ xOffset: this.selectedIndex * this.imageWidth, yOffset: 0 }); } else { - this.smallScroller.scrollTo({ xOffset: this.selectedIndex.get() * this.smallImgWidth, yOffset: 0 }); + this.smallScroller.scrollTo({ xOffset: this.selectedIndex * this.smallImgWidth, yOffset: 0 }); } } bigScrollAction(type: scrollTypeEnum) { let smallWidth = this.smallImgWidth + Constants.LIST_ITEM_SPACE; - this.selectedIndex.set(Math.round((this.bigScroller.currentOffset().xOffset + - smallWidth / Constants.DOUBLE_NUMBER) / this.imageWidth)); + this.selectedIndex = Math.round((this.bigScroller.currentOffset().xOffset + + smallWidth / Constants.DOUBLE_NUMBER) / this.imageWidth); if (type === scrollTypeEnum.SCROLL) { - this.smallScroller.scrollTo({ xOffset: this.selectedIndex.get() * smallWidth, yOffset: 0 }); + this.smallScroller.scrollTo({ xOffset: this.selectedIndex * smallWidth, yOffset: 0 }); } else { - this.bigScroller.scrollTo({ xOffset: this.selectedIndex.get() * this.imageWidth, yOffset: 0 }); + this.bigScroller.scrollTo({ xOffset: this.selectedIndex * this.imageWidth, yOffset: 0 }); } } build() { Navigation() { Stack({ alignContent: Alignment.Bottom }) { - List({ scroller: this.bigScroller, initialIndex: this.selectedIndex.get() }) { + List({ scroller: this.bigScroller, initialIndex: this.selectedIndex }) { ForEach(this.photoArr, (img: Resource) => { ListItem() { Image(img) @@ -107,15 +109,15 @@ struct DetailListPage { .width(Constants.FULL_PERCENT) .objectFit(ImageFit.Contain) .gesture(PinchGesture({ fingers: Constants.DOUBLE_NUMBER }) - .onActionStart(this.goDetailPage.bind(this))) - .onClick(this.goDetailPage.bind(this)) + .onActionStart(() => this.goDetailPage())) + .onClick(() => this.goDetailPage()) } .padding({ left: this.smallImgWidth / Constants.DOUBLE_NUMBER, right: this.smallImgWidth / Constants.DOUBLE_NUMBER }) .width(this.imageWidth) - }, item => JSON.stringify(item)) + }, (item: Resource) => JSON.stringify(item)) } .onScroll((scrollOffset, scrollState) => { if (scrollState === ScrollState.Fling) { @@ -131,7 +133,7 @@ struct DetailListPage { List({ scroller: this.smallScroller, space: Constants.LIST_ITEM_SPACE, - initialIndex: this.selectedIndex.get() + initialIndex: this.selectedIndex }) { ForEach(this.smallPhotoArr, (img: Resource, index: number) => { ListItem() { @@ -139,7 +141,7 @@ struct DetailListPage { } .width(this.smallImgWidth) .aspectRatio(1) - }, item => JSON.stringify(item)) + }, (item: Resource, index: number) => JSON.stringify(item) + index) } .listDirection(Axis.Horizontal) .onScroll((scrollOffset, scrollState) => { diff --git a/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/DetailPage.ets b/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/DetailPage.ets index 788fe9b19df782ea2a41a0d01a10e7e674454208..564edd46cacdb589182233c51b7e81a975a9a9d2 100644 --- a/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/DetailPage.ets +++ b/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/DetailPage.ets @@ -21,7 +21,7 @@ import Constants from '../common/constants/Constants'; @Component struct DetailPage { scroller: Scroller = new Scroller(); - photoArr: Array = router.getParams()[`${Constants.PARAM_PHOTO_ARR_KEY}`]; + photoArr: Array = (router.getParams() as Record>)[`${Constants.PARAM_PHOTO_ARR_KEY}`]; preOffsetX: number = 0; preOffsetY: number = 0; currentScale: number = 1; @@ -29,7 +29,7 @@ struct DetailPage { @State smallImgWidth: number = (Constants.DEFAULT_WIDTH - Constants.LIST_ITEM_SPACE * (Constants.SHOW_COUNT - 1)) / Constants.SHOW_COUNT; @State imageWidth: number = this.deviceWidth + this.smallImgWidth; - @State selectedIndex: SubscribedAbstractProperty = AppStorage.Link(`${Constants.SELECTED_INDEX_KEY}`); + @StorageLink('selectedIndex') selectedIndex: number = 0; @State isScaling: boolean = true; @State imgScale: number = 1; @State imgOffSetX: number = 0; @@ -54,20 +54,20 @@ struct DetailPage { handlePanEnd() { let initOffsetX = (this.imgScale - 1) * this.imageWidth + this.smallImgWidth; if (Math.abs(this.imgOffSetX) > initOffsetX) { - if (this.imgOffSetX > initOffsetX && this.selectedIndex.get() > 0) { - this.selectedIndex.set(this.selectedIndex.get() - 1); - } else if (this.imgOffSetX < -initOffsetX && this.selectedIndex.get() < (this.photoArr.length - 1)) { - this.selectedIndex.set(this.selectedIndex.get() + 1); + if (this.imgOffSetX > initOffsetX && this.selectedIndex > 0) { + this.selectedIndex = this.selectedIndex - 1; + } else if (this.imgOffSetX < -initOffsetX && this.selectedIndex < (this.photoArr.length - 1)) { + this.selectedIndex = this.selectedIndex + 1; } this.isScaling = false; this.resetImg(); - this.scroller.scrollTo({ xOffset: this.selectedIndex.get() * this.imageWidth, yOffset: 0 }); + this.scroller.scrollTo({ xOffset: this.selectedIndex * this.imageWidth, yOffset: 0 }); } } build() { Stack() { - List({ scroller: this.scroller, initialIndex: this.selectedIndex.get() }) { + List({ scroller: this.scroller, initialIndex: this.selectedIndex }) { ForEach(this.photoArr, (img: Resource) => { ListItem() { Image(img) @@ -99,12 +99,12 @@ struct DetailPage { right: this.smallImgWidth / Constants.DOUBLE_NUMBER }) .width(this.imageWidth) - }, item => JSON.stringify(item)) + }, (item: Resource) => JSON.stringify(item)) } .onScrollStop(() => { let currentIndex = Math.round((this.scroller.currentOffset().xOffset + - (this.imageWidth / Constants.DOUBLE_NUMBER)) / this.imageWidth); - this.selectedIndex.set(currentIndex); + (this.imageWidth / Constants.DOUBLE_NUMBER)) / this.imageWidth); + this.selectedIndex = currentIndex; this.scroller.scrollTo({ xOffset: currentIndex * this.imageWidth, yOffset: 0 }); }) .width(Constants.FULL_PERCENT) @@ -113,36 +113,36 @@ struct DetailPage { .visibility(this.isScaling ? Visibility.Hidden : Visibility.Visible) Row() { - Image(this.photoArr[this.selectedIndex.get()]) + Image(this.photoArr[this.selectedIndex]) .position({ x: this.imgOffSetX, y: this.imgOffSetY }) .scale({ x: this.imgScale, y: this.imgScale }) .objectFit(ImageFit.Contain) .onClick(() => router.back()) } .gesture(GestureGroup(GestureMode.Exclusive, - PinchGesture({ fingers: Constants.DOUBLE_NUMBER }) - .onActionUpdate((event: GestureEvent) => { - this.imgScale = this.currentScale * event.scale; - }) - .onActionEnd(() => { - if (this.imgScale < 1) { - this.resetImg(); - this.imgOffSetX = 0; - this.imgOffSetY = 0; - } else { - this.currentScale = this.imgScale; - } - }), - PanGesture() - .onActionStart(() => { - this.preOffsetX = this.imgOffSetX; - this.preOffsetY = this.imgOffSetY; - }) - .onActionUpdate((event: GestureEvent) => { - this.imgOffSetX = this.preOffsetX + event.offsetX; - this.imgOffSetY = this.preOffsetY + event.offsetY; - }) - .onActionEnd(this.handlePanEnd.bind(this)) + PinchGesture({ fingers: Constants.DOUBLE_NUMBER }) + .onActionUpdate((event: GestureEvent) => { + this.imgScale = this.currentScale * event.scale; + }) + .onActionEnd(() => { + if (this.imgScale < 1) { + this.resetImg(); + this.imgOffSetX = 0; + this.imgOffSetY = 0; + } else { + this.currentScale = this.imgScale; + } + }), + PanGesture() + .onActionStart(() => { + this.preOffsetX = this.imgOffSetX; + this.preOffsetY = this.imgOffSetY; + }) + .onActionUpdate((event: GestureEvent) => { + this.imgOffSetX = this.preOffsetX + event.offsetX; + this.imgOffSetY = this.preOffsetY + event.offsetY; + }) + .onActionEnd(() => this.handlePanEnd()) )) .padding({ left: this.smallImgWidth / Constants.DOUBLE_NUMBER, diff --git a/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/IndexPage.ets b/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/IndexPage.ets index 7ff2a768bdd08581246142ec0fdcf5708f7426f5..0cecbb18ae7ef199c66514a7fcdc6d40dec141d8 100644 --- a/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/IndexPage.ets +++ b/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/IndexPage.ets @@ -49,7 +49,7 @@ struct IndexPage { } .width(Constants.FULL_PERCENT) .aspectRatio(Constants.BANNER_ASPECT_RATIO) - }, (item, index) => JSON.stringify(item) + index) + }, (item: Resource, index: number) => JSON.stringify(item) + index) } .autoPlay(true) .loop(true) @@ -70,11 +70,11 @@ struct IndexPage { router.pushUrl({ url: Constants.URL_LIST_PAGE, params: { photoArr: photoArr } - }).catch((error) => { + }).catch((error: Error) => { Logger.error(Constants.TAG_INDEX_PAGE, JSON.stringify(error)); }); }) - }, (item, index) => JSON.stringify(item) + index) + }, (item: Array, index: number) => JSON.stringify(item) + index) } .columnsTemplate(Constants.INDEX_COLUMNS_TEMPLATE) .columnsGap($r('app.float.grid_padding')) diff --git a/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/ListPage.ets b/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/ListPage.ets index b156f8391143b43d8e308fa6cb5312fa107f76cf..d4141b88292a9e805d5cb2722436a7aaf87fb44f 100644 --- a/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/ListPage.ets +++ b/ETSUI/ElectronicAlbum/entry/src/main/ets/pages/ListPage.ets @@ -20,8 +20,8 @@ import Logger from '../common/utils/Logger'; @Entry @Component struct ListPage { - photoArr: Array = router.getParams()[`${Constants.PARAM_PHOTO_ARR_KEY}`]; - @State selectedIndex: SubscribedAbstractProperty = AppStorage.SetAndLink(`${Constants.SELECTED_INDEX_KEY}`, 0); + photoArr: Array = (router.getParams() as Record>)[`${Constants.PARAM_PHOTO_ARR_KEY}`]; + @StorageLink('selectedIndex') selectedIndex: number = 0; build() { Navigation() { @@ -33,20 +33,20 @@ struct ListPage { .width(Constants.FULL_PERCENT) .objectFit(ImageFit.Cover) .onClick(() => { - this.selectedIndex.set(index); + this.selectedIndex = index; router.pushUrl({ url: Constants.URL_DETAIL_LIST_PAGE, params: { photoArr: this.photoArr, } - }).catch((error) => { + }).catch((error: Error) => { Logger.error(Constants.TAG_LIST_PAGE, JSON.stringify(error)); }); }) } .width(Constants.FULL_PERCENT) .aspectRatio(1) - }, item => JSON.stringify(item)) + }, (item: Resource) => JSON.stringify(item)) } .columnsTemplate(Constants.GRID_COLUMNS_TEMPLATE) .rowsGap(Constants.LIST_ITEM_SPACE) diff --git a/ETSUI/ElectronicAlbum/entry/src/main/ets/view/PhotoItem.ets b/ETSUI/ElectronicAlbum/entry/src/main/ets/view/PhotoItem.ets index 3ee471b0498b014c8edd31faa217d913b094e90f..c6c3ad385024831397a31be5337e842a26eb2ddb 100644 --- a/ETSUI/ElectronicAlbum/entry/src/main/ets/view/PhotoItem.ets +++ b/ETSUI/ElectronicAlbum/entry/src/main/ets/view/PhotoItem.ets @@ -17,11 +17,12 @@ import Constants from '../common/constants/Constants'; @Component export default struct PhotoItem { - photoArr: Array; + photoArr: Array = []; @State currentIndex: number = 0; private showCount: number = Constants.SHOW_COUNT / Constants.DOUBLE_NUMBER; - @Builder albumPicBuilder(img: Resource, index: number) { + @Builder + albumPicBuilder(img: Resource, index: number) { Column() { Image(img) .width(Constants.FULL_PERCENT) @@ -37,9 +38,9 @@ export default struct PhotoItem { build() { Stack({ alignContent: Alignment.Top }) { - ForEach(Constants.CACHE_IMG_LIST, (image, index) => { - this.albumPicBuilder(this.photoArr[this.showCount - index - 1], index) - }, (item, index) => JSON.stringify(item) + index) + ForEach(Constants.CACHE_IMG_LIST, (image: string, index?: number) => { + this.albumPicBuilder(this.photoArr[this.showCount - (index || 0) - 1], index) + }, (item: string, index: number) => JSON.stringify(item) + index) } .width(Constants.FULL_PERCENT) .height(Constants.FULL_PERCENT) diff --git a/ETSUI/FlexLayout/README.md b/ETSUI/FlexLayout/README.md index 4e60a6bebb912bbf2acba1d46c306fa2297577bd..2bc293e1e28b20a178e71ec1e65c2cef40c195b3 100644 --- a/ETSUI/FlexLayout/README.md +++ b/ETSUI/FlexLayout/README.md @@ -20,13 +20,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -274,7 +274,7 @@ export default struct FlexLayout { ForEach(this.searchArr, (item: string) => { Text(`${item}`) ... - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } } ... diff --git a/ETSUI/FlexLayout/entry/src/main/ets/view/FlexLayout.ets b/ETSUI/FlexLayout/entry/src/main/ets/view/FlexLayout.ets index a6254cef0cf0ccd38c784766526946dbf794aded..c385050154ea875ac2fa3805627352f6de83f022 100644 --- a/ETSUI/FlexLayout/entry/src/main/ets/view/FlexLayout.ets +++ b/ETSUI/FlexLayout/entry/src/main/ets/view/FlexLayout.ets @@ -43,7 +43,7 @@ export default struct FlexLayout { }) .textOverflow({ overflow: TextOverflow.Ellipsis }) .maxLines(StyleConstants.TEXT_MAX_LINE) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } } .margin({ diff --git a/ETSUI/FlexLayout/hvigor/hvigor-config.json5 b/ETSUI/FlexLayout/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/ETSUI/FlexLayout/hvigor/hvigor-config.json5 +++ b/ETSUI/FlexLayout/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/ETSUI/List/README.md b/ETSUI/List/README.md index b9f8125f5db6c62d46f578b83687193ff587dd8a..69f2f46c355ffd2e21a36fc340facf296caec9fe 100644 --- a/ETSUI/List/README.md +++ b/ETSUI/List/README.md @@ -17,13 +17,13 @@ OpenHarmony ArkTS提供了丰富的接口和组件,开发者可以根据实际 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -44,7 +44,7 @@ OpenHarmony ArkTS提供了丰富的接口和组件,开发者可以根据实际 ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 @@ -69,7 +69,6 @@ OpenHarmony ArkTS提供了丰富的接口和组件,开发者可以根据实际 ├──en_US │ └──element │ └──string.json // 英文字符存放位置 - ├──rawfile // 大体积媒体资源存放位置 └──zh_CN └──element └──string.json // 中文字符存放位置 @@ -80,6 +79,7 @@ OpenHarmony ArkTS提供了丰富的接口和组件,开发者可以根据实际 页面使用Navigation与Tabs做页面布局,使用Navigation的title属性实现页面的标题,Tabs做商品内容的分类。示例代码如下: ```typescript +// ListIndex.ets Row() { Navigation() { Column() { @@ -90,6 +90,7 @@ Row() { } .size({ width: LAYOUT_WIDTH_OR_HEIGHT, height: LAYOUT_WIDTH_OR_HEIGHT }) .title(STORE) + .titleMode(NavigationTitleMode.Mini) } .height(LAYOUT_WIDTH_OR_HEIGHT) .backgroundColor($r('app.color.primaryBgColor')) @@ -98,6 +99,7 @@ Row() { 页面分为“精选”、“手机”、“服饰”、“穿搭”、“家居”五个模块,由于本篇CodeLab的主要内容在“精选”部分,故将“精选”部分单独编写代码,其余模块使用ForEach遍历生成。示例代码如下: ```typescript +// TabBarsComponent.ets Tabs() { // 精选模块 TabContent() { @@ -113,11 +115,12 @@ Tabs() { } .width(LAYOUT_WIDTH_OR_HEIGHT) } + ... } .tabBar(this.firstTabBar) // 其他模块 - ForEach(initTabBarData, (item, index) => { + ForEach(initTabBarData, (item: Resource, index?: number) => { TabContent() { Column() { Text(item).fontSize(MAX_FONT_SIZE) @@ -126,9 +129,10 @@ Tabs() { .width(LAYOUT_WIDTH_OR_HEIGHT) .height(LAYOUT_WIDTH_OR_HEIGHT) } - .tabBar(this.otherTabBar(item, index)) + .tabBar(this.otherTabBar(item, index !== undefined ? index : 0)) }) } +... ``` ## 商品列表的懒加载 @@ -136,6 +140,7 @@ Tabs() { 使用Scroll嵌套List做长列表,实现Scroll与List的联动。具体实现代码如下: ```typescript +// TabBarsComponent.ets Scroll() { Column() { // 下拉刷新的组件 @@ -145,10 +150,11 @@ Scroll() { // List的自定义组件 GoodsList() - Text($r('app.string.to_bottom')).fontSize(DEFAULT_16) + Text($r('app.string.to_bottom')).fontSize(NORMAL_FONT_SIZE).fontColor($r('app.color.gray')) } - .width(THOUSANDTH_1000) + .width(LAYOUT_WIDTH_OR_HEIGHT) } +... ``` 商品列表往往数据量很多,如果使用ForEach一次性遍历生成的话,性能不好,所以这里使用LazyForEach进行数据的懒加载。当向下滑动时,需要加载新的数据的时候,再将新的数据加载出来,生成新的列表。 @@ -156,13 +162,14 @@ Scroll() { 通过onTouch事件来触发懒加载行为,当商品列表向下滑动,加载新的数据。示例代码如下: ```typescript -// GoodsListComponent +// GoodsListComponent.ets List({ space:commonConst.LIST_ITEM_SPACE }) { - LazyForEach(this.goodsListData, (item) => { + LazyForEach(this.goodsListData, (item: GoodsListItemType) => { ListItem() { Row() { Column() { Image(item?.goodsImg) + ... } ... // 布局样式 @@ -174,7 +181,10 @@ List({ space:commonConst.LIST_ITEM_SPACE }) { } // 通过Touch事件来触发懒加载 - .onTouch((event:TouchEvent) => { + .onTouch((event?:TouchEvent) => { + if (event === undefined) { + return; + } switch (event.type) { case TouchType.Down: this.startTouchOffsetY = event.touches[0].y; @@ -187,12 +197,11 @@ List({ space:commonConst.LIST_ITEM_SPACE }) { this.goodsListData.pushData(); } break; - default: - break; } }) }) } +... ``` ## 下拉刷新与到底提示 @@ -204,29 +213,28 @@ List({ space:commonConst.LIST_ITEM_SPACE }) { 具体代码如下: ```typescript -putDownRefresh(event:TouchEvent) { +// TabBarsComponent.ets +putDownRefresh(event?:TouchEvent): void { + if (event === undefined) { + return; + } switch (event.type) { case TouchType.Down: - // 记录手指按下的y坐标 this.currentOffsetY = event.touches[0].y; break; case TouchType.Move: - // 根据下拉的偏移量来判断是否刷新 this.refreshStatus = event.touches[0].y - this.currentOffsetY > MAX_OFFSET_Y; break; case TouchType.Cancel: break; case TouchType.Up: - // 模拟刷新效果,并未真实请求数据 - const timer = setTimeout(() => { + this.timer = setTimeout(() => { this.refreshStatus = false; }, REFRESH_TIME) break; - default: - break; } } ... @@ -243,19 +251,20 @@ if (this.refreshStatus) { 具体代码如下: ```typescript +// TabBarsComponent.ets Scroll() { Column() { ... GoodsList() - Text($r('app.string.to_bottom')).fontSize(DEFAULT_16) + Text($r('app.string.to_bottom')).fontSize(NORMAL_FONT_SIZE).fontColor($r('app.color.gray')) } - .width(THOUSANDTH_1000) + .width(LAYOUT_WIDTH_OR_HEIGHT) } .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring) -.width(THOUSANDTH_1000) -.height(THOUSANDTH_1000) -.onTouch((event) => { +.width(LAYOUT_WIDTH_OR_HEIGHT) +.height(LAYOUT_WIDTH_OR_HEIGHT) +.onTouch((event?: TouchEvent) => { this.putDownRefresh(event) }) ``` diff --git a/ETSUI/List/entry/src/main/ets/entryability/EntryAbility.ts b/ETSUI/List/entry/src/main/ets/entryability/EntryAbility.ts index 388509e2f4331345c1d83d9e39333bf9b9ddba2a..3aecb4ac371f214a6dd5208a338a9fb748d89b3d 100644 --- a/ETSUI/List/entry/src/main/ets/entryability/EntryAbility.ts +++ b/ETSUI/List/entry/src/main/ets/entryability/EntryAbility.ts @@ -15,52 +15,56 @@ import hilog from '@ohos.hilog'; import UIAbility from '@ohos.app.ability.UIAbility' -import Window from '@ohos.window' +import type Window from '@ohos.window' +import type Want from '@ohos.app.ability.Want'; +import type AbilityConstant from '@ohos.app.ability.AbilityConstant'; export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); - hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); - hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); - } + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); + hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); + return; + } - onDestroy() { - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); - } + onDestroy(): void { + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } - onWindowStageCreate(windowStage: Window.WindowStage) { - // Main window is created, set main page for this ability - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + onWindowStageCreate(windowStage: Window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); - windowStage.loadContent('pages/ListIndex', (err, data) => { - if (err.code) { - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.ERROR); - hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); - return; - } - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); - }); - } + windowStage.loadContent('pages/ListIndex', (err, data) => { + if (err.code) { + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.ERROR); + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); + }); + return + } - onWindowStageDestroy() { - // Main window is destroyed, release UI related resources - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); - } + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } - onForeground() { - // Ability has brought to foreground - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); - } + onForeground(): void { + // Ability has brought to foreground + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } - onBackground() { - // Ability has back to background - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); - } + onBackground(): void { + // Ability has back to background + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } } diff --git a/ETSUI/List/entry/src/main/ets/view/GoodsListComponent.ets b/ETSUI/List/entry/src/main/ets/view/GoodsListComponent.ets index 9c4c5b26c10f49e07b11eef317b7b8751e8b974f..0313d920ffe594827e5438b4135e3b062176af5c 100644 --- a/ETSUI/List/entry/src/main/ets/view/GoodsListComponent.ets +++ b/ETSUI/List/entry/src/main/ets/view/GoodsListComponent.ets @@ -14,6 +14,7 @@ */ import * as commonConst from '../common/CommonConstants'; +import { GoodsListItemType } from '../viewmodel/InitialData'; import { ListDataSource } from '../viewmodel/ListDataSource'; @Component @@ -25,7 +26,7 @@ export default struct GoodsList { build() { Row() { List({ space: commonConst.LIST_ITEM_SPACE }) { - LazyForEach(this.goodsListData, (item) => { + LazyForEach(this.goodsListData, (item: GoodsListItemType) => { ListItem() { Row() { Column() { @@ -61,7 +62,10 @@ export default struct GoodsList { .height(commonConst.GOODS_LIST_HEIGHT) .width(commonConst.LAYOUT_WIDTH_OR_HEIGHT) } - .onTouch((event: TouchEvent) => { + .onTouch((event?: TouchEvent) => { + if (event === undefined) { + return; + } switch (event.type) { case TouchType.Down: this.startTouchOffsetY = event.touches[0].y; diff --git a/ETSUI/List/entry/src/main/ets/view/TabBarsComponent.ets b/ETSUI/List/entry/src/main/ets/view/TabBarsComponent.ets index cad8f1c43b8eaf00796904f16821ea5859f1185d..59dfc7331c9f29f61c01d8152f8da06f5774e728 100644 --- a/ETSUI/List/entry/src/main/ets/view/TabBarsComponent.ets +++ b/ETSUI/List/entry/src/main/ets/view/TabBarsComponent.ets @@ -43,7 +43,7 @@ export default struct TabBar { .justifyContent(FlexAlign.Center) } - @Builder otherTabBar(content, index) { + @Builder otherTabBar(content: Resource, index: number) { Column() { Text(content) .fontSize(this.tabsIndex === index + 1 ? BIGGER_FONT_SIZE : NORMAL_FONT_SIZE) @@ -54,7 +54,10 @@ export default struct TabBar { .justifyContent(FlexAlign.Center) } - putDownRefresh(event: TouchEvent) { + putDownRefresh(event?: TouchEvent): void { + if (event === undefined) { + return; + } switch (event.type) { case TouchType.Down: this.currentOffsetY = event.touches[0].y; @@ -65,7 +68,6 @@ export default struct TabBar { case TouchType.Cancel: break; case TouchType.Up: - // Only simulation effect, no data request this.timer = setTimeout(() => { this.refreshStatus = false; @@ -95,13 +97,13 @@ export default struct TabBar { .edgeEffect(EdgeEffect.Spring) .width(LAYOUT_WIDTH_OR_HEIGHT) .height(LAYOUT_WIDTH_OR_HEIGHT) - .onTouch((event) => { + .onTouch((event?: TouchEvent) => { this.putDownRefresh(event); }) } .tabBar(this.firstTabBar) - ForEach(initTabBarData, (item, index) => { + ForEach(initTabBarData, (item: Resource, index?: number) => { TabContent() { Column() { Text(item).fontSize(MAX_FONT_SIZE) @@ -110,7 +112,7 @@ export default struct TabBar { .width(LAYOUT_WIDTH_OR_HEIGHT) .height(LAYOUT_WIDTH_OR_HEIGHT) } - .tabBar(this.otherTabBar(item, index)) + .tabBar(this.otherTabBar(item, index !== undefined ? index : 0)) }) } .onChange((index: number) => { diff --git a/ETSUI/List/entry/src/main/ets/viewmodel/ListDataSource.ets b/ETSUI/List/entry/src/main/ets/viewmodel/ListDataSource.ets index 107e719ec0fdda9ac89e5d816a7d05c6d160564b..c5d34e3726dbc3761ee2369117b736ae32b12993 100644 --- a/ETSUI/List/entry/src/main/ets/viewmodel/ListDataSource.ets +++ b/ETSUI/List/entry/src/main/ets/viewmodel/ListDataSource.ets @@ -19,10 +19,10 @@ import { MAGNIFICATION, MAX_DATA_LENGTH } from '../common/CommonConstants'; /** * create a List range */ -const createListRange = () => { - let result = []; +const createListRange = (): GoodsListItemType[] => { + let result = new Array(); for (let i = 0; i < MAGNIFICATION; i++) { - result = [...result, ...goodsInitialList]; + result = result.concat(goodsInitialList); } return result; } @@ -37,7 +37,7 @@ class BasicDataSource implements IDataSource { return 0; } - public getData(index: number): GoodsListItemType { + public getData(index: number): GoodsListItemType | undefined { return undefined; } @@ -98,7 +98,7 @@ export class ListDataSource extends BasicDataSource { public pushData(): void { if(this.listData.length < MAX_DATA_LENGTH) { - this.listData = [...this.listData, ...goodsInitialList]; + this.listData.concat(goodsInitialList); this.notifyDataAdd(this.listData.length - 1); } } diff --git a/ETSUI/List/hvigor/hvigor-config.json5 b/ETSUI/List/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/ETSUI/List/hvigor/hvigor-config.json5 +++ b/ETSUI/List/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/ETSUI/List_HDC/README.md b/ETSUI/List_HDC/README.md index ffdc6b817cad0621210915487720acebaf0dab68..703f83231097f8eae3ec1a45e510ed9187f5398f 100644 --- a/ETSUI/List_HDC/README.md +++ b/ETSUI/List_HDC/README.md @@ -8,45 +8,44 @@ ### 相关概念 -- [@CustomDialog](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-common-components-custom-dialog.md):@CustomDialog装饰器用于装饰自定义弹窗。 -- [List](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md/):List是常用的滚动类容器组件之一,它按照水平或者竖直方向线性排列子组件, List的子组件必须是ListItem,它的宽度默认充满List的宽度。 -- [TimePicker](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-timepicker.md):TimePicker是选择时间的滑动选择器组件,默认以 00:00 至 23:59 的时间区创建滑动选择器。 -- [Toggle](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-toggle.md):组件提供勾选框样式、状态按钮样式及开关样式。 -- [Router](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-router.md):通过不同的url访问不同的页面,包括跳转到应用内的指定页面、用应用内的某个页面替换当前页面、返回上一页面或指定的页面等。 - +- [@CustomDialog](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-common-components-custom-dialog.md):@CustomDialog装饰器用于装饰自定义弹窗。 +- [List](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md/):List是常用的滚动类容器组件之一,它按照水平或者竖直方向线性排列子组件, List的子组件必须是ListItem,它的宽度默认充满List的宽度。 +- [TimePicker](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-timepicker.md):TimePicker是选择时间的滑动选择器组件,默认以 00:00 至 23:59 的时间区创建滑动选择器。 +- [Toggle](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-toggle.md):组件提供勾选框样式、状态按钮样式及开关样式。 +- [Router](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-router.md):通过不同的url访问不同的页面,包括跳转到应用内的指定页面、用应用内的某个页面替换当前页面、返回上一页面或指定的页面等。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 -- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: -1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以3.2 Release版本为例: +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以3.2 Release版本为例: ![](figures/zh-cn_image_0000001405854998.png) -2. 搭建烧录环境。 - 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) - 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) -3. 搭建开发环境。 - 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 - 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。 - 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 @@ -57,7 +56,7 @@ │ │ ├──BroadCast.ets // 事件发布订阅管理器 │ │ └──Log.ets // 日志打印 │ ├──entryability -│ │ └──EntryAbility.ts // 应用入口,承载应用的生命周期 +│ │ └──EntryAbility.ts // 应用入口,承载应用的生命周期 │ ├──model │ │ ├──EventSourceManager.ets // 事件资源管理器 │ │ ├──TaskInfo.ets // 任务信息存放 @@ -97,7 +96,7 @@ 使用Navigation以及List组件构成元素,使用ForEach遍历生成具体列表。这里是Navigation构成页面导航: ```typescript -// TaskIndexPage.ets +// ListIndexPage.ets Navigation() { Column() { @@ -116,11 +115,12 @@ Navigation() { ```typescript // TaskList.ets List({ space:commonConst.LIST_ITEM_SPACE }) { - ForEach(this.taskList, (item) => { + ForEach(this.taskList, (item: TaskListItem) => { ListItem() { Row() { Row() { Image(item?.icon) + ... Text(item?.taskName) ... } @@ -129,19 +129,18 @@ List({ space:commonConst.LIST_ITEM_SPACE }) { // 状态显示 if (item?.isOpen) { Text($r('app.string.already_open')) + ... } - Image($rawfile('task/right_grey.png')) - .width(commonConst.DEFAULT_8) - .height(commonConst.DEFAULT_16) + Image($r('app.media.right_grey')) + ... } ... } ... - // 路由跳转到任务编辑页 .onClick(() => { - router.push({ - url: 'pages/task/TaskEdit', + router.pushUrl({ + url: 'pages/TaskEditPage', params: { params: formatParams(item), } @@ -173,6 +172,7 @@ Navigation() { } .size({ width:THOUSANDTH_1000, height:THOUSANDTH_1000 }) .title(EDIT_TASK_TITLE) +.titleMode(NavigationTitleMode.Mini) ``` 自定义组件由List以及其子组件ListItem构成: @@ -202,18 +202,19 @@ List({ space:commonConst.LIST_ITEM_SPACE }) { ... } .width(commonConst.THOUSANDTH_940) -.margin({ bottom:commonConst.THOUSANDTH_400 }) ``` 列表的每一项做了禁用判断,需要任务打开才可以点击编辑: ```typescript +// TaskDetail.ets .enabled(this.settingParams?.isOpen) ``` 一些特殊情况的禁用,如每日微笑、每日刷牙的目标设置不可编辑: ```typescript +// TaskDetail.ets .enabled( this.settingParams?.isOpen && (this.settingParams?.taskID !== taskType.smile) @@ -224,12 +225,14 @@ List({ space:commonConst.LIST_ITEM_SPACE }) { 提醒时间在开启提醒打开之后才可以编辑: ```typescript +// TaskDetail.ets .enabled(this.settingParams?.isOpen && this.settingParams?.isAlarm) ``` 设置完成之后,点击完成按钮,此处为了模拟效果,并不与数据库产生交互,因此直接弹出提示“设置完成!!!”。 ```typescript +// TaskDetail.ets finishTaskEdit() { prompt.showToast({ message: commonConst.SETTING_FINISHED_MESSAGE @@ -244,7 +247,7 @@ finishTaskEdit() { CustomDialogView引入实例并注册事件: ```typescript -// TaskSettingDialog.ets +// CustomDialogView.ets targetSettingDialog = new CustomDialogController({ builder: TargetSettingDialog(), autoCancel: true, @@ -255,18 +258,21 @@ targetSettingDialog = new CustomDialogController({ // 注册事件 this.broadCast.on( - BroadCastType.SHOW_TARGETSETTING_DIALOG, - function () { - self.targetSettingDialog.open(); + BroadCastType.SHOW_FREQUENCY_DIALOG, + () => { + this.FrequencyDialogController.open(); }) ``` 点击对应的编辑项触发: ```typescript +// TaskDetail.ets .onClick(() => { - this.broadCast.emit( - BroadCastType.SHOW_TARGETSETTING_DIALOG); + if (this.broadCast !== undefined) { + this.broadCast.emit( + BroadCastType.SHOW_TARGET_SETTING_DIALOG); + } }) ``` @@ -274,9 +280,9 @@ this.broadCast.on( 因为任务目标设置有三种类型: -- 早睡早起的时间 -- 喝水的量度 -- 吃苹果的个数 +- 早睡早起的时间 +- 喝水的量度 +- 吃苹果的个数 如下图所示: @@ -286,16 +292,14 @@ this.broadCast.on( ```typescript // TaskSettingDialog.ets -if ([taskType.getup, taskType.sleepEarly].indexOf(this.settingParams?.taskID) - > commonConst.HAS_NO_INDEX) { +if ([taskType.getup, taskType.sleepEarly].indexOf(this.settingParams?.taskID) > commonConst.HAS_NO_INDEX) { TimePicker({ - selected:commonConst.DEFAULT_SELECTED_TIME, + selected:commonConst.DEFAULT_SELECTED_TIME }) ... } else { - TextPicker({ range:this.settingParams?.taskID === taskType.drinkWater - ? this.drinkRange - : this.appleRange }) + TextPicker({ range:this.settingParams?.taskID === taskType.drinkWater ? this.drinkRange : this.appleRange, + value: this.settingParams.targetValue}) ... } ``` @@ -304,11 +308,10 @@ if ([taskType.getup, taskType.sleepEarly].indexOf(this.settingParams?.taskID) ```typescript // TaskSettingDialog.ets - // 校验规则 compareTime(startTime: string, endTime: string) { - if (returnTimeStamp(this.currentTime) < returnTimeStamp(startTime) - || returnTimeStamp(this.currentTime) > returnTimeStamp(endTime)) { + if (returnTimeStamp(this.currentTime) < returnTimeStamp(startTime) || + returnTimeStamp(this.currentTime) > returnTimeStamp(endTime)) { // 弹出提示 prompt.showToast({ @@ -336,11 +339,7 @@ this.settingParams.targetValue = this.currentValue; 您已经完成了本次Codelab的学习,并了解到以下知识点: -1. 使用List组件实现列表布局。 -2. 使用@CustomDialog实现自定义弹窗。 +1. 使用List组件实现列表布局。 +2. 使用@CustomDialog实现自定义弹窗。 ![](figures/彩带动效.gif) - - - - diff --git a/ETSUI/List_HDC/entry/oh-package.json5 b/ETSUI/List_HDC/entry/oh-package.json5 index 19b9234a98d43a4711a0fc32cef604159228d3cd..225946cb11a2c405c8dc81eea89c22f923556638 100644 --- a/ETSUI/List_HDC/entry/oh-package.json5 +++ b/ETSUI/List_HDC/entry/oh-package.json5 @@ -7,4 +7,4 @@ "main": "", "version": "1.0.0", "dependencies": {} -} \ No newline at end of file +} diff --git a/ETSUI/List_HDC/entry/src/main/ets/common/utils/BroadCast.ets b/ETSUI/List_HDC/entry/src/main/ets/common/utils/BroadCast.ets index 451aaf7593183c8cb2dbbb62403d0f172fcb10d4..ab8fd61c6d462e98cfba55b13fc18e731642da40 100644 --- a/ETSUI/List_HDC/entry/src/main/ets/common/utils/BroadCast.ets +++ b/ETSUI/List_HDC/entry/src/main/ets/common/utils/BroadCast.ets @@ -14,55 +14,55 @@ */ export class BroadCast { - private callBackArray = []; + private callBackArray: Array void>> = []; - public on(event, callback) { - (this.callBackArray[event] || (this.callBackArray[event] = [])).push(callback); - } + public on(event: BroadCastType, callback: () => void) { + (this.callBackArray[event] || (this.callBackArray[event] = [])).push(callback); + } - public off(event, callback) { - if (event == null) { - this.callBackArray = []; - } - const cbs = this.callBackArray[event]; - if (!cbs) { - return; - } - if (callback == null) { - this.callBackArray[event] = null; - } - let cb; - let len = cbs.length; - for (let i = 0; i < len; i++) { - cb = cbs[i]; - if (cb === callback || cb.fn === callback) { - cbs.splice(i, 1); - break; - } - } + public off(event: BroadCastType | null, callback: () => void) { + if (event === null) { + this.callBackArray = []; + return; } + const cbs: Array<() => void> = this.callBackArray[event]; + if (!cbs) { + return; + } + if (callback === null) { + this.callBackArray[event] = null; + } + let cb: () => void; + let len = cbs.length; + for (let i = 0; i < len; i++) { + cb = cbs[i]; + if (cb === callback) { + cbs.splice(i, 1); + break; + } + } + } - public emit(event, args?: any[]) { - let _self = this; - if (!this.callBackArray[event]) { - return; - } - let cbs = [...this.callBackArray[event]]; - if (cbs) { - let len = cbs.length; - for (let i = 0; i < len; i++) { - try { - cbs[i].apply(_self, args); - } catch (e) { - new Error(e); - } - } + public emit(event: BroadCastType) { + if (!this.callBackArray[event]) { + return; + } + let cbs: Array<() => void> = this.callBackArray[event]; + if (cbs) { + let len = cbs.length; + for (let i = 0; i < len; i++) { + try { + cbs[i](); + } catch (e) { + new Error(e); } + } } + } } export enum BroadCastType { - SHOW_TARGET_SETTING_DIALOG = 'showTargetSettingDialog', - SHOW_REMIND_TIME_DIALOG = 'showRemindTimeDialog', - SHOW_FREQUENCY_DIALOG = 'showFrequencyDialog' + SHOW_TARGET_SETTING_DIALOG = 'showTargetSettingDialog', + SHOW_REMIND_TIME_DIALOG = 'showRemindTimeDialog', + SHOW_FREQUENCY_DIALOG = 'showFrequencyDialog' } \ No newline at end of file diff --git a/ETSUI/List_HDC/entry/src/main/ets/model/EventSourceManager.ets b/ETSUI/List_HDC/entry/src/main/ets/model/EventSourceManager.ets index be7c141e9ef897f303d4b438ee28c7ad5bbfca60..ec9a54fae8bbfdf19ed8556a700be6c9104a12be 100644 --- a/ETSUI/List_HDC/entry/src/main/ets/model/EventSourceManager.ets +++ b/ETSUI/List_HDC/entry/src/main/ets/model/EventSourceManager.ets @@ -18,20 +18,20 @@ import { BroadCast } from '../common/utils/BroadCast'; const APP_KEY_GROUP_DATA_SOURCE_MANAGER = 'app_key_group_data_source_manager' export class EventSourceManager { - private broadCast: BroadCast; + private broadCast: BroadCast; - constructor() { - this.broadCast = new BroadCast(); - } + constructor() { + this.broadCast = new BroadCast(); + } - public static getInstance(): EventSourceManager { - if (AppStorage.Get(APP_KEY_GROUP_DATA_SOURCE_MANAGER) == null) { - AppStorage.SetOrCreate(APP_KEY_GROUP_DATA_SOURCE_MANAGER, new EventSourceManager()); - } - return AppStorage.Get(APP_KEY_GROUP_DATA_SOURCE_MANAGER); + public static getInstance(): EventSourceManager | undefined { + if (AppStorage.Get(APP_KEY_GROUP_DATA_SOURCE_MANAGER) == null) { + AppStorage.SetOrCreate(APP_KEY_GROUP_DATA_SOURCE_MANAGER, new EventSourceManager()); } + return AppStorage.Get(APP_KEY_GROUP_DATA_SOURCE_MANAGER); + } - public getBroadCast(): BroadCast { - return this.broadCast; - } + public getBroadCast(): BroadCast { + return this.broadCast; + } } \ No newline at end of file diff --git a/ETSUI/List_HDC/entry/src/main/ets/view/CustomDialogView.ets b/ETSUI/List_HDC/entry/src/main/ets/view/CustomDialogView.ets index 160a6c9fdddedf89cfbb1f686eabc4db4ea51d96..3106943a2a3dff912082999aa8288098e904e29a 100644 --- a/ETSUI/List_HDC/entry/src/main/ets/view/CustomDialogView.ets +++ b/ETSUI/List_HDC/entry/src/main/ets/view/CustomDialogView.ets @@ -47,27 +47,25 @@ export struct CustomDialogView { }); aboutToAppear() { - let self = this; - //目标设置 this.broadCast.on( BroadCastType.SHOW_TARGET_SETTING_DIALOG, - function () { - self.targetSettingDialog.open(); + () => { + this.targetSettingDialog.open(); }) // 提醒时间弹窗 this.broadCast.on( BroadCastType.SHOW_REMIND_TIME_DIALOG, - function () { - self.RemindTimeDialogController.open(); + () => { + this.RemindTimeDialogController.open(); }) // 频率弹窗 this.broadCast.on( BroadCastType.SHOW_FREQUENCY_DIALOG, - function () { - self.FrequencyDialogController.open(); + () => { + this.FrequencyDialogController.open(); }) } diff --git a/ETSUI/List_HDC/entry/src/main/ets/view/TaskDetail.ets b/ETSUI/List_HDC/entry/src/main/ets/view/TaskDetail.ets index 504fc3ccb3a4b7455597c6d6f1a0bcd076cfe51c..78b0e11b3e01e8176a185217ebc9702a7df7e075 100644 --- a/ETSUI/List_HDC/entry/src/main/ets/view/TaskDetail.ets +++ b/ETSUI/List_HDC/entry/src/main/ets/view/TaskDetail.ets @@ -29,7 +29,8 @@ import { BroadCast, BroadCastType } from '../common/utils/BroadCast'; import { EventSourceManager } from '../model/EventSourceManager'; import { CustomDialogView } from './CustomDialogView'; -@Styles function listItemStyle() { +@Styles +function listItemStyle() { .backgroundColor($r('app.color.white')) .height(commonConst.DEFAULT_56) .borderRadius(commonConst.DEFAULT_10) @@ -38,12 +39,12 @@ import { CustomDialogView } from './CustomDialogView'; @Component export default struct TaskDetail { - @Provide broadCast: BroadCast = EventSourceManager.getInstance().getBroadCast(); + @Provide broadCast: BroadCast | undefined = EventSourceManager?.getInstance()?.getBroadCast(); @Provide settingParams: TaskListItem = this.parseRouterParams(); @Provide frequency: string = commonConst.EVERYDAY; - parseRouterParams() { - const routerParams: TaskListItem = JSON.parse(router.getParams()['params']); + parseRouterParams(): TaskListItem { + const routerParams: TaskListItem = JSON.parse((router.getParams() as Record).params as string); return routerParams; } @@ -54,7 +55,9 @@ export default struct TaskDetail { } aboutToAppear() { - this.broadCast.off(null, null); + if (this.broadCast !== undefined) { + this.broadCast.off(null, () => {}); + } } build() { @@ -71,12 +74,14 @@ export default struct TaskDetail { .listItemStyle() .enabled( this.settingParams?.isOpen - && (this.settingParams?.taskID !== taskType.smile) - && (this.settingParams?.taskID !== taskType.brushTeeth) + && (this.settingParams?.taskID !== taskType.smile) + && (this.settingParams?.taskID !== taskType.brushTeeth) ) .onClick(() => { - this.broadCast.emit( - BroadCastType.SHOW_TARGET_SETTING_DIALOG); + if (this.broadCast !== undefined) { + this.broadCast.emit( + BroadCastType.SHOW_TARGET_SETTING_DIALOG); + } }) ListItem() { @@ -91,9 +96,11 @@ export default struct TaskDetail { .listItemStyle() .enabled(this.settingParams?.isOpen && this.settingParams?.isAlarm) .onClick(() => { - this.broadCast.emit( - BroadCastType.SHOW_REMIND_TIME_DIALOG - ); + if (this.broadCast !== undefined) { + this.broadCast.emit( + BroadCastType.SHOW_REMIND_TIME_DIALOG + ); + } }) ListItem() { @@ -102,9 +109,11 @@ export default struct TaskDetail { .listItemStyle() .enabled(this.settingParams?.isOpen) .onClick(() => { - this.broadCast.emit( - BroadCastType.SHOW_FREQUENCY_DIALOG, - ); + if (this.broadCast !== undefined) { + this.broadCast.emit( + BroadCastType.SHOW_FREQUENCY_DIALOG, + ); + } }) } diff --git a/ETSUI/List_HDC/entry/src/main/ets/view/TaskEditListItem.ets b/ETSUI/List_HDC/entry/src/main/ets/view/TaskEditListItem.ets index eb93c32503f3b93cba3c88996c057c261f42e660..0352b0675960ae2bdc0cb153cd43a0651aba7afa 100644 --- a/ETSUI/List_HDC/entry/src/main/ets/view/TaskEditListItem.ets +++ b/ETSUI/List_HDC/entry/src/main/ets/view/TaskEditListItem.ets @@ -33,17 +33,17 @@ import { taskType } from '../model/TaskInfo' .align(Alignment.End) } -@Extend(Text) function targetSettingStyle (isOpen, taskID) { +@Extend(Text) function targetSettingStyle (isOpen: boolean, taskID: number) { .fontColor(isOpen && taskID !== taskType.smile && taskID !== taskType.brushTeeth ? $r('app.color.titleColor') : $r('app.color.disabledColor')) } -@Extend(Text) function remindTimeStyle (isOpen, isAlarm) { +@Extend(Text) function remindTimeStyle (isOpen: boolean, isAlarm: boolean) { .fontColor(isOpen && isAlarm ? $r('app.color.titleColor') : $r('app.color.disabledColor')) } -@Extend(Text) function frequencyStyle (isOpen) { +@Extend(Text) function frequencyStyle (isOpen: boolean) { .fontSize(DEFAULT_12) .flexGrow(1) .margin({ right: DEFAULT_8 }) @@ -85,10 +85,12 @@ export struct TargetSetItem { Text(`${this.settingParams?.targetValue}`) .targetSetCommon() .targetSettingStyle(this.settingParams?.isOpen, this.settingParams?.taskID) + .textAlign(TextAlign.End) } else { Text(`${this.settingParams?.targetValue} ${this.settingParams?.unit} ${PER_DAY}`) .targetSetCommon() .targetSettingStyle(this.settingParams?.isOpen, this.settingParams?.taskID) + .textAlign(TextAlign.End) } Image($r('app.media.right_grey')).width(DEFAULT_8).height(DEFAULT_16); } diff --git a/ETSUI/List_HDC/entry/src/main/ets/view/TaskList.ets b/ETSUI/List_HDC/entry/src/main/ets/view/TaskList.ets index da6d9a1da5b02dc72340eda2b0960114dbb66faa..66f16646706550ceecf3b760ee57bc54492a42cf 100644 --- a/ETSUI/List_HDC/entry/src/main/ets/view/TaskList.ets +++ b/ETSUI/List_HDC/entry/src/main/ets/view/TaskList.ets @@ -24,7 +24,7 @@ export default struct TaskList { build() { List({ space: commonConst.LIST_ITEM_SPACE }) { - ForEach(this.taskList, (item) => { + ForEach(this.taskList, (item: TaskListItem) => { ListItem() { Row() { Row() { @@ -40,7 +40,7 @@ export default struct TaskList { Text($r('app.string.already_open')) .fontSize(commonConst.DEFAULT_16) .flexGrow(1) - .align(Alignment.End) + .textAlign(TextAlign.End) .margin({ right: commonConst.DEFAULT_8 }) .fontColor($r('app.color.titleColor')) } diff --git a/ETSUI/List_HDC/entry/src/main/ets/view/TaskSettingDialog.ets b/ETSUI/List_HDC/entry/src/main/ets/view/TaskSettingDialog.ets index cc73f5ac6b7b15e7f2b5aaf379d4fbde75160c0d..b466202c730f739cb528661b697cef0878063be3 100644 --- a/ETSUI/List_HDC/entry/src/main/ets/view/TaskSettingDialog.ets +++ b/ETSUI/List_HDC/entry/src/main/ets/view/TaskSettingDialog.ets @@ -30,11 +30,10 @@ export struct TargetSettingDialog { currentValue: string = this.settingParams.taskID === taskType.drinkWater ? commonConst.DEFAULT_TEXT : commonConst.DEFAULT_APPLE; currentTime: string = commonConst.DEFAULT_TIME; - private tip: string = ''; compareTime(startTime: string, endTime: string) { if (returnTimeStamp(this.currentTime) < returnTimeStamp(startTime) || - returnTimeStamp(this.currentTime) > returnTimeStamp(endTime)) { + returnTimeStamp(this.currentTime) > returnTimeStamp(endTime)) { prompt.showToast({ message: commonConst.CHOOSE_TIME_OUT_RANGE }) @@ -210,7 +209,7 @@ export struct FrequencyDialog { .width(commonConst.THOUSANDTH_900) List() { - ForEach(this.frequencyChooseRange, (item) => { + ForEach(this.frequencyChooseRange, (item: FrequencyContentType) => { ListItem() { Row() { Text(item?.label).fontSize(commonConst.DEFAULT_20) diff --git a/ETSUI/List_HDC/entry/src/main/ets/viewmodel/FrequencySetting.ets b/ETSUI/List_HDC/entry/src/main/ets/viewmodel/FrequencySetting.ets index bf6d933ae88d51e3b66681bec808bb413a3e6400..f69c71d5661b324db6ba3232bf91b9bd4d195c01 100644 --- a/ETSUI/List_HDC/entry/src/main/ets/viewmodel/FrequencySetting.ets +++ b/ETSUI/List_HDC/entry/src/main/ets/viewmodel/FrequencySetting.ets @@ -13,6 +13,9 @@ * limitations under the License. */ +import { FrequencyContentType } from '../model/TaskInitList'; + + const chineseNumOfWeek: string[] = ['一', '二', '三', '四', '五', '六', '日']; const WEEK: string = '星期'; @@ -22,7 +25,7 @@ export function padTo2Digits(num: number) { } export const frequencyRange = () => { - const frequencyRangeArr = [] + const frequencyRangeArr: FrequencyContentType[] = [] chineseNumOfWeek.forEach((item, index) => { frequencyRangeArr.push({ id: (index + 1), @@ -34,9 +37,11 @@ export const frequencyRange = () => { } export const oneWeekDictFunc = () => { - const oneWeekDict = {}; - chineseNumOfWeek.forEach((item, index) => { - oneWeekDict[index + 1] = `${WEEK}${chineseNumOfWeek[index]}`; + const oneWeekDict: string[] = []; + chineseNumOfWeek.forEach((item:string, index?: number) => { + if (index !== undefined) { + oneWeekDict[index + 1] = `${WEEK}${chineseNumOfWeek[index]}`; + } }); return oneWeekDict; } diff --git a/ETSUI/List_HDC/entry/src/main/ets/viewmodel/TaskTargetSetting.ets b/ETSUI/List_HDC/entry/src/main/ets/viewmodel/TaskTargetSetting.ets index fef0ea5f61fe5b06be9541122bd003840cb002c6..4c9738cc896659e7f7be87f8aac8a20f0ff77994 100644 --- a/ETSUI/List_HDC/entry/src/main/ets/viewmodel/TaskTargetSetting.ets +++ b/ETSUI/List_HDC/entry/src/main/ets/viewmodel/TaskTargetSetting.ets @@ -14,16 +14,16 @@ */ import { - TODAY, - DRINK_STEP, - DRINK_MAX_RANGE, - EAT_APPLE_RANGE, - TIMES_100 + TODAY, + DRINK_STEP, + DRINK_MAX_RANGE, + EAT_APPLE_RANGE, + TIMES_100 } from '../common/constants/CommonConstant'; import { padTo2Digits } from './FrequencySetting'; -export const formatParams = (params) => { - return JSON.stringify(params) +export const formatParams = (params: Object) => { + return JSON.stringify(params) } /** @@ -32,16 +32,16 @@ export const formatParams = (params) => { * @return timestamp */ export const returnTimeStamp = (currentTime: string) => { - const timeString = `${TODAY} ${currentTime}`; - return new Date(timeString).getTime(); + const timeString = `${TODAY} ${currentTime}`; + return new Date(timeString).getTime(); } /** * @description It is used for formatting time and displayed in the form of HH: mm * @param value */ -export const formatTime = (value) => { - return `${padTo2Digits(value?.hour)}:${padTo2Digits(value?.minute)}`; +export const formatTime = (value: TimePickerResult) => { + return `${padTo2Digits(value?.hour ?? 0)}:${padTo2Digits(value?.minute ?? 0)}`; } /** @@ -49,11 +49,11 @@ export const formatTime = (value) => { * @return Array */ export const createDrinkRange = () => { - const drinkRangeArr = [] - for (let i = DRINK_STEP; i <= DRINK_MAX_RANGE; i += DRINK_STEP) { - drinkRangeArr.push(`${i / TIMES_100} L`); - } - return drinkRangeArr; + const drinkRangeArr: string[] = [] + for (let i = DRINK_STEP; i <= DRINK_MAX_RANGE; i += DRINK_STEP) { + drinkRangeArr.push(`${i / TIMES_100} L`); + } + return drinkRangeArr; } /** @@ -61,9 +61,9 @@ export const createDrinkRange = () => { * @return Array */ export const createAppleRange = () => { - const appleRangeArr = [] - for (let i = 1; i <= EAT_APPLE_RANGE; i++) { - appleRangeArr.push(`${i} 个`); - } - return appleRangeArr; + const appleRangeArr: string[] = [] + for (let i = 1; i <= EAT_APPLE_RANGE; i++) { + appleRangeArr.push(`${i} 个`); + } + return appleRangeArr; } \ No newline at end of file diff --git a/ETSUI/List_HDC/hvigor/hvigor-config.json5 b/ETSUI/List_HDC/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/ETSUI/List_HDC/hvigor/hvigor-config.json5 +++ b/ETSUI/List_HDC/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/ETSUI/List_HDC/oh-package.json5 b/ETSUI/List_HDC/oh-package.json5 index 80083f5e17fcd6b8b0da450dc70dfa5e028a2539..3df2dcec847e85f775a45d18c733816a45c278d8 100644 --- a/ETSUI/List_HDC/oh-package.json5 +++ b/ETSUI/List_HDC/oh-package.json5 @@ -9,4 +9,4 @@ "main": "", "version": "1.0.0", "dependencies": {} -} \ No newline at end of file +} diff --git a/ETSUI/MultipleDialog/README.md b/ETSUI/MultipleDialog/README.md index da9981241e571fab8b02d20886a313a2e2f441f1..5d09aad8b5821e1b9bff5f032ed9aa37ddb68051 100644 --- a/ETSUI/MultipleDialog/README.md +++ b/ETSUI/MultipleDialog/README.md @@ -21,13 +21,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -57,8 +57,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ └──HobbyBean.ets // 兴趣爱好bean类 │ │ ├──constants │ │ │ └──CommonConstants.ets // 常量类 │ │ └──utils @@ -68,10 +66,12 @@ │ │ └──EntryAbility.ets // 程序入口类 │ ├──pages │ │ └──HomePage.ets // 主页面 -│ └──view -│ ├──CustomDialogWidget.ets // 自定义弹窗组件 -│ ├──TextCommonWidget.ets // 自定义Text组件 -│ └──TextInputWidget.ets // 自定义TextInput组件 +│ ├──view +│ │ ├──CustomDialogWidget.ets // 自定义弹窗组件 +│ │ ├──TextCommonWidget.ets // 自定义Text组件 +│ │ └──TextInputWidget.ets // 自定义TextInput组件 +│ └──viewmodel +│ └──HobbyModel.ets // 兴趣爱好model类 └──entry/src/main/resources // 资源文件目录 ``` @@ -94,9 +94,9 @@ @Component export default struct TextInputWidget { // 文本框左侧图片 - private inputImage: Resource; + private inputImage?: Resource; // 文本框提示 - private hintText: Resource; + private hintText?: Resource; build() { Row() { @@ -121,11 +121,11 @@ // 显示内容 @Link content: string; // 文字标题左侧图片 - private textImage: Resource; + private textImage?: Resource; // 文本标题 - private title: Resource; + private title?: Resource; // 点击事件回调 - onItemClick: () => void; + onItemClick: () => void = () => {}; build() { Row() { @@ -250,9 +250,9 @@ datePickerDialog(dateCallback) { // 是否显示农历 lunar: false, onAccept: (value: DatePickerResult) => { - let year = value.year; - let month = value.month + CommonConstants.PLUS_ONE; - let day = value.day; + let year = value.year as number; + let month = value.month as number + CommonConstants.PLUS_ONE; + let day = value.day as number; let birthdate: string = this.getBirthDateValue(year, month, day); dateCallback(birthdate); } @@ -294,7 +294,7 @@ build() { ```typescript // CommonUtils.ets -textPickerDialog(sexArray: Resource, sexCallback) { +textPickerDialog(sexArray: Resource, sexCallback: (sexValue: string) => void) { TextPickerDialog.show({ range: sexArray, selected: 0, @@ -341,7 +341,7 @@ build() { ```typescript // CustomDialogWeight.ets - @State hobbyBeans: hobbyBean[] = []; + @State hobbyModels: HobbyModel[] = []; aboutToAppear() { let context: Context = getContext(this); @@ -355,10 +355,10 @@ build() { Logger.error(CommonConstants.TAG_CUSTOM, 'error = ' + JSON.stringify(error)); } else { hobbyArray.forEach((hobbyItem: string) => { - let hobbyBean = new HobbyBean(); - hobbyBean.label = hobbyItem; - hobbyBean.isChecked = false; - this.hobbyBeans.push(hobbyBean); + let hobbyModel = new HobbyModel(); + hobbyModel.label = hobbyItem; + hobbyModel.isChecked = false; + this.hobbyModels.push(hobbyModel); }); } }); @@ -369,18 +369,18 @@ build() { ```typescript // CustomDialogWeight.ets - @State hobbyBeans: hobbyBean[] = []; + @State hobbyModels: HobbyModel[] = []; @Link hobbies: string; // 处理自定义弹窗选项结果 - setHobbiesValue(hobbyBeans: HobbyBean[]) { - if (CommonUtils.isEmptyArr(hobbyBeans)) { - Logger.error(CommonConstants.TAG_CUSTOM, 'hobbyBeans length is 0'); + setHobbiesValue(hobbyModels: HobbyModel[]) { + if (CommonUtils.isEmptyArr(hobbyModels)) { + Logger.error(CommonConstants.TAG_CUSTOM, 'hobbyModels length is 0'); return; } let hobbiesText: string = ''; - hobbiesText = hobbyBeans.filter((isCheckItem: HobbyBean) => isCheckItem?.isChecked) - .map((checkedItem: HobbyBean) => { + hobbiesText = hobbyModels.filter((isCheckItem: HobbyModel) => isCheckItem?.isChecked) + .map((checkedItem: HobbyModel) => { return checkedItem.label; }) .join(CommonConstants.COMMA); @@ -403,7 +403,7 @@ build() { Button($r('app.string.definite_button')) .dialogButtonStyle() .onClick(() => { - this.setHobbiesValue(this.hobbyBeans); + this.setHobbiesValue(this.hobbyModels); this.controller.close(); }) } diff --git a/ETSUI/MultipleDialog/entry/src/main/ets/common/utils/CommonUtils.ets b/ETSUI/MultipleDialog/entry/src/main/ets/common/utils/CommonUtils.ets index 25e4051af7c1d475eb6430fdf97462e794889f4f..3244bc0f388e5b56172c4ecb370e26d3597a02d8 100644 --- a/ETSUI/MultipleDialog/entry/src/main/ets/common/utils/CommonUtils.ets +++ b/ETSUI/MultipleDialog/entry/src/main/ets/common/utils/CommonUtils.ets @@ -54,16 +54,16 @@ export class CommonUtils { /** * Date dialog dialog */ - datePickerDialog(dateCallback) { + datePickerDialog(dateCallback: (birthValue: string) => void) { DatePickerDialog.show({ start: new Date(CommonConstants.START_TIME), end: new Date(), selected: new Date(CommonConstants.SELECT_TIME), lunar: false, onAccept: (value: DatePickerResult) => { - let year = value.year; - let month = value.month + CommonConstants.PLUS_ONE; - let day = value.day; + let year = value.year as number; + let month = value.month as number + CommonConstants.PLUS_ONE; + let day = value.day as number; let birthdate: string = this.getBirthDateValue(year, month, day); dateCallback(birthdate); } @@ -73,7 +73,7 @@ export class CommonUtils { /** * Text dialog dialog */ - textPickerDialog(sexArray: Resource, sexCallback) { + textPickerDialog(sexArray: Resource, sexCallback: (sexValue: string) => void) { if (this.isEmptyArr(sexArray)) { Logger.error(CommonConstants.TAG_COMMON_UTILS, 'sex is null'); return; @@ -110,7 +110,7 @@ export class CommonUtils { * @param {object} obj * @return {boolean} true(empty) */ - isEmpty(obj): boolean { + isEmpty(obj: Object): boolean { return obj === undefined || obj === null || obj === ''; } @@ -120,8 +120,8 @@ export class CommonUtils { * @param {Array}array * @return {boolean} true(empty) */ - isEmptyArr(array): boolean { - return this.isEmpty(array) || array.length === 0; + isEmptyArr(array: Object | Object[]): boolean { + return this.isEmpty(array) || (array as Object[]).length === 0; } } diff --git a/ETSUI/MultipleDialog/entry/src/main/ets/common/utils/Logger.ets b/ETSUI/MultipleDialog/entry/src/main/ets/common/utils/Logger.ets index 7701200f06ff6737c0e813c674f989b695c4ab55..f44152b0bcc1c2de44c7bd1dd85a3a6ea734c36c 100644 --- a/ETSUI/MultipleDialog/entry/src/main/ets/common/utils/Logger.ets +++ b/ETSUI/MultipleDialog/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/ETSUI/MultipleDialog/entry/src/main/ets/view/CustomDialogWidget.ets b/ETSUI/MultipleDialog/entry/src/main/ets/view/CustomDialogWidget.ets index 97502fc315c3a2260d7b58f226750daada3bba0b..f93e5cb3f8411be70c85ac48322c9b0c684eb7f8 100644 --- a/ETSUI/MultipleDialog/entry/src/main/ets/view/CustomDialogWidget.ets +++ b/ETSUI/MultipleDialog/entry/src/main/ets/view/CustomDialogWidget.ets @@ -14,15 +14,15 @@ */ import Logger from '../common/utils/Logger'; -import HobbyBean from '../common/bean/HobbyBean'; +import HobbyModel from '../viewmodel/HobbyModel'; import CommonUtils from '../common/utils/CommonUtils'; import CommonConstants from '../common/constants/CommonConstants'; @CustomDialog export default struct CustomDialogWidget { - @State hobbyBeans: HobbyBean[] = []; + @State hobbyModels: HobbyModel[] = []; @Link hobbies: string; - private controller: CustomDialogController; + private controller?: CustomDialogController; aboutToAppear() { let context: Context = getContext(this); @@ -36,10 +36,10 @@ export default struct CustomDialogWidget { Logger.error(CommonConstants.TAG_CUSTOM, 'error = ' + JSON.stringify(error)); } else { hobbyArray.forEach((hobbyItem: string) => { - let hobbyBean = new HobbyBean(); - hobbyBean.label = hobbyItem; - hobbyBean.isChecked = false; - this.hobbyBeans.push(hobbyBean); + let hobbyModel = new HobbyModel(); + hobbyModel.label = hobbyItem; + hobbyModel.isChecked = false; + this.hobbyModels.push(hobbyModel); }); } }); @@ -48,16 +48,16 @@ export default struct CustomDialogWidget { /** * Set hobbies value * - * @param {HobbyBean[]} hobby bean array + * @param {HobbyModel[]} hobby model array */ - setHobbiesValue(hobbyBeans: HobbyBean[]) { - if (CommonUtils.isEmptyArr(hobbyBeans)) { - Logger.error(CommonConstants.TAG_HOME, 'hobbyBeans length is 0'); + setHobbiesValue(hobbyModels: HobbyModel[]) { + if (CommonUtils.isEmptyArr(hobbyModels)) { + Logger.error(CommonConstants.TAG_HOME, 'hobbyModels length is 0'); return; } let hobbiesText: string = ''; - hobbiesText = hobbyBeans.filter((isCheckItem: HobbyBean) => isCheckItem?.isChecked) - .map((checkedItem: HobbyBean) => { + hobbiesText = hobbyModels.filter((isCheckItem: HobbyModel) => isCheckItem?.isChecked) + .map((checkedItem: HobbyModel) => { return checkedItem.label; }) .join(CommonConstants.COMMA); @@ -76,7 +76,7 @@ export default struct CustomDialogWidget { .alignSelf(ItemAlign.Start) .margin({ left: $r('app.float.title_left_distance') }) List() { - ForEach(this.hobbyBeans, (itemHobby: HobbyBean) => { + ForEach(this.hobbyModels, (itemHobby: HobbyModel) => { ListItem() { Row() { Text(itemHobby.label) @@ -100,7 +100,7 @@ export default struct CustomDialogWidget { bottom: $r('app.float.options_bottom_distance') }) } - }, itemHobby => itemHobby.label) + }, (itemHobby: HobbyModel): string => itemHobby.label) } .margin({ top: $r('app.float.list_top_distance'), @@ -119,7 +119,7 @@ export default struct CustomDialogWidget { Button($r('app.string.cancel_button')) .dialogButtonStyle() .onClick(() => { - this.controller.close(); + this.controller?.close(); }) Blank() .backgroundColor($r('app.color.custom_blank_color')) @@ -129,8 +129,8 @@ export default struct CustomDialogWidget { Button($r('app.string.definite_button')) .dialogButtonStyle() .onClick(() => { - this.setHobbiesValue(this.hobbyBeans); - this.controller.close(); + this.setHobbiesValue(this.hobbyModels); + this.controller?.close(); }) } } diff --git a/ETSUI/MultipleDialog/entry/src/main/ets/view/TextCommonWidget.ets b/ETSUI/MultipleDialog/entry/src/main/ets/view/TextCommonWidget.ets index a436ce0fb9119b5852fb178fe062d939bfe3254f..4bb72bf4450697791b38e3f17ef4b9c28d3c05b3 100644 --- a/ETSUI/MultipleDialog/entry/src/main/ets/view/TextCommonWidget.ets +++ b/ETSUI/MultipleDialog/entry/src/main/ets/view/TextCommonWidget.ets @@ -18,13 +18,13 @@ import CommonConstants from '../common/constants/CommonConstants'; @Component export default struct TextCommonWidget { @Link content: string; - private textImage: Resource; - private title: Resource; - onItemClick: () => void; + private textImage?: Resource; + private title?: Resource; + onItemClick: () => void = () => {}; build() { Row() { - Image(this.textImage) + Image(this.textImage as Resource) .width($r('app.float.text_image_size')) .height($r('app.float.text_image_size')) .margin({ left: $r('app.float.image_left_distance') }) diff --git a/ETSUI/MultipleDialog/entry/src/main/ets/view/TextInputWidget.ets b/ETSUI/MultipleDialog/entry/src/main/ets/view/TextInputWidget.ets index 2d4f824bb280c4dd17cb9261dd8dd9f549e7ede0..453389aab9c2b22117c19b05b73ce46356181af0 100644 --- a/ETSUI/MultipleDialog/entry/src/main/ets/view/TextInputWidget.ets +++ b/ETSUI/MultipleDialog/entry/src/main/ets/view/TextInputWidget.ets @@ -17,12 +17,12 @@ import CommonConstants from '../common/constants/CommonConstants'; @Component export default struct TextInputWidget { - private inputImage: Resource; - private hintText: Resource; + private inputImage?: Resource; + private hintText?: Resource; build() { Row() { - Image(this.inputImage) + Image(this.inputImage as Resource) .width($r('app.float.input_image_size')) .height($r('app.float.input_image_size')) .margin({ left: $r('app.float.input_image_left') }) diff --git a/ETSUI/MultipleDialog/entry/src/main/ets/common/bean/HobbyBean.ets b/ETSUI/MultipleDialog/entry/src/main/ets/viewmodel/HobbyModel.ets similarity index 86% rename from ETSUI/MultipleDialog/entry/src/main/ets/common/bean/HobbyBean.ets rename to ETSUI/MultipleDialog/entry/src/main/ets/viewmodel/HobbyModel.ets index 1bb82dfd6d99483d9705ecc197380f1769cb48ed..8109f151690d0a4b9b511986f4d95012a863c6e2 100644 --- a/ETSUI/MultipleDialog/entry/src/main/ets/common/bean/HobbyBean.ets +++ b/ETSUI/MultipleDialog/entry/src/main/ets/viewmodel/HobbyModel.ets @@ -14,16 +14,16 @@ */ /** - * Hobby info bean. + * Hobby info model. */ -export default class HobbyBean { +export default class HobbyModel { /** * Hobby title */ - label: string; + label: string = ''; /** * Hobby check status */ - isChecked: boolean; + isChecked: boolean = false; } \ No newline at end of file diff --git a/ETSUI/MultipleDialog/hvigor/hvigor-config.json5 b/ETSUI/MultipleDialog/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/MultipleDialog/hvigor/hvigor-config.json5 +++ b/ETSUI/MultipleDialog/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } -} +} \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/README.md b/ETSUI/OHLayoutAlign/README.md index 43b43c2389a9f5276ab4f94643ddf6176e523a6b..424dc6c5c17569064c0566f07cb106e73e1e7e17 100644 --- a/ETSUI/OHLayoutAlign/README.md +++ b/ETSUI/OHLayoutAlign/README.md @@ -4,6 +4,8 @@ 基于ArkTS扩展的声明式开发范式,实现Flex、Column、Row和Stack四种常用布局容器对齐方式。 +效果图如下: + ![](figures/zh-cn_image_0000001409408710.gif) ### 相关概念 @@ -19,13 +21,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -48,18 +50,15 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──ContainerModuleItem.ets // 属性模块对象 -│ │ │ └──IndexListItem.ets // 首页列表数据对象 │ │ └──constants │ │ └──CommonConstants.ets // 样式常量类 │ ├──entryability -│ │ └──EntryAbility.ts // 程序入口类 +│ │ └──EntryAbility.ts // 程序入口类 │ ├──pages │ │ ├──LayoutAlignIndex.ets // 主界面 │ │ └──Second.ets // 视频播放界面 @@ -79,7 +78,9 @@ │ │ └──StackComponent.ets // 自定义Stack容器子元素文件 │ └──viewmodel │ ├──AttributeModuleData.ets // 属性模块数据 -│ └──IndexData.ets // 首页数据 +│ ├──ContainerModuleItem.ets // 属性模块对象 +│ ├──IndexData.ets // 首页数据 +│ └──IndexListItem.ets // 首页数据对象 └──entry/src/main/resource // 应用静态资源目录 ``` @@ -96,34 +97,36 @@ 2. 在LayoutAlignIndex.ets主界面中包含显示四种容器对齐方式的入口。 ```typescript + // LayoutAlignIndex.ets @Entry @Component struct LayoutAlignIndex { private indexList: IndexListItem[] = getIndexList(); + build() { Column() { - // 标题 Text($r('app.string.index_title')) ... - List() { - ForEach(this.indexList, (item) => { + ForEach(this.indexList, (item: IndexListItem) => { ListItem() { ListItemComp({ item: item }) .margin({ top: MARGIN_FONT_SIZE_SPACE.SECOND_MARGIN }) } - }, item => JSON.stringify(item)) + }, (item: IndexListItem) => JSON.stringify(item)) } + .height(ALL_PERCENT) + .width(ALL_PERCENT) .listDirection(Axis.Vertical) .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) } - ... + ... } } @Component struct ListItemComp { - ... + ... } ``` @@ -142,6 +145,7 @@ 具体代码如下: ```typescript + // ColumnShowList.ets @Component export struct ColumnShowList { @Consume currentColumnJustifyContent: FlexAlign; @@ -149,27 +153,24 @@ build() { Column() { - // Column中元素对齐方式布局 Column() { - ForEach(LIST, (item) => { + ForEach(LIST, (item: number) => { CommonItem({ item: item }) - }, item => JSON.stringify(item)) + }, (item: number) => JSON.stringify(item)) } ... // 设置主轴对齐方式 ColumnMainAlignRadioList() - .margin({ top:MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) + .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) // 设置交叉轴对齐方式 ColumnAxisAlignRadioList() - .margin({ top:MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) + .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) } - .layoutWeight(1) - .height(ALL_PERCENT) - .width(ALL_PERCENT) + ... } } ``` - + 其中ColumnMainAlignRadioList子组件和ColumnAxisAlignRadioList子组件分别是设置主轴对齐方式单选框列表和设置交叉轴对齐方式单选框列表,并且在FlexShowList,RowShowList和StackComponent中都存在代码结构类似的子组件,只是设置的属性和参数单选框列表不同,后面不在重复其详细代码,这里选择其中一个单选框列表子组件来显示。 ![](figures/zh-cn_image_0000001408157208.png) @@ -177,13 +178,14 @@ 具体代码如下: ```typescript +// ColumnMainAlignRadioList.ets @Component export struct ColumnMainAlignRadioList { ... build() { Column({ space: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) { -     // 单选框列表模块名称 + // 单选框列表模块名称 Row() { Text(this.moduleName) .fontSize(MARGIN_FONT_SIZE_SPACE.FOURTH_MARGIN) @@ -192,16 +194,15 @@ Flex({ direction: FlexDirection.Row, - justifyContent: FlexAlign.SpaceBetween , - wrap: FlexWrap.NoWrap + justifyContent: FlexAlign.SpaceBetween, + wrap: FlexWrap.NoWrap }) { - ForEach(this.radioList, (item, index) => { - MainAlignRadioItem({ textName: item, groupName: this.groupName, - isChecked: index === 0 ? true : false }) + ForEach(this.radioList, (item: string, index?: number) => { + MainAlignRadioItem({ textName: item, groupName: this.groupName, isChecked: index === 0 ? true : false }) .margin({ right: MARGIN_FONT_SIZE_SPACE.COMMON_MARGIN }) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } - ... + ... } ... } @@ -214,7 +215,9 @@ build() { Row() { Radio({ value: this.textName, group: this.groupName }) - ... + .checked(this.isChecked) + .height((MARGIN_FONT_SIZE_SPACE.SECOND_MARGIN)) + .width((MARGIN_FONT_SIZE_SPACE.SECOND_MARGIN)) .onClick(() => { switch (this.textName) { case ATTRIBUTE.START: @@ -243,6 +246,7 @@ 具体代码如下: ```typescript + // FlexShowList.ets @Component export struct FlexShowList { @Consume list: number[]; @@ -254,26 +258,26 @@ build() { Column() { - // Flex中元素对齐方式布局 Flex({ - // 参数设置 - ... + // 参数设置 + ... }) { - ForEach(this.list, (item) => { + ForEach(this.list, (item: number) => { CommonItem({ item: item }) - }, item => JSON.stringify(item)) + }, (item: number) => JSON.stringify(item)) } ... // 设置主轴方向 - FlexMainDirectionRadioList().margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) - // 设置主轴对齐方式 - FlexMainAlignRadioList().margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) + FlexMainDirectionRadioList() + .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) + // 设置主轴方向 + FlexMainAlignRadioList() + .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) // 设置交叉轴对齐方式 - FlexAxisAlignRadioList().margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) + FlexAxisAlignRadioList() + .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) } - .layoutWeight(1) - .height(ALL_PERCENT) - .width(ALL_PERCENT) + ... } } ``` @@ -285,6 +289,7 @@ 代码如下: ```typescript + // RowShowList.ets @Component export struct RowShowList { @Consume currentRowJustifyContent: FlexAlign; @@ -292,11 +297,10 @@ build() { Column() { - // Row中元素对齐方式布局 Row() { - ForEach(LIST, (item) => { + ForEach(LIST, (item: number) => { CommonItem({ item: item }) - }, item => JSON.stringify(item)) + }, (item: number) => JSON.stringify(item)) } ... // 设置主轴对齐方式 @@ -306,13 +310,11 @@ RowAxisAlignRadioList() .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) } - .layoutWeight(1) - .height(ALL_PERCENT) - .width(ALL_PERCENT) + ... } } ``` - + 5. 在StackComponent.ets中,自定组件StackComponent主要效果是在Stack布局容器中,设置不同对齐方式属性时,容器内堆叠元素的对齐方式。 ![](figures/zh-cn_image_0000001407837816.png) @@ -320,15 +322,13 @@ 代码如下: ```typescript + // StackComponent.ets @Component export struct StackComponent { - @Consume currentStackAlignContent: Alignment; - @Consume message: string ; - @State textAl: TextAlign = TextAlign.Center; + ... build() { Column() { - // Stack中元素对齐方式布局 Stack({ alignContent: this.currentStackAlignContent }) { Text('') .width(ALL_PERCENT) @@ -345,47 +345,52 @@ StackAlignRadioList() .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) } - .layoutWeight(1) - .height(ALL_PERCENT) - .width(ALL_PERCENT) + ... } } ``` + +6. 在CommonComponent.ets中,自定义组件CommonItem,代码如下: -6. 在CommonComponent.ets中,自定义组件CommonItem,代码如下: - - ```typescript - @Component - export struct CommonItem { - private item: number; - - build() { - Text(this.item.toString()) - .fontSize(MARGIN_FONT_SIZE_SPACE.FIFTH_MARGIN) - .width(MARGIN_FONT_SIZE_SPACE.NINTH_MARGIN) - .height(MARGIN_FONT_SIZE_SPACE.NINTH_MARGIN) - .fontColor($r("app.color.show_list_fontColor")) - .textAlign(TextAlign.Center) - .align(Alignment.Center) - .backgroundColor($r("app.color.white")) - .borderRadius(MARGIN_FONT_SIZE_SPACE.COMMON_PADDING) - .margin(MARGIN_FONT_SIZE_SPACE.COMMON_PADDING) - } - } - ``` + ```typescript + // CommonComponent.ets + @Component + export struct CommonItem { + private item: number = 0; + + build() { + Text(this.item.toString()) + .fontSize(MARGIN_FONT_SIZE_SPACE.FIFTH_MARGIN) + .width(MARGIN_FONT_SIZE_SPACE.NINTH_MARGIN) + .height(MARGIN_FONT_SIZE_SPACE.NINTH_MARGIN) + .fontColor($r("app.color.show_list_fontColor")) + .textAlign(TextAlign.Center) + .align(Alignment.Center) + .backgroundColor($r("app.color.white")) + .borderRadius(MARGIN_FONT_SIZE_SPACE.COMMON_PADDING) + .margin(MARGIN_FONT_SIZE_SPACE.COMMON_PADDING) + } + } + ``` 7. 在Second.ets页面,根据首页跳转时的参数,渲染顶部不同的容器名称和条件渲染不同的子组件。 代码如下: ```typescript + // Second.ets @Entry @Component struct Second { - private moduleList: any[] = router.getParams()[MODULE_LIST]; - private componentName: string = router.getParams()[COMPONENT_NAME]; ... + aboutToAppear() { + let params = router.getParams() as Record; + this.moduleList = params.moduleList as ContainerModuleItem[]; + this.componentName = params.componentName as string; + this.containerType = params.containerType as number; + } + build() { Row() { Column({ space: MARGIN_FONT_SIZE_SPACE.SIXTH_MARGIN }) { @@ -410,10 +415,9 @@ } } - // 顶部子组件 @Component struct BackComp { - ... + ... } ``` diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/common/constants/CommonConstants.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/common/constants/CommonConstants.ets index 5f1f39229649b72cdbbcfe60fafd4c1dd5cb4c0f..1b9d5f3b7349be7f3eb702e826662d24edbb2268 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/common/constants/CommonConstants.ets @@ -51,7 +51,7 @@ export const ALL_PERCENT: string = '100%'; /** * opacity of text */ -export const ATTRIBUTE_OPACITY: number = parseFloat('0.6'); +export const ATTRIBUTE_OPACITY: number = Number.parseFloat('0.6'); /** * title font weight diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/pages/LayoutAlignIndex.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/pages/LayoutAlignIndex.ets index 68665ee78726446913840e866ad4285bd9092ee9..2d56cfbcae24748d37751034452e6c40a41747ad 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/pages/LayoutAlignIndex.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/pages/LayoutAlignIndex.ets @@ -14,7 +14,7 @@ */ import router from '@ohos.router'; -import { IndexListItem } from '../common/bean/IndexListItem'; +import { IndexListItem } from '../viewmodel/IndexListItem'; import { TITLE_FONT_WEIGHT, MARGIN_FONT_SIZE_SPACE, @@ -32,10 +32,11 @@ import { getIndexList } from '../viewmodel/IndexData'; @Entry @Component struct LayoutAlignIndex { - private indexList : IndexListItem[] = getIndexList(); + private indexList: IndexListItem[] = getIndexList(); + build() { Column() { - Text($r("app.string.index_title")) + Text($r('app.string.index_title')) .width(ALL_PERCENT) .fontSize(MARGIN_FONT_SIZE_SPACE.SEVENTH_MARGIN) .fontWeight(TITLE_FONT_WEIGHT) @@ -43,12 +44,15 @@ struct LayoutAlignIndex { .fontColor(Color.Black) .margin({ top: EIGHT_POINT_TWO_PERCENT }) List() { - ForEach(this.indexList, (item) => { + ForEach(this.indexList, (item: IndexListItem) => { ListItem() { - ListItemComp({ item: item }).margin({ top: MARGIN_FONT_SIZE_SPACE.SECOND_MARGIN }) + ListItemComp({ item: item }) + .margin({ top: MARGIN_FONT_SIZE_SPACE.SECOND_MARGIN }) } - }, item => JSON.stringify(item)) + }, (item: IndexListItem) => JSON.stringify(item)) } + .height(ALL_PERCENT) + .width(ALL_PERCENT) .listDirection(Axis.Vertical) .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) } @@ -62,11 +66,11 @@ struct LayoutAlignIndex { @Component struct ListItemComp { - private item: IndexListItem; + private item: IndexListItem = new IndexListItem(); build() { Row() { - Image(this.item['icon']) + Image(this.item.icon) .height(MARGIN_FONT_SIZE_SPACE.SEVENTH_MARGIN) .width(MARGIN_FONT_SIZE_SPACE.SEVENTH_MARGIN) .margin({ @@ -74,7 +78,7 @@ struct ListItemComp { top: MARGIN_FONT_SIZE_SPACE.SIXTH_MARGIN, bottom: MARGIN_FONT_SIZE_SPACE.SIXTH_MARGIN }) - Text(this.item['name']) + Text(this.item.name) .fontSize(MARGIN_FONT_SIZE_SPACE.FIFTH_MARGIN) .fontColor(Color.Black) .fontWeight(COMMON_FONT_WEIGHT) @@ -90,11 +94,11 @@ struct ListItemComp { router.pushUrl({ url: SECOND_PAGE, params: { - containerType: this.item['containerType'], - componentName: this.item['name'], - moduleList: this.item['moduleList'] + containerType: this.item.containerType, + componentName: this.item.name, + moduleList: this.item.moduleList } }); }) } -} +} \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/pages/Second.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/pages/Second.ets index ff7831c2d27825faeca026d294b51e360c0039d6..61500c0d5f4f87b3928d93fe42f0f037b7eb42a8 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/pages/Second.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/pages/Second.ets @@ -21,14 +21,12 @@ import { StackComponent } from '../view/StackComponent'; import { MARGIN_FONT_SIZE_SPACE, COMMON_FONT_WEIGHT, - MODULE_LIST, - COMPONENT_NAME, - CONTAINER_TYPE_STR, LIST, ATTRIBUTE, CONTAINER_TYPE, ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { ContainerModuleItem } from '../viewmodel/ContainerModuleItem'; /** *second page @@ -36,9 +34,9 @@ import { @Entry @Component struct Second { - private moduleList: any[] = router.getParams()[MODULE_LIST]; - private componentName: string = router.getParams()[COMPONENT_NAME]; - @Provide containerType: number = router.getParams()[CONTAINER_TYPE_STR]; + private moduleList: ContainerModuleItem[] = []; + private componentName: string = ''; + @Provide containerType: number = 0; @Provide currentFlexDirection: FlexDirection = FlexDirection.Column; @Provide currentFlexJustifyContent: FlexAlign = FlexAlign.Start; @Provide currentFlexAlignItems: ItemAlign = ItemAlign.Start; @@ -52,6 +50,13 @@ struct Second { @Provide message: string = ATTRIBUTE.TOP_START; @Provide list: number[] = LIST; + aboutToAppear() { + let params = router.getParams() as Record; + this.moduleList = params.moduleList as ContainerModuleItem[]; + this.componentName = params.componentName as string; + this.containerType = params.containerType as number; + } + build() { Row() { Column({ space: MARGIN_FONT_SIZE_SPACE.SIXTH_MARGIN }) { @@ -79,7 +84,7 @@ struct Second { @Component struct BackComp { private backIconResource: Resource = $r('app.media.icon_back'); - private componentName: string; + private componentName: string = ''; build() { Row() { diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnAxisAlignRadioList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnAxisAlignRadioList.ets index 885a0694d07d426cbc79214ecc2a958400ca6b12..03f22d3e3d4445b90408464e8437c7f3f0be5028 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnAxisAlignRadioList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnAxisAlignRadioList.ets @@ -13,18 +13,19 @@ * limitations under the License. */ -import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE,ALL_PERCENT } from '../common/Constants/CommonConstants'; -import {getColumnModuleList} from '../viewmodel/AttributeModuleData'; -import {ContainerModuleItem} from '../common/bean/ContainerModuleItem'; +import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE, ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { getColumnModuleList } from '../viewmodel/AttributeModuleData'; +import { ContainerModuleItem } from '../viewmodel/ContainerModuleItem'; + /** *Set Axis Alignment in Column */ @Component export struct ColumnAxisAlignRadioList { - private columnModuleList :ContainerModuleItem[] = getColumnModuleList(); - private groupName: string = this.columnModuleList[1]['groupName']; - private moduleName: Resource = this.columnModuleList[1]['moduleName']; - private radioList: Array =this.columnModuleList[1]['attributeList']; + private columnModuleList: ContainerModuleItem[] = getColumnModuleList(); + private groupName: string = this.columnModuleList[1].groupName; + private moduleName: Resource = this.columnModuleList[1].moduleName; + private radioList: Array = this.columnModuleList[1].attributeList; build() { Column({ space: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) { @@ -40,10 +41,10 @@ export struct ColumnAxisAlignRadioList { justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.NoWrap }) { - ForEach(this.radioList, (item, index) => { + ForEach(this.radioList, (item: string, index?: number) => { AxisAlignRadioItem({ textName: item, groupName: this.groupName, isChecked: index === 0 ? true : false }) .margin({ right: MARGIN_FONT_SIZE_SPACE.COMMON_MARGIN }) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } .width(ALL_PERCENT) .height(MARGIN_FONT_SIZE_SPACE.SEVENTH_MARGIN) @@ -56,9 +57,9 @@ export struct ColumnAxisAlignRadioList { @Component struct AxisAlignRadioItem { - private textName: string; - private groupName: string; - private isChecked: boolean; + private textName: string = ''; + private groupName: string = ''; + private isChecked: boolean = false; @Consume currentColumnAlignItems: HorizontalAlign; build() { @@ -80,7 +81,9 @@ struct AxisAlignRadioItem { break; } }) - Text(this.textName).fontSize(MARGIN_FONT_SIZE_SPACE.THIRD_MARGIN).opacity(ATTRIBUTE_OPACITY) + Text(this.textName) + .fontSize(MARGIN_FONT_SIZE_SPACE.THIRD_MARGIN) + .opacity(ATTRIBUTE_OPACITY) } } } diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnMainAlignRadioList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnMainAlignRadioList.ets index 441be60ab3277e1ce09365e5bbd01b48a697fa36..3e9a15066d26d9c6a8c087ce53353fdfe063103b 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnMainAlignRadioList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnMainAlignRadioList.ets @@ -15,7 +15,7 @@ import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE, ALL_PERCENT } from '../common/Constants/CommonConstants'; import { getColumnModuleList } from '../viewmodel/AttributeModuleData'; -import { ContainerModuleItem } from '../common/bean/ContainerModuleItem'; +import { ContainerModuleItem } from '../viewmodel/ContainerModuleItem'; /** *Set Main Alignment in Column @@ -23,16 +23,15 @@ import { ContainerModuleItem } from '../common/bean/ContainerModuleItem'; @Component export struct ColumnMainAlignRadioList { private columnModuleList: ContainerModuleItem[] = getColumnModuleList(); - private groupName: string = this.columnModuleList[0]['groupName']; - private moduleName: Resource = this.columnModuleList[0]['moduleName']; - private radioList: Array = this.columnModuleList[0]['attributeList']; + private groupName: string = this.columnModuleList[0].groupName; + private moduleName: Resource = this.columnModuleList[0].moduleName; + private radioList: Array = this.columnModuleList[0].attributeList; build() { Column({ space: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) { Row() { Text(this.moduleName) .fontSize(MARGIN_FONT_SIZE_SPACE.FOURTH_MARGIN) - } .margin({ left: MARGIN_FONT_SIZE_SPACE.SECOND_MARGIN }) @@ -41,10 +40,10 @@ export struct ColumnMainAlignRadioList { justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.NoWrap }) { - ForEach(this.radioList, (item, index) => { + ForEach(this.radioList, (item: string, index?: number) => { MainAlignRadioItem({ textName: item, groupName: this.groupName, isChecked: index === 0 ? true : false }) .margin({ right: MARGIN_FONT_SIZE_SPACE.COMMON_MARGIN }) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } .width(ALL_PERCENT) .height(MARGIN_FONT_SIZE_SPACE.SEVENTH_MARGIN) @@ -57,9 +56,9 @@ export struct ColumnMainAlignRadioList { @Component struct MainAlignRadioItem { - private textName: string; - private groupName: string; - private isChecked: boolean; + private textName: string = ''; + private groupName: string = ''; + private isChecked: boolean = false; @Consume currentColumnJustifyContent: FlexAlign; build() { @@ -86,4 +85,4 @@ struct MainAlignRadioItem { .opacity(ATTRIBUTE_OPACITY) } } -} +} \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnShowList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnShowList.ets index 09f6fdbd9c60c6ce8f442fec7a9d9739d1391035..776dbc9c42cbe44349ff2d249f9a4c79bae8880d 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnShowList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/ColumnShowList.ets @@ -1,4 +1,3 @@ - /* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +14,12 @@ */ import { CommonItem } from './CommonComponent'; -import { MARGIN_FONT_SIZE_SPACE, LIST, SHOW_LIST_HEIGHT_PERCENT,ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { + MARGIN_FONT_SIZE_SPACE, + LIST, + SHOW_LIST_HEIGHT_PERCENT, + ALL_PERCENT +} from '../common/Constants/CommonConstants'; import { ColumnAxisAlignRadioList } from './ColumnAxisAlignRadioList'; import { ColumnMainAlignRadioList } from './ColumnMainAlignRadioList'; @@ -29,11 +33,10 @@ export struct ColumnShowList { build() { Column() { - // Column中元素对齐方式布局 Column() { - ForEach(LIST, (item) => { + ForEach(LIST, (item: number) => { CommonItem({ item: item }) - }, item => JSON.stringify(item)) + }, (item: number) => JSON.stringify(item)) } .alignItems(this.currentColumnAlignItems) .justifyContent(this.currentColumnJustifyContent) @@ -42,18 +45,16 @@ export struct ColumnShowList { .height(SHOW_LIST_HEIGHT_PERCENT.COLUMN_ROW_SHOW_LIST_HEIGHT) .backgroundColor($r("app.color.show_list_backgroundColor")) .margin({ top: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) + // set main align ColumnMainAlignRadioList() - .margin({top:MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN}) + .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) // set axis align ColumnAxisAlignRadioList() - .margin({top:MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN}) + .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) } .layoutWeight(1) .height(ALL_PERCENT) .width(ALL_PERCENT) } -} - - - +} \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/CommonComponent.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/CommonComponent.ets index 495bedd01f34f9761e886fa53cfa7c5e1a978010..03e539a0a8c324620f803b59f9b20185ad6189b7 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/CommonComponent.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/CommonComponent.ets @@ -20,7 +20,7 @@ import { MARGIN_FONT_SIZE_SPACE } from '../common/Constants/CommonConstants'; */ @Component export struct CommonItem { - private item: number; + private item: number = 0; build() { Text(this.item.toString()) diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexAxisAlignRadioList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexAxisAlignRadioList.ets index ddea853200abaa1ac488f978a844e731f2ac7df3..3bb9544f6614fb3648ed96824ca78cde9098c92c 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexAxisAlignRadioList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexAxisAlignRadioList.ets @@ -13,26 +13,25 @@ * limitations under the License. */ -import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE,ALL_PERCENT } from '../common/Constants/CommonConstants'; -import {getFlexModuleList} from '../viewmodel/AttributeModuleData'; -import {ContainerModuleItem} from '../common/bean/ContainerModuleItem'; +import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE, ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { getFlexModuleList } from '../viewmodel/AttributeModuleData'; +import { ContainerModuleItem } from '../viewmodel/ContainerModuleItem'; /** *Set Axis Alignment in Flex */ @Component export struct FlexAxisAlignRadioList { - private flexModuleList :ContainerModuleItem[] = getFlexModuleList(); - private groupName: string = this.flexModuleList[2]['groupName']; - private moduleName: Resource = this.flexModuleList[2]['moduleName']; - private radioList: Array =this.flexModuleList[2]['attributeList']; + private flexModuleList: ContainerModuleItem[] = getFlexModuleList(); + private groupName: string = this.flexModuleList[2].groupName; + private moduleName: Resource = this.flexModuleList[2].moduleName; + private radioList: Array = this.flexModuleList[2].attributeList; build() { Column({ space: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) { Row() { Text(this.moduleName) .fontSize(MARGIN_FONT_SIZE_SPACE.FOURTH_MARGIN) - } .margin({ left: MARGIN_FONT_SIZE_SPACE.SECOND_MARGIN }) @@ -41,10 +40,10 @@ export struct FlexAxisAlignRadioList { justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.NoWrap }) { - ForEach(this.radioList, (item, index) => { + ForEach(this.radioList, (item: string, index?: number) => { AxisAlignRadioItem({ textName: item, groupName: this.groupName, isChecked: index === 0 ? true : false }) .margin({ right: MARGIN_FONT_SIZE_SPACE.COMMON_MARGIN }) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } .width(ALL_PERCENT) .height(MARGIN_FONT_SIZE_SPACE.SEVENTH_MARGIN) @@ -57,9 +56,9 @@ export struct FlexAxisAlignRadioList { @Component struct AxisAlignRadioItem { - private textName: string; - private groupName: string; - private isChecked: boolean; + private textName: string = ''; + private groupName: string = ''; + private isChecked: boolean = false; @Consume currentFlexAlignItems: ItemAlign; build() { @@ -81,7 +80,9 @@ struct AxisAlignRadioItem { break; } }) - Text(this.textName).fontSize(MARGIN_FONT_SIZE_SPACE.THIRD_MARGIN).opacity(ATTRIBUTE_OPACITY) + Text(this.textName) + .fontSize(MARGIN_FONT_SIZE_SPACE.THIRD_MARGIN) + .opacity(ATTRIBUTE_OPACITY) } } -} +} \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexMainAlignRadioList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexMainAlignRadioList.ets index 010440bd8d218f5e45faf29d007b627deeb09333..6da9ffa5e335ff4dd0b9a702c3aaae2d76c15d7f 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexMainAlignRadioList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexMainAlignRadioList.ets @@ -13,20 +13,19 @@ * limitations under the License. */ -import { MARGIN_FONT_SIZE_SPACE,ATTRIBUTE_OPACITY,ATTRIBUTE,ALL_PERCENT } from '../common/Constants/CommonConstants'; -import {getFlexModuleList} from '../viewmodel/AttributeModuleData'; -import {ContainerModuleItem} from '../common/bean/ContainerModuleItem'; +import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE, ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { getFlexModuleList } from '../viewmodel/AttributeModuleData'; +import { ContainerModuleItem } from '../viewmodel/ContainerModuleItem'; /** *Set Main Alignment in Flex */ @Component export struct FlexMainAlignRadioList { - private flexModuleList :ContainerModuleItem[] = getFlexModuleList(); - private groupName: string = this.flexModuleList[1]['groupName']; - private moduleName: Resource = this.flexModuleList[1]['moduleName']; - private radioList: Array =this.flexModuleList[1]['attributeList']; - + private flexModuleList: ContainerModuleItem[] = getFlexModuleList(); + private groupName: string = this.flexModuleList[1].groupName; + private moduleName: Resource = this.flexModuleList[1].moduleName; + private radioList: Array = this.flexModuleList[1].attributeList; build() { Column({ space: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) { @@ -39,13 +38,13 @@ export struct FlexMainAlignRadioList { Flex({ direction: FlexDirection.Row, - justifyContent: FlexAlign.SpaceBetween , - wrap: FlexWrap.NoWrap + justifyContent: FlexAlign.SpaceBetween, + wrap: FlexWrap.NoWrap }) { - ForEach(this.radioList, (item, index) => { + ForEach(this.radioList, (item: string, index: number | undefined) => { MainAlignRadioItem({ textName: item, groupName: this.groupName, isChecked: index === 0 ? true : false }) - .margin({right: MARGIN_FONT_SIZE_SPACE.COMMON_MARGIN}) - }, item => JSON.stringify(item)) + .margin({ right: MARGIN_FONT_SIZE_SPACE.COMMON_MARGIN }) + }, (item: string) => JSON.stringify(item)) } .width(ALL_PERCENT) .height(MARGIN_FONT_SIZE_SPACE.SEVENTH_MARGIN) @@ -58,12 +57,11 @@ export struct FlexMainAlignRadioList { @Component struct MainAlignRadioItem { - private textName: string; - private groupName: string; - private isChecked: boolean; + private textName: string = ''; + private groupName: string = ''; + private isChecked: boolean = false; @Consume currentFlexJustifyContent: FlexAlign; - build() { Row() { Radio({ value: this.textName, group: this.groupName }) diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexMainDirectionRadioList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexMainDirectionRadioList.ets index ec0e8d6ad31ab54d02220e34ff1698e9fef4ca4e..7dcef878bb01b57984275c9ab2e8fc4b8eea5ee9 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexMainDirectionRadioList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexMainDirectionRadioList.ets @@ -13,26 +13,25 @@ * limitations under the License. */ -import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE,ALL_PERCENT } from '../common/Constants/CommonConstants'; -import {getFlexModuleList} from '../viewmodel/AttributeModuleData'; -import {ContainerModuleItem} from '../common/bean/ContainerModuleItem'; +import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE, ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { getFlexModuleList } from '../viewmodel/AttributeModuleData'; +import { ContainerModuleItem } from '../viewmodel/ContainerModuleItem'; /** *Set Main Direction Alignment in Flex */ @Component export struct FlexMainDirectionRadioList { - private flexModuleList :ContainerModuleItem[] = getFlexModuleList(); - private groupName: string = this.flexModuleList[0]['groupName']; - private moduleName: Resource = this.flexModuleList[0]['moduleName']; - private radioList: Array =this.flexModuleList[0]['attributeList']; + private flexModuleList: ContainerModuleItem[] = getFlexModuleList(); + private groupName: string = this.flexModuleList[0].groupName; + private moduleName: Resource = this.flexModuleList[0].moduleName; + private radioList: Array = this.flexModuleList[0].attributeList; build() { Column({ space: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) { Row() { Text(this.moduleName) .fontSize(MARGIN_FONT_SIZE_SPACE.FOURTH_MARGIN) - } .margin({ left: MARGIN_FONT_SIZE_SPACE.SECOND_MARGIN }) @@ -41,10 +40,10 @@ export struct FlexMainDirectionRadioList { justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.NoWrap }) { - ForEach(this.radioList, (item, index) => { + ForEach(this.radioList, (item: string, index: number | undefined) => { MainDirectionRadioItem({ textName: item, groupName: this.groupName, isChecked: index === 0 ? true : false }) .margin({ right: MARGIN_FONT_SIZE_SPACE.COMMON_MARGIN }) - }, item => JSON.stringify(item)) + }, (item: number) => JSON.stringify(item)) } .width(ALL_PERCENT) .height(MARGIN_FONT_SIZE_SPACE.SEVENTH_MARGIN) @@ -57,9 +56,9 @@ export struct FlexMainDirectionRadioList { @Component struct MainDirectionRadioItem { - private textName: string; - private groupName: string; - private isChecked: boolean; + private textName: string = ''; + private groupName: string = ''; + private isChecked: boolean = false; @Consume currentFlexDirection: FlexDirection; build() { diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexShowList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexShowList.ets index aa59acc61b73a3d0facdd5afd93c4fca35e87792..3491bb278429dcefc9f66f82561dcbc6e0ee3be4 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexShowList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/FlexShowList.ets @@ -14,7 +14,7 @@ */ import { CommonItem } from './CommonComponent'; -import { MARGIN_FONT_SIZE_SPACE, SHOW_LIST_HEIGHT_PERCENT,ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { MARGIN_FONT_SIZE_SPACE, SHOW_LIST_HEIGHT_PERCENT, ALL_PERCENT } from '../common/Constants/CommonConstants'; import { FlexAxisAlignRadioList } from './FlexAxisAlignRadioList'; import { FlexMainAlignRadioList } from './FlexMainAlignRadioList'; import { FlexMainDirectionRadioList } from './FlexMainDirectionRadioList'; @@ -33,7 +33,6 @@ export struct FlexShowList { build() { Column() { - // Flex中元素对齐方式布局 Flex({ alignItems: this.currentFlexAlignItems, direction: this.currentFlexDirection, @@ -41,9 +40,9 @@ export struct FlexShowList { wrap: this.currentFlexWrap, alignContent: this.currentFlexAlignContent }) { - ForEach(this.list, (item) => { + ForEach(this.list, (item: number) => { CommonItem({ item: item }) - }, item => JSON.stringify(item)) + }, (item: number) => JSON.stringify(item)) } .padding(MARGIN_FONT_SIZE_SPACE.COMMON_PADDING) .width(ALL_PERCENT) @@ -52,25 +51,17 @@ export struct FlexShowList { .margin({ top: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) // set main direction - FlexMainDirectionRadioList().margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) + FlexMainDirectionRadioList() + .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) // set main align - FlexMainAlignRadioList().margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) + FlexMainAlignRadioList() + .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) // set axis align - FlexAxisAlignRadioList().margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) + FlexAxisAlignRadioList() + .margin({ top: MARGIN_FONT_SIZE_SPACE.EIGHTH_MARGIN }) } .layoutWeight(1) .height(ALL_PERCENT) .width(ALL_PERCENT) - } -} - - - - - - - - - - +} \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowAxisAlignRadioList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowAxisAlignRadioList.ets index 87e052fc80f6ae109c6e5276c0f09ccdda680c88..cd88ff8faa8d1df22c3f52a347be5b6aaa194c08 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowAxisAlignRadioList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowAxisAlignRadioList.ets @@ -13,19 +13,19 @@ * limitations under the License. */ -import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE,ALL_PERCENT } from '../common/Constants/CommonConstants'; -import {getRowModuleList} from '../viewmodel/AttributeModuleData'; -import {ContainerModuleItem} from '../common/bean/ContainerModuleItem'; +import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE, ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { getRowModuleList } from '../viewmodel/AttributeModuleData'; +import { ContainerModuleItem } from '../viewmodel/ContainerModuleItem'; /** *Set Axis Alignment in Row */ @Component export struct RowAxisAlignRadioList { - private rowModuleList :ContainerModuleItem[] = getRowModuleList(); - private groupName: string = this.rowModuleList[1]['groupName']; - private moduleName: Resource = this.rowModuleList[1]['moduleName']; - private radioList: Array =this.rowModuleList[1]['attributeList']; + private rowModuleList: ContainerModuleItem[] = getRowModuleList(); + private groupName: string = this.rowModuleList[1].groupName; + private moduleName: Resource = this.rowModuleList[1].moduleName; + private radioList: Array = this.rowModuleList[1].attributeList; build() { Column({ space: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) { @@ -41,10 +41,10 @@ export struct RowAxisAlignRadioList { justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.NoWrap }) { - ForEach(this.radioList, (item, index) => { + ForEach(this.radioList, (item: string, index?: number) => { AxisAlignRadioItem({ textName: item, groupName: this.groupName, isChecked: index === 0 ? true : false }) .margin({ right: MARGIN_FONT_SIZE_SPACE.COMMON_MARGIN }) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } .width(ALL_PERCENT) .height(MARGIN_FONT_SIZE_SPACE.SEVENTH_MARGIN) @@ -57,9 +57,9 @@ export struct RowAxisAlignRadioList { @Component struct AxisAlignRadioItem { - private textName: string; - private groupName: string; - private isChecked: boolean; + private textName: string = ''; + private groupName: string = ''; + private isChecked: boolean = false; @Consume currentRowAlignItems: VerticalAlign; build() { diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowMainAlignRadioList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowMainAlignRadioList.ets index eedfdfedbd3a6ac2fa654c0b2b89f2ae3beed52a..0c406351257aab64b32c80757cd13d7f14e20cc6 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowMainAlignRadioList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowMainAlignRadioList.ets @@ -13,26 +13,25 @@ * limitations under the License. */ -import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE,ALL_PERCENT } from '../common/Constants/CommonConstants'; -import {getRowModuleList} from '../viewmodel/AttributeModuleData'; -import {ContainerModuleItem} from '../common/bean/ContainerModuleItem'; +import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE, ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { getRowModuleList } from '../viewmodel/AttributeModuleData'; +import { ContainerModuleItem } from '../viewmodel/ContainerModuleItem'; /** *Set Main Alignment in Row */ @Component export struct RowMainAlignRadioList { - private rowModuleList :ContainerModuleItem[] = getRowModuleList(); - private groupName: string = this.rowModuleList[0]['groupName']; - private moduleName: Resource = this.rowModuleList[0]['moduleName']; - private radioList: Array =this.rowModuleList[0]['attributeList']; + private rowModuleList: ContainerModuleItem[] = getRowModuleList(); + private groupName: string = this.rowModuleList[0].groupName; + private moduleName: Resource = this.rowModuleList[0].moduleName; + private radioList: Array = this.rowModuleList[0].attributeList; build() { Column({ space: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) { Row() { Text(this.moduleName) .fontSize(MARGIN_FONT_SIZE_SPACE.FOURTH_MARGIN) - } .margin({ left: MARGIN_FONT_SIZE_SPACE.SECOND_MARGIN }) @@ -41,10 +40,10 @@ export struct RowMainAlignRadioList { justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.NoWrap }) { - ForEach(this.radioList, (item, index) => { + ForEach(this.radioList, (item: string, index?: number) => { MainAlignRadioItem({ textName: item, groupName: this.groupName, isChecked: index === 0 ? true : false }) .margin({ right: MARGIN_FONT_SIZE_SPACE.COMMON_MARGIN }) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } .width(ALL_PERCENT) .height(MARGIN_FONT_SIZE_SPACE.SEVENTH_MARGIN) @@ -57,9 +56,9 @@ export struct RowMainAlignRadioList { @Component struct MainAlignRadioItem { - private textName: string; - private groupName: string; - private isChecked: boolean; + private textName: string = ''; + private groupName: string = ''; + private isChecked: boolean = false; @Consume currentRowJustifyContent: FlexAlign; build() { @@ -81,7 +80,9 @@ struct MainAlignRadioItem { break; } }) - Text(this.textName).fontSize(MARGIN_FONT_SIZE_SPACE.THIRD_MARGIN).opacity(ATTRIBUTE_OPACITY) + Text(this.textName) + .fontSize(MARGIN_FONT_SIZE_SPACE.THIRD_MARGIN) + .opacity(ATTRIBUTE_OPACITY) } } } \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowShowList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowShowList.ets index 2293d3983450d121ff9c0c2aaa8435bcd1a6b2db..ca616cb571f09c61c9a3b58eaa0dc1d8a14a53f3 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowShowList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/RowShowList.ets @@ -14,7 +14,12 @@ */ import { CommonItem } from './CommonComponent'; -import { MARGIN_FONT_SIZE_SPACE, LIST, SHOW_LIST_HEIGHT_PERCENT,ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { + MARGIN_FONT_SIZE_SPACE, + LIST, + SHOW_LIST_HEIGHT_PERCENT, + ALL_PERCENT +} from '../common/Constants/CommonConstants'; import { RowAxisAlignRadioList } from './RowAxisAlignRadioList'; import { RowMainAlignRadioList } from './RowMainAlignRadioList'; @@ -28,18 +33,17 @@ export struct RowShowList { build() { Column() { - // Row中元素对齐方式布局 Row() { - ForEach(LIST, (item) => { + ForEach(LIST, (item: number) => { CommonItem({ item: item }) - }, item => JSON.stringify(item)) + }, (item: number) => JSON.stringify(item)) } .alignItems(this.currentRowAlignItems) .justifyContent(this.currentRowJustifyContent) .padding(MARGIN_FONT_SIZE_SPACE.COMMON_PADDING) .width(ALL_PERCENT) .height(SHOW_LIST_HEIGHT_PERCENT.COLUMN_ROW_SHOW_LIST_HEIGHT) - .backgroundColor($r("app.color.show_list_backgroundColor")) + .backgroundColor($r('app.color.show_list_backgroundColor')) .margin({ top: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) // set main align @@ -52,11 +56,5 @@ export struct RowShowList { .layoutWeight(1) .height(ALL_PERCENT) .width(ALL_PERCENT) - } -} - - - - - +} \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/StackAlignRadioList.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/StackAlignRadioList.ets index 119d3e9f3d9b4061dd6c52aad2a592319eef9384..140f3b820d43c5947b59ad11685c95077bb84204 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/StackAlignRadioList.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/StackAlignRadioList.ets @@ -13,19 +13,19 @@ * limitations under the License. */ -import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE,ALL_PERCENT } from '../common/Constants/CommonConstants'; -import {getStackModuleList} from '../viewmodel/AttributeModuleData'; -import {ContainerModuleItem} from '../common/bean/ContainerModuleItem'; +import { MARGIN_FONT_SIZE_SPACE, ATTRIBUTE_OPACITY, ATTRIBUTE, ALL_PERCENT } from '../common/Constants/CommonConstants'; +import { getStackModuleList } from '../viewmodel/AttributeModuleData'; +import { ContainerModuleItem } from '../viewmodel/ContainerModuleItem'; /** *Set Alignment in Stack */ @Component export struct StackAlignRadioList { - private stackModuleList :ContainerModuleItem[] = getStackModuleList(); - private groupName: string = this.stackModuleList[0]['groupName']; - private moduleName: Resource = this.stackModuleList[0]['moduleName']; - private radioList: Array =this.stackModuleList[0]['attributeList']; + private stackModuleList: ContainerModuleItem[] = getStackModuleList(); + private groupName: string = this.stackModuleList[0].groupName; + private moduleName: Resource = this.stackModuleList[0].moduleName; + private radioList: Array = this.stackModuleList[0].attributeList; build() { Column({ space: MARGIN_FONT_SIZE_SPACE.FIRST_MARGIN }) { @@ -40,10 +40,10 @@ export struct StackAlignRadioList { justifyContent: FlexAlign.Start, wrap: FlexWrap.Wrap }) { - ForEach(this.radioList, (item, index) => { + ForEach(this.radioList, (item: string, index?: number) => { StackAlignRadioListItem({ textName: item, groupName: this.groupName, isChecked: index === 0 ? true : false }) .margin({ right: MARGIN_FONT_SIZE_SPACE.COMMON_MARGIN }) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } .width(ALL_PERCENT) .height(ALL_PERCENT) @@ -56,9 +56,9 @@ export struct StackAlignRadioList { @Component export struct StackAlignRadioListItem { - private textName: string; - private groupName: string; - private isChecked: boolean; + private textName: string = ''; + private groupName: string = ''; + private isChecked: boolean = false; @Consume currentStackAlignContent: Alignment; @Consume message: string; @@ -92,7 +92,9 @@ export struct StackAlignRadioListItem { break; } }) - Text(this.textName).fontSize(MARGIN_FONT_SIZE_SPACE.THIRD_MARGIN).opacity(ATTRIBUTE_OPACITY) + Text(this.textName) + .fontSize(MARGIN_FONT_SIZE_SPACE.THIRD_MARGIN) + .opacity(ATTRIBUTE_OPACITY) } } } \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/StackComponent.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/StackComponent.ets index c10b547861c5afbe6734823b05b06494932fcb38..c5489aaa503597f5a121b69a829cf3eee45c5c89 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/view/StackComponent.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/view/StackComponent.ets @@ -22,7 +22,7 @@ import { StackAlignRadioList } from './StackAlignRadioList'; @Component export struct StackComponent { @Consume currentStackAlignContent: Alignment; - @Consume message: string ; + @Consume message: string; @State textAl: TextAlign = TextAlign.Center; build() { @@ -52,4 +52,4 @@ export struct StackComponent { .height(ALL_PERCENT) .width(ALL_PERCENT) } -} +} \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/AttributeModuleData.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/AttributeModuleData.ets index ad1ddbe7d2a3f3466093d5c11599781cb43984e0..a697259ecc6889391a00887cfcbf9cd0ada80fce 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/AttributeModuleData.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/AttributeModuleData.ets @@ -14,15 +14,15 @@ */ import { ATTRIBUTE, GROUP } from '../common/Constants/CommonConstants'; -import {ContainerModuleItem} from '../common/bean/ContainerModuleItem'; +import { ContainerModuleItem } from './ContainerModuleItem'; /** *Get Module List Data in Flex */ -export function getFlexModuleList() :Array{ +export function getFlexModuleList(): Array { let flexModuleArray: Array = [] - FLEX_MODULE.forEach(item => { - flexModuleArray.push(new ContainerModuleItem(item['groupName'], item['moduleName'], item['attributeList'])); + FLEX_MODULE.forEach((item: ContainerModuleItem) => { + flexModuleArray.push(item); }) return flexModuleArray; } @@ -30,10 +30,10 @@ export function getFlexModuleList() :Array{ /** *Get Module List Data in Column */ -export function getColumnModuleList() :Array{ +export function getColumnModuleList(): Array { let columnModuleArray: Array = [] - COLUMN_MODULE.forEach(item => { - columnModuleArray.push(new ContainerModuleItem(item['groupName'], item['moduleName'], item['attributeList'])); + COLUMN_MODULE.forEach((item: ContainerModuleItem) => { + columnModuleArray.push(item); }) return columnModuleArray; } @@ -41,10 +41,10 @@ export function getColumnModuleList() :Array{ /** *Get Module List Data in Row */ -export function getRowModuleList() :Array{ +export function getRowModuleList(): Array { let rowModuleArray: Array = [] - ROW_MODULE.forEach(item => { - rowModuleArray.push(new ContainerModuleItem(item['groupName'], item['moduleName'], item['attributeList'])); + ROW_MODULE.forEach((item: ContainerModuleItem) => { + rowModuleArray.push(item); }) return rowModuleArray; } @@ -52,18 +52,18 @@ export function getRowModuleList() :Array{ /** *Get Module List Data in Stack */ -export function getStackModuleList() :Array{ +export function getStackModuleList(): Array { let stackModuleArray: Array = [] - STACK_MODULE.forEach(item => { - stackModuleArray.push(new ContainerModuleItem(item['groupName'], item['moduleName'], item['attributeList'])); + STACK_MODULE.forEach((item:ContainerModuleItem) => { + stackModuleArray.push(item); }) return stackModuleArray; } -export const FLEX_MODULE: object[] = [ +export const FLEX_MODULE: ContainerModuleItem[] = [ { groupName: GROUP.MAIN_DIRECTION, - moduleName: $r("app.string.main_direction"), + moduleName: $r('app.string.main_direction'), attributeList: [ATTRIBUTE.COLUMN, ATTRIBUTE.ROW, ATTRIBUTE.COLUMN_REVERSE] }, { @@ -78,7 +78,7 @@ export const FLEX_MODULE: object[] = [ } ]; -export const COLUMN_MODULE: object[] = [ +export const COLUMN_MODULE: ContainerModuleItem[] = [ { groupName: GROUP.MAIN_ALIGN, moduleName: $r("app.string.main_align"), @@ -91,7 +91,7 @@ export const COLUMN_MODULE: object[] = [ } ]; -export const ROW_MODULE: object[] = [ +export const ROW_MODULE: ContainerModuleItem[] = [ { groupName: GROUP.MAIN_ALIGN, moduleName: $r("app.string.main_align"), @@ -104,10 +104,10 @@ export const ROW_MODULE: object[] = [ } ]; -export const STACK_MODULE: object[] = [ +export const STACK_MODULE: ContainerModuleItem[] = [ { groupName: GROUP.ALIGN_TYPE, - moduleName: $r("app.string.align_type"), + moduleName: $r('app.string.align_type'), attributeList: [ATTRIBUTE.TOP_START, ATTRIBUTE.BOTTOM_START, ATTRIBUTE.TOP_END, ATTRIBUTE.BOTTOM_END, ATTRIBUTE.CENTER] } ]; diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/common/bean/ContainerModuleItem.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/ContainerModuleItem.ets similarity index 70% rename from ETSUI/OHLayoutAlign/entry/src/main/ets/common/bean/ContainerModuleItem.ets rename to ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/ContainerModuleItem.ets index 181f24d554ecbf6baf8247934dcef8308854ee82..f68c18cf29401fdb98a22d675e8aa2b3e13ac345 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/common/bean/ContainerModuleItem.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/ContainerModuleItem.ets @@ -12,18 +12,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { ATTRIBUTE, GROUP } from '../common/constants/CommonConstants'; /* * class for ContainerModuleItem */ export class ContainerModuleItem { - private groupName: string; - private moduleName: Resource; - private attributeList: string[]; - - constructor(groupName: string, moduleName: Resource, attributeList: string[]) { - this.groupName = groupName; - this.moduleName = moduleName; - this.attributeList = attributeList; - } + groupName: string = GROUP.MAIN_ALIGN; + moduleName: Resource = $r("app.string.main_align"); + attributeList: string[] = [ATTRIBUTE.START, ATTRIBUTE.CENTER, ATTRIBUTE.END]; } diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/IndexData.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/IndexData.ets index 79f8b80458902f461540dcb1921cde10c068ecc6..1defd1b0386c387bdae99bd9cfc1072e8023dc9e 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/IndexData.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/IndexData.ets @@ -15,41 +15,42 @@ import { CONTAINER, CONTAINER_TYPE } from '../common/Constants/CommonConstants'; import { FLEX_MODULE, COLUMN_MODULE, ROW_MODULE, STACK_MODULE } from '../viewmodel/AttributeModuleData'; -import {IndexListItem} from '../common/bean/IndexListItem' +import { IndexListItem } from './IndexListItem' /** * get Index page dataList */ -export function getIndexList() :Array{ +export function getIndexList(): Array { let indexModuleArray: Array = [] - INDEX_LIST.forEach(item => { - indexModuleArray.push(new IndexListItem(item['name'], item['icon'], item['containerType'],item['moduleList'])); + INDEX_LIST.forEach((item: IndexListItem) => { + indexModuleArray.push(item); }) return indexModuleArray; -}; +} -export const INDEX_LIST: Object[] = [ - { name: CONTAINER.FLEX, - icon: $r("app.media.ic_flex"), +export const INDEX_LIST: IndexListItem[] = [ + { + name: CONTAINER.FLEX, + icon: $r('app.media.ic_flex'), containerType: CONTAINER_TYPE.FLEX, moduleList: FLEX_MODULE }, { name: CONTAINER.COLUMN, - icon: $r("app.media.ic_column"), + icon: $r('app.media.ic_column'), containerType: CONTAINER_TYPE.COLUMN, moduleList: COLUMN_MODULE }, - { name: CONTAINER.ROW, - icon: $r("app.media.ic_row"), + { + name: CONTAINER.ROW, + icon: $r('app.media.ic_row'), containerType: CONTAINER_TYPE.ROW, moduleList: ROW_MODULE }, { name: CONTAINER.STACK, - icon: $r("app.media.ic_stack"), + icon: $r('app.media.ic_stack'), containerType: CONTAINER_TYPE.STACK, moduleList: STACK_MODULE }, ]; - diff --git a/ETSUI/OHLayoutAlign/entry/src/main/ets/common/bean/IndexListItem.ets b/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/IndexListItem.ets similarity index 59% rename from ETSUI/OHLayoutAlign/entry/src/main/ets/common/bean/IndexListItem.ets rename to ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/IndexListItem.ets index 3b427cde9d4506992249dc464e462620b59874a6..4a1b2bf4db91fb13c8f6db1f4a3af71e89d9f51a 100644 --- a/ETSUI/OHLayoutAlign/entry/src/main/ets/common/bean/IndexListItem.ets +++ b/ETSUI/OHLayoutAlign/entry/src/main/ets/viewmodel/IndexListItem.ets @@ -12,21 +12,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import {ContainerModuleItem} from './ContainerModuleItem' +import { FLEX_MODULE } from './AttributeModuleData'; +import { CONTAINER, CONTAINER_TYPE } from '../common/constants/CommonConstants'; +import { ContainerModuleItem } from './ContainerModuleItem' /* * class for IndexListItem */ -export class IndexListItem{ - private name : string; - private icon :Resource; - private containerType : number - private moduleList :ContainerModuleItem[]; - constructor(name : string,icon:Resource,containerType :number,moduleList :ContainerModuleItem[]){ - this.name = name; - this.icon = icon; - this.containerType = containerType; - this.moduleList = moduleList; - } +export class IndexListItem { + name: string = CONTAINER.FLEX; + icon: Resource = $r('app.media.ic_flex'); + containerType: number = CONTAINER_TYPE.FLEX; + moduleList: ContainerModuleItem[] = FLEX_MODULE; } \ No newline at end of file diff --git a/ETSUI/OHLayoutAlign/hvigor/hvigor-config.json5 b/ETSUI/OHLayoutAlign/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/ETSUI/OHLayoutAlign/hvigor/hvigor-config.json5 +++ b/ETSUI/OHLayoutAlign/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/ETSUI/PixelConversion/README.md b/ETSUI/PixelConversion/README.md index 7a9a5c2cee6c1b783c5932a857a701251431d967..d428a537c1886ce75ab272d3bb745047eb9e4ad8 100644 --- a/ETSUI/PixelConversion/README.md +++ b/ETSUI/PixelConversion/README.md @@ -1,37 +1,49 @@ -# 像素转换(ArkTS) +# 1 卡片介绍 + +基于像素单位,展示了像素单位的基本知识与像素转换API的使用。 + +# 2 标题 + +像素转换(ArkTS) + +# 3 介绍 + -## 介绍 本篇Codelab介绍像素单位的基本知识与像素单位转换API的使用。通过像素转换案例,向开发者讲解了如何使用像素单位设置组件的尺寸、字体的大小以及不同像素单位之间的转换方法。主要功能包括: -1. 展示了不同像素单位的使用。 -2. 展示了像素单位转换相关API的使用。 -![](figures/conversion_all_360.gif) +1. 展示了不同像素单位的使用。 +2. 展示了像素单位转换相关API的使用。 + + ![](figures/conversion_all_320.gif) + +## 相关概念 -### 相关概念 - [像素单位](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-pixel-units.md):为开发者提供4种像素单位,框架采用vp为基准数据单位。 - [List](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md):列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。 - [Column](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md):沿垂直方向布局的容器。 - [Text](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-text.md):显示一段文本的组件。 -## 环境搭建 -### 软件要求 +# 4 环境搭建 + -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +## 软件要求 -### 硬件要求 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 + +## 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 -### 环境搭建 +## 环境搭建 完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: 1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以3.2 Release版本为例: - ![](figures/zh-cn_image_0000001554588725.png) + ![](figures/zh-cn_image_0000001681848240.png) 2. 搭建烧录环境。 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) @@ -39,17 +51,16 @@ 3. 搭建开发环境。 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 - 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建arkts工程)创建工程(模板选择“Empty Ability”)。 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 -## 代码结构解读 +# 5 代码结构解读 + 本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 + ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──ConversionItem.ets // 像素转换bean -│ │ │ └──IntroductionItem.ets // 像素介绍bean │ │ ├──constants │ │ │ └──Constants.ets // 常量类 │ │ └──utils @@ -64,18 +75,20 @@ │ │ ├──ConversionItemComponment.ets // 像素转换Item │ │ └──IntroductionItemComponment.ets // 像素介绍Item │ └──viewmodel +│ ├──ConversionItem.ets // 像素转换信息类 │ ├──ConversionViewModel.ets // 像素转换ViewModel +│ ├──IntroductionItem.ets // 像素介绍信息类 │ └──IntroductionViewModel.ets // 像素介绍ViewModel └──entry/src/main/resources // 资源文件 ``` -## 像素单位介绍页面 +# 6 像素单位介绍页面 在像素单位介绍页面,介绍了系统像素单位的概念,并在页面中为Text组件的宽度属性设置不同的像素单位,fp像素单位则设置为Text组件的字体大小。 -![](figures/oh_intro_360.png) +![](figures/introduce_320.png) -```typescript +``` // IntroductionPage.ets // 设置Text组件的宽度为200px Text('200px') @@ -114,12 +127,13 @@ Column() { >- 为组件设置具体的宽高时,可以不加“vp”\(系统默认单位为vp)。 >- 为文字设置字体大小时可以不加“fp”(系统默认为fp)。 -## 像素转换页面 +# 7 像素转换页面 + 在像素转换页面,通过使用像素转换API,实现不同像素单位之间的相互转换功能。 -![](figures/oh_conversion_360.png) +![](figures/conversion_320.png) -```typescript +``` // ConversionPage.ets // vp转换为px Row() @@ -147,11 +161,12 @@ Row() .width(px2lpx(60)) ``` -## 总结 +# 8 总结 您已经完成了本次Codelab的学习,并了解到以下知识点: 1. 不同像素单位的使用。 2. 像素单位转换相关API的使用。 -![](figures/彩带动效.gif) \ No newline at end of file +![](figures/彩带动效.gif) + diff --git a/ETSUI/PixelConversion/entry/src/main/ets/common/utils/Logger.ets b/ETSUI/PixelConversion/entry/src/main/ets/common/utils/Logger.ets index f983817752de699e5e10c8a4478012da2d67aff1..db966d9e657c1823e5fb29cdf1df5ecba733b6df 100644 --- a/ETSUI/PixelConversion/entry/src/main/ets/common/utils/Logger.ets +++ b/ETSUI/PixelConversion/entry/src/main/ets/common/utils/Logger.ets @@ -36,19 +36,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: Object[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: Object[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: Object[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: Object[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/ETSUI/PixelConversion/entry/src/main/ets/pages/ConversionPage.ets b/ETSUI/PixelConversion/entry/src/main/ets/pages/ConversionPage.ets index cff61963200ec26dd79c881a207cac2d7dcb343a..9179c7f79620f6472c8e9d90ee33bb1863121214 100644 --- a/ETSUI/PixelConversion/entry/src/main/ets/pages/ConversionPage.ets +++ b/ETSUI/PixelConversion/entry/src/main/ets/pages/ConversionPage.ets @@ -15,7 +15,7 @@ import Constants from '../common/constants/Constants'; import ConversionItemComponent from '../view/ConversionItemComponent'; -import ConversionItem from '../common/bean/ConversionItem'; +import ConversionItem from '../viewmodel/ConversionItem'; import ConversionViewModel from '../viewmodel/ConversionViewModel'; @Entry diff --git a/ETSUI/PixelConversion/entry/src/main/ets/pages/IndexPage.ets b/ETSUI/PixelConversion/entry/src/main/ets/pages/IndexPage.ets index 22f4622a516fe0046295e9854f7294bd1edcdc9d..96c4098ac6a2cbb487566720c5a77a9c22c55171 100644 --- a/ETSUI/PixelConversion/entry/src/main/ets/pages/IndexPage.ets +++ b/ETSUI/PixelConversion/entry/src/main/ets/pages/IndexPage.ets @@ -22,7 +22,7 @@ import Logger from '../common/utils/Logger'; struct IndexPage { jumpPage(url: string) { router.pushUrl({ url }) - .catch((error) => { + .catch((error: Error) => { Logger.error(Constants.INDEX_PAGE_TAG, error); }); } diff --git a/ETSUI/PixelConversion/entry/src/main/ets/pages/IntroductionPage.ets b/ETSUI/PixelConversion/entry/src/main/ets/pages/IntroductionPage.ets index b757b7bb12cba0deb69180b870847e07820cf4b7..2f99eca1800af01388f1377c4a0e0c959ba81503 100644 --- a/ETSUI/PixelConversion/entry/src/main/ets/pages/IntroductionPage.ets +++ b/ETSUI/PixelConversion/entry/src/main/ets/pages/IntroductionPage.ets @@ -14,7 +14,7 @@ */ import Constants from '../common/constants/Constants'; -import IntroductionItem from '../common/bean/IntroductionItem'; +import IntroductionItem from '../viewmodel/IntroductionItem'; import IntroduceItemComponent from '../view/IntroduceItemComponent'; import IntroductionViewModel from '../viewmodel/IntroductionViewModel'; diff --git a/ETSUI/PixelConversion/entry/src/main/ets/view/ConversionItemComponent.ets b/ETSUI/PixelConversion/entry/src/main/ets/view/ConversionItemComponent.ets index c45b27532d8178dd2684bf2004b0e8f30e08c40c..9c8be70e9667df8c27f61d167cccc50d1459b9c5 100644 --- a/ETSUI/PixelConversion/entry/src/main/ets/view/ConversionItemComponent.ets +++ b/ETSUI/PixelConversion/entry/src/main/ets/view/ConversionItemComponent.ets @@ -14,7 +14,7 @@ */ import Constants from '../common/constants/Constants'; -import ConversionItem from '../common/bean/ConversionItem'; +import ConversionItem from '../viewmodel/ConversionItem'; @Extend(Text) function descTextStyle() { .fontColor($r('app.color.title_font')) @@ -41,30 +41,30 @@ import ConversionItem from '../common/bean/ConversionItem'; @Component export default struct ConversionItemComponent { - model: ConversionItem; + model?: ConversionItem; build() { Column() { - Text(this.model.title) + Text(this.model?.title) .titleTextStyle() .margin({ top: $r('app.float.title_margin_top') }) - Text(this.model.subTitle) + Text(this.model?.subTitle) .descTextStyle() .opacity($r('app.float.label_opacity')) Row() .blueStyle() - .width(this.model.value) - Text(this.model.conversionTitle) + .width(this.model?.value) + Text(this.model?.conversionTitle) .titleTextStyle() .margin({ top: $r('app.float.item_margin_top') }) - Text(this.model.conversionSubTitle) + Text(this.model?.conversionSubTitle) .descTextStyle() .opacity($r('app.float.label_opacity')) Row() .blueStyle() - .width(this.model.conversionValue) - if (this.model.notice) { - Text(this.model.notice) + .width(this.model?.conversionValue) + if (this.model?.notice) { + Text(this.model?.notice) .descTextStyle() .fontColor($r('app.color.notice_font')) } diff --git a/ETSUI/PixelConversion/entry/src/main/ets/view/IntroduceItemComponent.ets b/ETSUI/PixelConversion/entry/src/main/ets/view/IntroduceItemComponent.ets index e6a53a1dcaf83d8ea0b7b53179d090db9ba48a3c..e4a7f41578f5ba0e65839be75caa94856b0c7fc4 100644 --- a/ETSUI/PixelConversion/entry/src/main/ets/view/IntroduceItemComponent.ets +++ b/ETSUI/PixelConversion/entry/src/main/ets/view/IntroduceItemComponent.ets @@ -14,7 +14,7 @@ */ import Constants from '../common/constants/Constants'; -import IntroductionItem from '../common/bean/IntroductionItem'; +import IntroductionItem from '../viewmodel/IntroductionItem'; @Extend(Text) function titleTextStyle() { .fontColor($r('app.color.title_font')) @@ -24,22 +24,22 @@ import IntroductionItem from '../common/bean/IntroductionItem'; @Component export default struct IntroduceItemComponent { - model: IntroductionItem; + model?: IntroductionItem; build() { Column() { - Text(this.model.name) + Text(this.model?.name) .titleTextStyle() .fontSize($r('app.float.name_font_size')) - Text(this.model.title) + Text(this.model?.title) .titleTextStyle() .fontSize($r('app.float.title_font_size')) .fontFamily($r('app.string.HarmonyHeiTi')) .lineHeight($r('app.float.desc_line_height')) .margin({ top: $r('app.float.desc_margin_top') }) .fontWeight(Constants.LABEL_FONT_WEIGHT) - if (this.model.subTitle) { - Text(this.model.subTitle) + if (this.model?.subTitle) { + Text(this.model?.subTitle) .titleTextStyle() .opacity($r('app.float.label_opacity')) .lineHeight($r('app.float.subtitle_line_height')) @@ -48,25 +48,25 @@ export default struct IntroduceItemComponent { .margin({ top: $r('app.float.subtitle_margin_top') }) .fontWeight(Constants.LABEL_FONT_WEIGHT) } - if (this.model.value.length > 0) { - Text(this.model.value) + if (this.model !== undefined && this.model?.value.length > 0) { + Text(this.model?.value) .titleTextStyle() .fontColor($r('app.color.item_background')) .fontSize($r('app.float.name_font_size')) .textAlign(TextAlign.Center) .backgroundColor($r('app.color.blue_background')) .height($r('app.float.value_height')) - .width(this.model.value) + .width(this.model?.value) .borderRadius($r('app.float.value_border_radius')) .margin({ top: $r('app.float.item_padding') }) } else { Column() { - Text($r('app.string.font_desc', this.model.smallFontSize)) + Text($r('app.string.font_desc', this.model?.smallFontSize)) .titleTextStyle() - .fontSize(this.model.smallFontSize) - Text($r('app.string.font_desc', this.model.largeFontSize)) + .fontSize(this.model?.smallFontSize) + Text($r('app.string.font_desc', this.model?.largeFontSize)) .titleTextStyle() - .fontSize(this.model.largeFontSize) + .fontSize(this.model?.largeFontSize) .margin({ top: $r('app.float.title_margin_top') }) } .alignItems(HorizontalAlign.Start) diff --git a/ETSUI/PixelConversion/entry/src/main/ets/common/bean/ConversionItem.ets b/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/ConversionItem.ets similarity index 92% rename from ETSUI/PixelConversion/entry/src/main/ets/common/bean/ConversionItem.ets rename to ETSUI/PixelConversion/entry/src/main/ets/viewmodel/ConversionItem.ets index 1e800db1f7309c8a664240fd3c9fec00b41286f9..7ba84b7657ac9b04f1e1acb3e87a991ffe329448 100644 --- a/ETSUI/PixelConversion/entry/src/main/ets/common/bean/ConversionItem.ets +++ b/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/ConversionItem.ets @@ -13,12 +13,12 @@ * limitations under the License. */ -export default class ConversionItem { +export default interface ConversionItem { title: string; subTitle: string; value: number; conversionTitle: string; conversionSubTitle: string; conversionValue: number; - notice: Resource; + notice?: Resource; } \ No newline at end of file diff --git a/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/ConversionViewModel.ets b/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/ConversionViewModel.ets index 80838cae4987d3a5db31b2f08fb3d643d7babcd8..3f600b79fc22c00e0e145f62bb12577b450a9c1f 100644 --- a/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/ConversionViewModel.ets +++ b/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/ConversionViewModel.ets @@ -14,7 +14,7 @@ */ import Constants from '../common/constants/Constants'; -import ConversionItem from '../common/bean/ConversionItem'; +import ConversionItem from './ConversionItem'; class ConversionViewModel { /** @@ -35,8 +35,7 @@ export const CONVERSION_LIST: ConversionItem[] = [ value: vp2px(Constants.VP_SIZE), conversionTitle: 'px > vp', conversionSubTitle: `px2vp(${Constants.VP_SIZE})`, - conversionValue: px2vp(Constants.VP_SIZE), - notice: null + conversionValue: px2vp(Constants.VP_SIZE) }, { title: 'fp > px', @@ -44,8 +43,7 @@ export const CONVERSION_LIST: ConversionItem[] = [ value: fp2px(Constants.VP_SIZE), conversionTitle: 'px > fp', conversionSubTitle: `px2fp(${Constants.VP_SIZE})`, - conversionValue: px2fp(Constants.VP_SIZE), - notice: null + conversionValue: px2fp(Constants.VP_SIZE) }, { title: 'lpx > px', diff --git a/ETSUI/PixelConversion/entry/src/main/ets/common/bean/IntroductionItem.ets b/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/IntroductionItem.ets similarity index 91% rename from ETSUI/PixelConversion/entry/src/main/ets/common/bean/IntroductionItem.ets rename to ETSUI/PixelConversion/entry/src/main/ets/viewmodel/IntroductionItem.ets index bb02eb5cccd5c5fd5acf514f3be9018739235421..ecfbb74c1e8df6e617b5b8f6a144688719358d03 100644 --- a/ETSUI/PixelConversion/entry/src/main/ets/common/bean/IntroductionItem.ets +++ b/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/IntroductionItem.ets @@ -13,10 +13,10 @@ * limitations under the License. */ -export default class IntroductionItem { +export default interface IntroductionItem { name: string; title: Resource; - subTitle: Resource; + subTitle?: Resource; value: string; smallFontSize: number; largeFontSize: number; diff --git a/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/IntroductionViewModel.ets b/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/IntroductionViewModel.ets index 05a5e74a3e40e547a29f0e17034dad38f4b25d06..6b8ed6928224c9194f513a17b7c9970ec7a1a5c6 100644 --- a/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/IntroductionViewModel.ets +++ b/ETSUI/PixelConversion/entry/src/main/ets/viewmodel/IntroductionViewModel.ets @@ -14,7 +14,7 @@ */ import Constants from '../common/constants/Constants'; -import IntroductionItem from '../common/bean/IntroductionItem'; +import IntroductionItem from './IntroductionItem'; class IntroductionViewModel { /** @@ -32,7 +32,6 @@ const INTRODUCE_LIST: IntroductionItem[] = [ { name: 'px', title: $r('app.string.px_unit'), - subTitle: null, value: Constants.PIXEL_WIDTH + 'px', smallFontSize: 0, largeFontSize: 0 @@ -48,7 +47,6 @@ const INTRODUCE_LIST: IntroductionItem[] = [ { name: 'lpx', title: $r('app.string.lpx_unit'), - subTitle: null, value: Constants.PIXEL_WIDTH + 'lpx', smallFontSize: 0, largeFontSize: 0 diff --git a/ETSUI/PixelConversion/figures/conversion_320.png b/ETSUI/PixelConversion/figures/conversion_320.png new file mode 100644 index 0000000000000000000000000000000000000000..7d0e62955282ee6156b30d44a95ca419786820d1 Binary files /dev/null and b/ETSUI/PixelConversion/figures/conversion_320.png differ diff --git a/NetworkManagement/NewsDataArkTS/figures/news.gif b/ETSUI/PixelConversion/figures/conversion_all_320.gif similarity index 49% rename from NetworkManagement/NewsDataArkTS/figures/news.gif rename to ETSUI/PixelConversion/figures/conversion_all_320.gif index ed30dc733c38360da3f006c6c922a58b3b20262c..0eaf366bb73325e2a4446dc773b3a54691596595 100644 Binary files a/NetworkManagement/NewsDataArkTS/figures/news.gif and b/ETSUI/PixelConversion/figures/conversion_all_320.gif differ diff --git a/ETSUI/PixelConversion/figures/conversion_all_360.gif b/ETSUI/PixelConversion/figures/conversion_all_360.gif deleted file mode 100644 index 820eafc7041bea448e37910d87b660360dcdc282..0000000000000000000000000000000000000000 Binary files a/ETSUI/PixelConversion/figures/conversion_all_360.gif and /dev/null differ diff --git a/ETSUI/PixelConversion/figures/introduce_320.png b/ETSUI/PixelConversion/figures/introduce_320.png new file mode 100644 index 0000000000000000000000000000000000000000..c85814d3523f4c8118534c5220b95f2443b3329c Binary files /dev/null and b/ETSUI/PixelConversion/figures/introduce_320.png differ diff --git a/ETSUI/PixelConversion/figures/oh_conversion_360.png b/ETSUI/PixelConversion/figures/oh_conversion_360.png deleted file mode 100644 index 120df00a0723e0578bd1b62841bcf294fcd45b33..0000000000000000000000000000000000000000 Binary files a/ETSUI/PixelConversion/figures/oh_conversion_360.png and /dev/null differ diff --git a/ETSUI/PixelConversion/figures/oh_intro_360.png b/ETSUI/PixelConversion/figures/oh_intro_360.png deleted file mode 100644 index a9adbf166d50961360310922bee254b869d9b987..0000000000000000000000000000000000000000 Binary files a/ETSUI/PixelConversion/figures/oh_intro_360.png and /dev/null differ diff --git a/ETSUI/PixelConversion/figures/zh-cn_image_0000001554588725.png b/ETSUI/PixelConversion/figures/zh-cn_image_0000001681848240.png similarity index 100% rename from ETSUI/PixelConversion/figures/zh-cn_image_0000001554588725.png rename to ETSUI/PixelConversion/figures/zh-cn_image_0000001681848240.png diff --git a/ETSUI/PixelConversion/hvigor/hvigor-config.json5 b/ETSUI/PixelConversion/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/PixelConversion/hvigor/hvigor-config.json5 +++ b/ETSUI/PixelConversion/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/ETSUI/RankingDemo/README.md b/ETSUI/RankingDemo/README.md index 17375f1cf8811e89c82622404fbaa1d92c259ad5..e7883f139f8a89725a5686cdae2d8961a6d576e3 100644 --- a/ETSUI/RankingDemo/README.md +++ b/ETSUI/RankingDemo/README.md @@ -1,6 +1,6 @@ # ArkTS基础知识(ArkTS) ## 介绍 -本课程使用声明式语法和组件化基础知识,搭建一个可刷新的排行榜页面。在排行榜页面中,使用循环渲染控制语法来实现列表数据渲染,使用@Builder创建排行列表布局内容,使用装饰器@State、@Prop、@Link来管理组件状态。最后我们点击系统返回按键,来学习自定义组件生命周期函数。完成效果如下图所示: +本课程使用声明式语法和组件化基础知识,搭建一个可刷新的排行榜页面。在排行榜页面中,使用循环渲染控制语法来实现列表数据渲染,使用@Builder创建排行列表布局内容,使用装饰器@State、@Prop、@Link来管理组件状态。最后我们点击系统返回按键,来学习自定义组件生命周期函数。效果如图所示: ![](figures/gif320.gif) @@ -37,13 +37,13 @@ ForEach( - [@Link](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-link.md)装饰的变量可以和父组件的@State变量建立双向数据绑定,需要注意的是:@Link变量不能在组件内部进行初始化。 - [@Builder](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-builder.md)装饰的方法用于定义组件的声明式UI描述,在一个自定义组件内快速生成多个布局内容。 -@State、@Prop、@Link三者关系如下图所示: +@State、@Prop、@Link三者关系如图所示: ![](figures/image5.png) 3.组件生命周期函数: -[自定义组件的生命周期函数](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/js-framework-lifecycle.md)用于通知用户该自定义组件的生命周期,这些回调函数是私有的,在运行时由开发框架在特定的时间进行调用,不能从应用程序中手动调用这些回调函数。 右图是自定义组件生命周期的简化图示: +[自定义组件的生命周期函数](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-page-custom-components-lifecycle.md)用于通知用户该自定义组件的生命周期,这些回调函数是私有的,在运行时由开发框架在特定的时间进行调用,不能从应用程序中手动调用这些回调函数。 右图是自定义组件生命周期的简化图示: ![](figures/image6.png) @@ -54,13 +54,13 @@ ForEach( ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -79,13 +79,10 @@ ForEach( 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 - +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 │ ├──common // 公共文件目录 -│ │ ├──bean -│ │ │ └──RankData.ets // 实体类 │ │ └──constants │ │ └──Constants.ets // 常量 │ ├──entryability @@ -98,15 +95,17 @@ ForEach( │ │ ├──ListHeaderComponent.ets │ │ ├──ListItemComponent.ets │ │ └──TitleComponent.ets -│ └──viewmodel -│ └──RankViewModel.ets // 视图业务逻辑类 -└──entry/src/main/resources // 资源文件目录 +│ └──viewmodel +│ ├──RankData.ets // 实体类 +│ └──RankViewModel.ets // 视图业务逻辑类 +└──entry/src/main/resources // 资源文件目录 ``` ## 使用@Link封装标题组件 在TitleComponent文件中,首先使用struct对象创建自定义组件,然后使用@Link修饰器管理TitleComponent组件内的状态变量isRefreshData,状态变量isRefreshData值发生改变后,通过@Link装饰器通知页面刷新List中的数据。代码如下: ```typescript +// TitleComponent.ets ... @Component export struct TitleComponent { @@ -133,7 +132,7 @@ export struct TitleComponent { } ``` -实现效果如下: +效果如图所示: ![](figures/titlebar.png) @@ -142,11 +141,12 @@ export struct TitleComponent { 在ListHeaderComponent文件中,我们使用常规成员变量来设置自定义组件ListHeaderComponent的widthValue和paddingValue,代码如下: ```typescript +// ListHeaderComponent.ets ... @Component export struct ListHeaderComponent { - paddingValue: Padding | Length; - widthValue: Length; + paddingValue: Padding | Length = 0; + widthValue: Length = 0; build() { Row() { @@ -172,7 +172,7 @@ export struct ListHeaderComponent { } ``` -实现效果如下: +效果如图所示: ![](figures/image3.png) @@ -183,13 +183,14 @@ export struct ListHeaderComponent { 在代码中,我们使用@State管理ListItemComponent中的 isChange 状态,当用户点击ListItemComponent时,ListItemComponent组件中的文本颜色发生变化。我们使用条件渲染控制语句,创建的圆型文本组件。 ```typescript +// ListItemComponent.ets ... @Component export struct ListItemComponent { - index: number; - private name: Resource; - @Prop vote: string; - @Prop isSwitchDataSource: boolean; + index?: number; + private name?: Resource; + @Prop vote: string = ''; + @Prop isSwitchDataSource: boolean = false; // 判断是否改变ListItemComponent字体颜色 @State isChange: boolean = false; @@ -197,9 +198,11 @@ export struct ListItemComponent { Row() { Column() { if (this.isRenderCircleText()) { - this.CircleText(this.index); + if (this.index !== undefined) { + this.CircleText(this.index); + } } else { - Text(this.index.toString()) + Text(this.index?.toString()) .lineHeight(ItemStyle.TEXT_LAYOUT_SIZE) .textAlign(TextAlign.Center) .width(ItemStyle.TEXT_LAYOUT_SIZE) @@ -241,6 +244,7 @@ export struct ListItemComponent { 为了简化代码,提高代码的可读性,我们使用@Builder描述排行列表布局内容,使用循环渲染组件ForEach创建ListItem。代码如下: ```typescript +// RankPage.ets ... build() { Column() { @@ -248,11 +252,16 @@ export struct ListItemComponent { TitleComponent({ isRefreshData: $isSwitchDataSource, title: TITLE }) // 列表头部样式 ListHeaderComponent({ - paddingValue: { left: Style.RANK_PADDING, - right: Style.RANK_PADDING }, + paddingValue: { + left: Style.RANK_PADDING, + right: Style.RANK_PADDING + }, widthValue: Style.CONTENT_WIDTH - }).margin({ top: Style.HEADER_MARGIN_TOP, - bottom: Style.HEADER_MARGIN_BOTTOM }) + }) + .margin({ + top: Style.HEADER_MARGIN_TOP, + bottom: Style.HEADER_MARGIN_BOTTOM + }) // 列表区域 this.RankList(Style.CONTENT_WIDTH) } @@ -265,20 +274,22 @@ export struct ListItemComponent { Column() { List() { ForEach(this.isSwitchDataSource ? this.dataSource1 : this.dataSource2, - (item, index) => { + (item: RankData, index?: number) => { ListItem() { - ListItemComponent({ index: index + 1, name: item.name, vote: item.vote, + ListItemComponent({ index: (Number(index) + 1), name: item.name, vote: item.vote, isSwitchDataSource: this.isSwitchDataSource }) } - }, (item, index) => item.id) + }, (item: RankData) => JSON.stringify(item)) } .width(WEIGHT) .height(Style.LIST_HEIGHT) .divider({ strokeWidth: Style.STROKE_WIDTH }) } - .padding({ left: Style.RANK_PADDING, - right: Style.RANK_PADDING }) + .padding({ + left: Style.RANK_PADDING, + right: Style.RANK_PADDING + }) .borderRadius(Style.BORDER_RADIUS) .width(widthValue) .alignItems(HorizontalAlign.Center) @@ -287,7 +298,7 @@ export struct ListItemComponent { ... ``` -布局效果如下: +效果如图所示: ![](figures/image1.png) @@ -296,6 +307,7 @@ export struct ListItemComponent { 我们通过点击系统导航返回按钮来演示onBackPress回调方法的使用,在指定的时间段内,如果满足退出条件,onBackPress将返回false,系统默认关闭当前页面。否则,提示用户需要再点击一次才能退出,同时onBackPress返回true,表示用户自己处理导航返回事件。代码如下: ```typescript +// RankPage.ets ... @Entry @Component @@ -303,7 +315,10 @@ struct RankPage { ... onBackPress() { if (this.isShowToast()) { - prompt.showToast({ message: $r('app.string.prompt_text'), duration: TIME }); + prompt.showToast({ + message: $r('app.string.prompt_text'), + duration: TIME + }); this.clickBackTimeRecord = new Date().getTime(); return true; } @@ -322,10 +337,3 @@ struct RankPage { 4. 自定义组件生命周期函数onBackPress的调用。 ![](figures/finished.gif) - - - - - - - diff --git a/ETSUI/RankingDemo/entry/src/main/ets/common/constants/Constants.ets b/ETSUI/RankingDemo/entry/src/main/ets/common/constants/Constants.ets index d5175f9f9b52ed7421db52ca0ec26b96f427b03d..274793fe8c2db1c582e3d84df38a746902dd19fa 100644 --- a/ETSUI/RankingDemo/entry/src/main/ets/common/constants/Constants.ets +++ b/ETSUI/RankingDemo/entry/src/main/ets/common/constants/Constants.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,6 +13,8 @@ * limitations under the License. */ +import { itemStyle, listHeaderStyle, style, titleBarStyle } from '../../viewmodel/RankData'; + /** * The font size of application. */ @@ -58,7 +60,7 @@ export const TITLE: Resource = $r('app.string.title'); /** * The Style of RankPage. */ -export const Style = { +export const Style: style = { /** * The padding of ranking. */ @@ -98,7 +100,7 @@ export const Style = { /** * The Style of ListHeaderComponent. */ -export const ListHeaderStyle = { +export const ListHeaderStyle: listHeaderStyle = { /** * The weight of font. */ @@ -123,7 +125,7 @@ export const ListHeaderStyle = { /** * The Style of ListItemComponent. */ -export const ItemStyle = { +export const ItemStyle: itemStyle = { /** * The line height of text. */ @@ -137,7 +139,7 @@ export const ItemStyle = { /** * The size of circle text. */ - CIRCLE_TEXT_SIZE:24, + CIRCLE_TEXT_SIZE: 24, /** * Gradient color proportion. @@ -188,7 +190,7 @@ export const ItemStyle = { /** * The Style of TitleComponent. */ -export const TitleBarStyle = { +export const TitleBarStyle: titleBarStyle = { /** * The image size of back button. */ @@ -223,8 +225,4 @@ export const TitleBarStyle = { * The weight of Row layout. */ WEIGHT: '50%', -}; - - - - +}; \ No newline at end of file diff --git a/ETSUI/RankingDemo/entry/src/main/ets/entryability/EntryAbility.ts b/ETSUI/RankingDemo/entry/src/main/ets/entryability/EntryAbility.ts index 446c52359c972bda7fbb21d9a6a0ff9f7400c6c2..0196804d9e265a96ebce1be738fa2752f6f3ef03 100644 --- a/ETSUI/RankingDemo/entry/src/main/ets/entryability/EntryAbility.ts +++ b/ETSUI/RankingDemo/entry/src/main/ets/entryability/EntryAbility.ts @@ -15,22 +15,24 @@ import hilog from '@ohos.hilog'; import UIAbility from '@ohos.app.ability.UIAbility'; -import Window from '@ohos.window'; +import type window from '@ohos.window'; +import type AbilityConstant from '@ohos.app.ability.AbilityConstant'; +import type Want from '@ohos.app.ability.Want'; export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); } - onDestroy() { + onDestroy(): void | Promise { hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); } - onWindowStageCreate(windowStage: Window.WindowStage) { + onWindowStageCreate(windowStage: window.WindowStage): void { // Main window is created, set main page for this ability hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); @@ -46,19 +48,19 @@ export default class EntryAbility extends UIAbility { }); } - onWindowStageDestroy() { + onWindowStageDestroy(): void { // Main window is destroyed, release UI related resources hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); } - onForeground() { + onForeground(): void { // Ability has brought to foreground hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); } - onBackground() { + onBackground(): void { // Ability has back to background hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); diff --git a/ETSUI/RankingDemo/entry/src/main/ets/model/DataModel.ets b/ETSUI/RankingDemo/entry/src/main/ets/model/DataModel.ets index 98ddde31c05e51263152d8f6a705acee22ece9eb..bfd5c2145a2050457b6c82de7eae6693d76df257 100644 --- a/ETSUI/RankingDemo/entry/src/main/ets/model/DataModel.ets +++ b/ETSUI/RankingDemo/entry/src/main/ets/model/DataModel.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,97 +13,35 @@ * limitations under the License. */ +import { RankData } from '../viewmodel/RankData'; + /* * the Mock file instead of network data. */ export { rankData1, rankData2 } -const rankData1: object[] = [ - { - 'id': '1', - 'name': $r('app.string.fruit_apple'), - 'vote': '12080', - }, - { - 'id': '2', - 'name': $r('app.string.fruit_grapes'), - 'vote': '10320', - }, - { 'id': '3', - 'name': $r('app.string.fruit_watermelon'), - 'vote': '9801', - }, - { - 'id': '4', - 'name': $r('app.string.fruit_banana'), - 'vote': '8431', - }, - { 'id': '5', - 'name': $r('app.string.fruit_pineapple'), - 'vote': '7546', - }, - { 'id': '6', - 'name': $r('app.string.fruit_durian'), - 'vote': '7431', - }, - { 'id': '7', - 'name': $r('app.string.fruit_red_grape'), - 'vote': '7187', - }, - { 'id': '8', - 'name': $r('app.string.fruit_pears'), - 'vote': '7003', - }, - { 'id': '9', - 'name': $r('app.string.fruit_carambola'), - 'vote': '6794', - }, - { 'id': '10', - 'name': $r('app.string.fruit_guava'), - 'vote': '6721', - }, +const rankData1: RankData[] = [ + new RankData('1', $r('app.string.fruit_apple'), '12080'), + new RankData('2', $r('app.string.fruit_grapes'), '10320'), + new RankData('3', $r('app.string.fruit_watermelon'), '9801'), + new RankData('4', $r('app.string.fruit_banana'), '8431'), + new RankData('5', $r('app.string.fruit_pineapple'), '7546'), + new RankData('6', $r('app.string.fruit_durian'), '7431'), + new RankData('7', $r('app.string.fruit_red_grape'), '7187'), + new RankData('8', $r('app.string.fruit_pears'), '7003'), + new RankData('9', $r('app.string.fruit_carambola'), '6794'), + new RankData('10', $r('app.string.fruit_guava'), '6721') ]; -const rankData2: object[] = [ - { 'id': '11', - 'name': $r('app.string.fruit_watermelon'), - 'vote': '8836', - }, - { 'id': '12', - 'name': $r('app.string.fruit_apple'), - 'vote': '8521', - }, - - { 'id': '13', - 'name': $r('app.string.fruit_banana'), - 'vote': '8431', - }, - { 'id': '14', - 'name': $r('app.string.fruit_grapes'), - 'vote': '7909', - }, - { 'id': '15', - 'name': $r('app.string.fruit_red_grape'), - 'vote': '7547', - }, - { 'id': '16', - 'name': $r('app.string.fruit_pears'), - 'vote': '7433', - }, - { 'id': '17', - 'name': $r('app.string.fruit_pineapple'), - 'vote': '7186', - }, - { 'id': '18', - 'name': $r('app.string.fruit_durian'), - 'vote': '7023', - }, - { 'id': '19', - 'name': $r('app.string.fruit_guava'), - 'vote': '6794', - }, - { 'id': '20', - 'name': $r('app.string.fruit_carambola'), - 'vote': '6721', - }, +const rankData2: RankData[] = [ + new RankData('11', $r('app.string.fruit_watermelon'), '8836'), + new RankData('12', $r('app.string.fruit_apple'), '8521'), + new RankData('13', $r('app.string.fruit_banana'), '8431'), + new RankData('14', $r('app.string.fruit_grapes'), '7909'), + new RankData('15', $r('app.string.fruit_red_grape'), '7547'), + new RankData('16', $r('app.string.fruit_pears'), '7433'), + new RankData('17', $r('app.string.fruit_pineapple'), '7186'), + new RankData('18', $r('app.string.fruit_durian'), '7023'), + new RankData('19', $r('app.string.fruit_guava'), '6794'), + new RankData('20', $r('app.string.fruit_carambola'), '6721') ]; \ No newline at end of file diff --git a/ETSUI/RankingDemo/entry/src/main/ets/pages/RankPage.ets b/ETSUI/RankingDemo/entry/src/main/ets/pages/RankPage.ets index 006ebe7557237731194ac51baef441fab4f55a3c..c912479490464335b79a0e2aa4b1a8c06d2fe451 100644 --- a/ETSUI/RankingDemo/entry/src/main/ets/pages/RankPage.ets +++ b/ETSUI/RankingDemo/entry/src/main/ets/pages/RankPage.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,7 +15,7 @@ import prompt from '@ohos.promptAction'; import { RankViewModel } from '../viewmodel/RankViewModel'; -import { RankData } from '../common/bean/RankData'; +import { RankData } from '../viewmodel/RankData'; import { ListHeaderComponent } from '../view/ListHeaderComponent'; import { TitleComponent } from '../view/TitleComponent'; import { ListItemComponent } from '../view/ListItemComponent'; @@ -39,12 +39,11 @@ struct RankPage { } onBackPress() { - let options = { - message: $r('app.string.prompt_text'), - duration: TIME - } if (this.isShowToast()) { - prompt.showToast(options); + prompt.showToast({ + message: $r('app.string.prompt_text'), + duration: TIME + }); this.clickBackTimeRecord = new Date().getTime(); return true; } @@ -67,10 +66,10 @@ struct RankPage { }, widthValue: Style.CONTENT_WIDTH }) - .margin({ - top: Style.HEADER_MARGIN_TOP, - bottom: Style.HEADER_MARGIN_BOTTOM - }) + .margin({ + top: Style.HEADER_MARGIN_TOP, + bottom: Style.HEADER_MARGIN_BOTTOM + }) // The style of List component. this.RankList(Style.CONTENT_WIDTH) } @@ -83,13 +82,13 @@ struct RankPage { Column() { List() { ForEach(this.isSwitchDataSource ? this.dataSource1 : this.dataSource2, - (item, index) => { + (item: RankData, index?: number) => { ListItem() { - ListItemComponent({ index: index + 1, name: item.name, vote: item.vote, + ListItemComponent({ index: (Number(index) + 1), name: item.name, vote: item.vote, isSwitchDataSource: this.isSwitchDataSource }) } - }, item => JSON.stringify(item)) + }, (item: RankData) => JSON.stringify(item)) } .width(WEIGHT) .height(Style.LIST_HEIGHT) @@ -104,5 +103,4 @@ struct RankPage { .alignItems(HorizontalAlign.Center) .backgroundColor(Color.White) } -} - +} \ No newline at end of file diff --git a/ETSUI/RankingDemo/entry/src/main/ets/view/ListHeaderComponent.ets b/ETSUI/RankingDemo/entry/src/main/ets/view/ListHeaderComponent.ets index 56e931f45ec6e0307e97031deffd2e09a1033bf5..ac1dd01da9f4c3f226d00bbdbd455e54f2444b44 100644 --- a/ETSUI/RankingDemo/entry/src/main/ets/view/ListHeaderComponent.ets +++ b/ETSUI/RankingDemo/entry/src/main/ets/view/ListHeaderComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,8 +17,8 @@ import { FontSize, ListHeaderStyle } from '../common/constants/Constants'; @Component export struct ListHeaderComponent { - paddingValue: Padding | Length; - widthValue: Length; + paddingValue: Padding | Length = 0; + widthValue: Length = 0; build() { Row() { diff --git a/ETSUI/RankingDemo/entry/src/main/ets/view/ListItemComponent.ets b/ETSUI/RankingDemo/entry/src/main/ets/view/ListItemComponent.ets index 255a35bb8eeb65acd2d83ecc5ff8e4bbd0a6f71f..20de60009cb6b1cf0677942e76f96369f0c1daad 100644 --- a/ETSUI/RankingDemo/entry/src/main/ets/view/ListItemComponent.ets +++ b/ETSUI/RankingDemo/entry/src/main/ets/view/ListItemComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,10 +17,10 @@ import { FontSize, FontWeight, ItemStyle, WEIGHT } from '../common/constants/Con @Component export struct ListItemComponent { - index: number; - private name: Resource; - @Prop vote: string; - @Prop isSwitchDataSource: boolean; + index?: number; + private name?: Resource; + @Prop vote: string = ''; + @Prop isSwitchDataSource: boolean = false; // The state is related to the font color of ListItemComponent. @State isChange: boolean = false; @@ -28,9 +28,11 @@ export struct ListItemComponent { Row() { Column() { if (this.isRenderCircleText()) { - this.CircleText(this.index); + if (this.index !== undefined) { + this.CircleText(this.index); + } } else { - Text(this.index.toString()) + Text(this.index?.toString()) .lineHeight(ItemStyle.TEXT_LAYOUT_SIZE) .textAlign(TextAlign.Center) .width(ItemStyle.TEXT_LAYOUT_SIZE) @@ -62,15 +64,17 @@ export struct ListItemComponent { @Builder CircleText(index: number) { Row() { - Text(this.index.toString()) + Text(this.index?.toString()) .fontWeight(FontWeight.BOLD) .fontSize(FontSize.SMALL) .fontColor(Color.White); } .justifyContent(FlexAlign.Center) .borderRadius(ItemStyle.CIRCLE_TEXT_BORDER_RADIUS) - .size({ width: ItemStyle.CIRCLE_TEXT_SIZE, - height: ItemStyle.CIRCLE_TEXT_SIZE }) + .size({ + width: ItemStyle.CIRCLE_TEXT_SIZE, + height: ItemStyle.CIRCLE_TEXT_SIZE + }) .backgroundColor($r('app.color.circle_text_background')) } diff --git a/ETSUI/RankingDemo/entry/src/main/ets/view/TitleComponent.ets b/ETSUI/RankingDemo/entry/src/main/ets/view/TitleComponent.ets index 3d15432e077c91d742ac9d58c7fc32ada8961a44..5b4955c57334fa154829cd8010487450055e402f 100644 --- a/ETSUI/RankingDemo/entry/src/main/ets/view/TitleComponent.ets +++ b/ETSUI/RankingDemo/entry/src/main/ets/view/TitleComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -52,8 +52,10 @@ export struct TitleComponent { .justifyContent(FlexAlign.End) } .width(WEIGHT) - .padding({ left: TitleBarStyle.BAR_MARGIN_HORIZONTAL, - right: TitleBarStyle.BAR_MARGIN_HORIZONTAL }) + .padding({ + left: TitleBarStyle.BAR_MARGIN_HORIZONTAL, + right: TitleBarStyle.BAR_MARGIN_HORIZONTAL + }) .margin({ top: TitleBarStyle.BAR_MARGIN_TOP }) .height(TitleBarStyle.BAR_HEIGHT) .justifyContent(FlexAlign.SpaceAround) diff --git a/Media/AudioPlayer/entry/src/main/ets/common/bean/MusicItem.ets b/ETSUI/RankingDemo/entry/src/main/ets/viewmodel/RankData.ets similarity index 30% rename from Media/AudioPlayer/entry/src/main/ets/common/bean/MusicItem.ets rename to ETSUI/RankingDemo/entry/src/main/ets/viewmodel/RankData.ets index 879fca369cbd2db1ddd2172fb68d3c2298cfd59b..f9994b18a32754e7761c8501cbe7bd262bd49036 100644 --- a/Media/AudioPlayer/entry/src/main/ets/common/bean/MusicItem.ets +++ b/ETSUI/RankingDemo/entry/src/main/ets/viewmodel/RankData.ets @@ -13,100 +13,56 @@ * limitations under the License. */ -import resourceManager from '@ohos.resourceManager'; - -/** - * Song Attributes. - */ -export interface MusicItemProperties { - /** - * Identifier. - */ - id: number; - - /** - * Music name. - */ - name: string; - - /** - * Singer. - */ - singer: string; - - /** - * Lyricist. - */ - lyrics: string; - - /** - * Resource Path. - */ - path: string; - - /** - * Member song or not. - */ - isVip: boolean; - - /** - * Song icon. - */ - image: Resource; +export class RankData { + name: Resource; + vote: string; // Number of votes + id: string; + + constructor(id: string, name: Resource, vote: string) { + this.id = id; + this.name = name; + this.vote = vote; + } } -/** - * Song entity class. - */ -export class MusicItem { - /** - * Identifier. - */ - id: number; - - /** - * Music name. - */ - name: string; - - /** - * Singer. - */ - singer: string; - - /** - * Lyricist. - */ - lyrics: string; - - /** - * Resource Path. - */ - path: string; - - /** - * Member song or not. - */ - isVip: boolean; +export class titleBarStyle { + IMAGE_BACK_SIZE: number = 21; + IMAGE_BACK_MARGIN_RIGHT: number = 18; + IMAGE_LOADING_SIZE: number = 22; + BAR_HEIGHT: number = 47; + BAR_MARGIN_HORIZONTAL: number = 26; + BAR_MARGIN_TOP: number = 10; + WEIGHT: string = '50%'; +} - /** - * Song icon. - */ - image: Resource; +export class itemStyle { + TEXT_LAYOUT_SIZE: number = 24; + CIRCLE_TEXT_BORDER_RADIUS: number = 24; + CIRCLE_TEXT_SIZE: number = 24; + CIRCLE_TEXT_COLOR_STOP_1: number = 0.5; + CIRCLE_TEXT_COLOR_STOP_2: number = 1.0; + BAR_HEIGHT: number = 48; + LAYOUT_WEIGHT_LEFT: string = '30%'; + LAYOUT_WEIGHT_CENTER: string = '50%'; + LAYOUT_WEIGHT_RIGHT: string = '20%'; + BORDER_WIDTH: number = 1; + COLOR_BLUE: Resource = $r('app.color.item_color'); + COLOR_BLACK: Resource = $r('app.color.item_color_black'); +} - /** - * Resource descriptor. - */ - rawFileDescriptor: resourceManager.RawFileDescriptor; +export class listHeaderStyle { + FONT_WEIGHT: number = 400; + LAYOUT_WEIGHT_LEFT: string = '30%'; + LAYOUT_WEIGHT_CENTER: string = '50%'; + LAYOUT_WEIGHT_RIGHT: string = '20%'; +} - constructor(musicItemProperties: MusicItemProperties, rawFileDescriptor: resourceManager.RawFileDescriptor) { - this.id = musicItemProperties.id; - this.name = musicItemProperties.name; - this.singer = musicItemProperties.singer; - this.lyrics = musicItemProperties.lyrics; - this.path = musicItemProperties.path; - this.isVip = musicItemProperties.isVip; - this.image = musicItemProperties.image; - this.rawFileDescriptor = rawFileDescriptor; - } +export class style { + RANK_PADDING: number = 15; + CONTENT_WIDTH: string = '90%'; + BORDER_RADIUS: number = 20; + STROKE_WIDTH: number = 1; + HEADER_MARGIN_TOP: number = 20; + HEADER_MARGIN_BOTTOM: number = 15; + LIST_HEIGHT: string = '65%'; } \ No newline at end of file diff --git a/ETSUI/RankingDemo/entry/src/main/ets/viewmodel/RankViewModel.ets b/ETSUI/RankingDemo/entry/src/main/ets/viewmodel/RankViewModel.ets index d63997408b3155ce7de6e9ec9808508669cdc9ab..3f9b5a5b6e29931cad7238e37947f084cdc18e8f 100644 --- a/ETSUI/RankingDemo/entry/src/main/ets/viewmodel/RankViewModel.ets +++ b/ETSUI/RankingDemo/entry/src/main/ets/viewmodel/RankViewModel.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,16 +13,17 @@ * limitations under the License. */ +import { RankData } from './RankData'; import { rankData1, rankData2 } from '../model/DataModel'; export class RankViewModel { // Load data from the rankData1 of the Mock file. - loadRankDataSource1(): any[] { + loadRankDataSource1(): RankData[] { return rankData1; } // Load data from the rankData2 of the Mock file,but rankData2 is different from rankData1. - loadRankDataSource2(): any[] { + loadRankDataSource2(): RankData[] { return rankData2; } } diff --git a/ETSUI/RankingDemo/hvigor/hvigor-config.json5 b/ETSUI/RankingDemo/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/RankingDemo/hvigor/hvigor-config.json5 +++ b/ETSUI/RankingDemo/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/ETSUI/SecondLevelLinkage/README.md b/ETSUI/SecondLevelLinkage/README.md index 4b2ae0fa1fce4bc9dfd54a3e93d50032d1d3d3f6..175baf2666fcb4d834fd48952ac130c5684ce952 100644 --- a/ETSUI/SecondLevelLinkage/README.md +++ b/ETSUI/SecondLevelLinkage/README.md @@ -1,37 +1,48 @@ -# 二级联动(ArkTS) +# 1 卡片介绍 -## 介绍 -本篇Codelab主要介绍如何基于List组件实现一个导航和内容的二级联动效果。样例主要包含以下功能: +使用ArkTS语言,实现一个导航与内容二级联动的效果。 + +# 2 标题 + +二级联动(ArkTS) + +# 3 介绍 + + +本篇Codelab是主要介绍了如何基于List组件实现一个导航和内容的二级联动效果。样例主要包含以下功能: 1. 切换左侧导航,右侧滚动到对应的内容。 2. 滚动右侧的内容,左侧会切换对应的导航。 -![](figures/oh_level_360.gif) +效果如图所示: + +![](figures/twolevel_320.gif) + +## 相关概念 -### 相关概念 - [List](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md):列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。 -- [ListItemGroup](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-listitemgroup.md): 该组件用来展示列表item分组,宽度默认充满List组件,必须配合List组件来使用。 +- [ListItemGroup](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-listitemgroup.md):该组件用来展示列表item分组,宽度默认充满List组件,必须配合List组件来使用。 -## 环境搭建 +# 4 环境搭建 -### 软件要求 +## 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 -### 硬件要求 +## 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 -### 环境搭建 +## 环境搭建 完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: 1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以3.2 Release版本为例: - ![](figures/zh-cn_image_0000001554588725.png) + ![](figures/zh-cn_image_0000001681848240.png) 2. 搭建烧录环境。 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) @@ -39,19 +50,16 @@ 3. 搭建开发环境。 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 - 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建arkts工程)创建工程(模板选择“Empty Ability”)。 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 -## 代码结构解读 +# 5 代码结构解读 本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 + ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──ClassifyModel.ets // 导航bean -│ │ │ ├──CourseModel.ets // 课程内容bean -│ │ │ └──LinkDataModel.ets // 数据源bean │ │ └──constants │ │ └──Constants.ets // 常量类 │ ├──entryability @@ -62,16 +70,20 @@ │ │ ├──ClassifyItem.ets // 课程分类组件 │ │ └──CourseItem.ets // 课程信息组件 │ └──viewmodel -│ └──ClassifyViewModel.ets // 导航ViewModel +│ ├──ClassifyModel.ets // 导航Model +│ ├──ClassifyViewModel.ets // 导航ViewModel +│ ├──CourseModel.ets // 课程内容Model +│ └──LinkDataModel.ets // 数据源Model └──entry/src/main/resources // 资源文件 ``` -## 二级联动实现 +# 6 二级联动实现 + 界面整体使用Row组件实现横向布局,分为左右两部分。均使用List组件实现对导航和内容的数据展示,导航部分固定宽度,内容部分自适应屏幕剩余宽度并用ListItemGroup完成每个导航下的内容布局。 -![](figures/oh_level_360.png) +![](figures/twolevel_320-0.png) -```typescript +``` Row() { List({ scroller: this.classifyScroller }) { ForEach(this.classifyList, (item: ClassifyModel, index: number) => { @@ -79,10 +91,10 @@ Row() { ClassifyItem({ classifyName: item.classifyName, isSelected: this.currentClassify === index, - onClickAction: this.classifyChangeAction.bind(this, index, true) + onClickAction: () => this.classifyChangeAction(index, true) }) } - }, (item: ClassifyModel) => item.classifyName) + }, (item: ClassifyModel) => item.classifyName + this.currentClassify) } List({ scroller: this.scroller }) { @@ -108,7 +120,7 @@ Row() { 点击左侧导航时,右侧内容区域通过scrollToIndex方法跳转到对应的内容页面,并改变导航的选中状态。同理在滚动右侧内容的过程中,如果当前展示的ListItemGroup发生改变时,修改左侧导航的选中状态,并滚到到对应的导航item。 -```typescript +``` classifyChangeAction(index: number, isClassify: boolean) { if (this.currentClassify !== index) { // change the classify status @@ -124,7 +136,7 @@ classifyChangeAction(index: number, isClassify: boolean) { } ``` -## 总结 +# 7 总结 您已经完成了本次Codelab的学习,并了解到以下知识点: diff --git a/ETSUI/SecondLevelLinkage/entry/src/main/ets/pages/IndexPage.ets b/ETSUI/SecondLevelLinkage/entry/src/main/ets/pages/IndexPage.ets index 10230b4a7c3038c1a806c672c42f45febb9b4702..4daa0fef545310266d1cf95c316d6ce489a3dba9 100644 --- a/ETSUI/SecondLevelLinkage/entry/src/main/ets/pages/IndexPage.ets +++ b/ETSUI/SecondLevelLinkage/entry/src/main/ets/pages/IndexPage.ets @@ -14,8 +14,8 @@ */ import Constants from '../common/constants/Constants'; -import ClassifyModel from '../common/bean/ClassifyModel'; -import CourseModel from '../common/bean/CourseModel'; +import ClassifyModel from '../viewmodel/ClassifyModel'; +import CourseModel from '../viewmodel/CourseModel'; import CourseItem from '../view/CourseItem'; import ClassifyItem from '../view/ClassityItem'; import ClassifyViewModel from '../viewmodel/ClassifyViewModel'; @@ -51,7 +51,7 @@ struct IndexPage { .backgroundColor($r('app.color.base_background')) } - classifyChangeAction(index: number, isClassify: boolean) { + classifyChangeAction(index: number, isClassify: boolean) : void { if (this.currentClassify !== index) { // change the classify status. this.currentClassify = index; @@ -74,7 +74,7 @@ struct IndexPage { ClassifyItem({ classifyName: item.classifyName, isSelected: this.currentClassify === index, - onClickAction: this.classifyChangeAction.bind(this, index, true) + onClickAction: () => this.classifyChangeAction(index, true) }) } }, (item: ClassifyModel) => item.classifyName + this.currentClassify) diff --git a/ETSUI/SecondLevelLinkage/entry/src/main/ets/view/ClassityItem.ets b/ETSUI/SecondLevelLinkage/entry/src/main/ets/view/ClassityItem.ets index 891fc338d9cff263e72ec5849d74be62cdcfa4b6..3bb68c8140a1b9f5d1451f55fd0931b75b2e70a1 100644 --- a/ETSUI/SecondLevelLinkage/entry/src/main/ets/view/ClassityItem.ets +++ b/ETSUI/SecondLevelLinkage/entry/src/main/ets/view/ClassityItem.ets @@ -17,9 +17,9 @@ import Constants from '../common/constants/Constants'; @Component export default struct ClassifyItem { - classifyName: string; + classifyName: string = ''; @Prop isSelected: boolean; - onClickAction: () => void; + onClickAction?: () => void; build() { Text(this.classifyName) diff --git a/ETSUI/SecondLevelLinkage/entry/src/main/ets/view/CourseItem.ets b/ETSUI/SecondLevelLinkage/entry/src/main/ets/view/CourseItem.ets index cd4707873e1a358e87dd2ac8438c401f73129bf0..e03622b2ed7fa801c31b7c8d273d73059911ddb1 100644 --- a/ETSUI/SecondLevelLinkage/entry/src/main/ets/view/CourseItem.ets +++ b/ETSUI/SecondLevelLinkage/entry/src/main/ets/view/CourseItem.ets @@ -14,12 +14,12 @@ */ import Constants from '../common/constants/Constants'; -import CourseModel from '../common/bean/CourseModel'; +import CourseModel from '../viewmodel/CourseModel'; @Component export default struct CourseItem { @Prop itemStr: string; - item: CourseModel; + item?: CourseModel; aboutToAppear() { this.item = JSON.parse(this.itemStr); @@ -27,11 +27,11 @@ export default struct CourseItem { build() { Row() { - Image(this.item.imageUrl) + Image(this.item?.imageUrl) .height(Constants.FULL_PERCENT) .aspectRatio(1) Column() { - Text(this.item.courseName) + Text(this.item?.courseName) .fontSize($r('app.float.normal_font_size')) .fontColor($r('app.color.base_font_color')) .fontFamily($r('app.string.hei_ti_medium')) @@ -39,7 +39,7 @@ export default struct CourseItem { .textOverflow({ overflow: TextOverflow.Clip }) .lineHeight($r('app.float.title_line_height')) .width(Constants.FULL_PERCENT) - Text(this.item.price === 0 ? $r('app.string.free_price') : $r('app.string.price_str', this.item.price)) + Text(this.item?.price === 0 ? $r('app.string.free_price') : $r('app.string.price_str', this.item?.price)) .fontSize($r('app.float.header_font_size')) .fontColor($r('app.color.price_color')) .fontFamily($r('app.string.hei_ti_medium')) diff --git a/ETSUI/SecondLevelLinkage/entry/src/main/ets/common/bean/ClassifyModel.ets b/ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/ClassifyModel.ets similarity index 95% rename from ETSUI/SecondLevelLinkage/entry/src/main/ets/common/bean/ClassifyModel.ets rename to ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/ClassifyModel.ets index 871056e1b4990da173808fdcdc0972ddfb88c393..b9d6bab4d3fa7479fefa872a5527a824c479e5d6 100644 --- a/ETSUI/SecondLevelLinkage/entry/src/main/ets/common/bean/ClassifyModel.ets +++ b/ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/ClassifyModel.ets @@ -18,7 +18,7 @@ import CourseModel from './CourseModel'; /** * course classity model */ -export default class ClassifyModel { +export default interface ClassifyModel { /** * classify id */ diff --git a/ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/ClassifyViewModel.ets b/ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/ClassifyViewModel.ets index 106a233f4ed676d20ffc2cfdac9aeefd487bea28..6eb720a7a4178430a012720cf2af2677e3238418 100644 --- a/ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/ClassifyViewModel.ets +++ b/ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/ClassifyViewModel.ets @@ -13,9 +13,9 @@ * limitations under the License. */ -import ClassifyModel from '../common/bean/ClassifyModel'; -import CourseModel from '../common/bean/CourseModel'; -import LinkDataModel from '../common/bean/LinkDataModel'; +import ClassifyModel from './ClassifyModel'; +import CourseModel from './CourseModel'; +import LinkDataModel from './LinkDataModel'; class ClassifyViewModel { /** @@ -56,443 +56,443 @@ export default classifyViewModel as ClassifyViewModel; const LINK_DATA: LinkDataModel[] = [ { - 'superId': 1, - 'superName': '热门课程', - 'id': 1, - 'courseName': '应用市场介绍', - 'imageUrl': $r('app.media.ic_img_1'), - 'price': 0 + superId: 1, + superName: '热门课程', + id: 1, + courseName: '应用市场介绍', + imageUrl: $r('app.media.ic_img_1'), + price: 0 }, { - 'superId': 1, - 'superName': '热门课程', - 'id': 2, - 'courseName': '上架流程', - 'imageUrl': $r('app.media.ic_img_2'), - 'price': 100 + superId: 1, + superName: '热门课程', + id: 2, + courseName: '上架流程', + imageUrl: $r('app.media.ic_img_2'), + price: 100 }, { - 'superId': 1, - 'superName': '热门课程', - 'id': 3, - 'courseName': '应用出海', - 'imageUrl': $r('app.media.ic_img_3'), - 'price': 50 + superId: 1, + superName: '热门课程', + id: 3, + courseName: '应用出海', + imageUrl: $r('app.media.ic_img_3'), + price: 50 }, { - 'superId': 1, - 'superName': '热门课程', - 'id': 4, - 'courseName': '审核政策', - 'imageUrl': $r('app.media.ic_img_4'), - 'price': 222 + superId: 1, + superName: '热门课程', + id: 4, + courseName: '审核政策', + imageUrl: $r('app.media.ic_img_4'), + price: 222 }, { - 'superId': 1, - 'superName': '热门课程', - 'id': 5, - 'courseName': 'CaaS Kit - HMS Core精品实战课', - 'imageUrl': $r('app.media.ic_img_5'), - 'price': 256 + superId: 1, + superName: '热门课程', + id: 5, + courseName: 'CaaS Kit - HMS Core精品实战课', + imageUrl: $r('app.media.ic_img_5'), + price: 256 }, { - 'superId': 1, - 'superName': '热门课程', - 'id': 6, - 'courseName': '机器学习在图像分割场景中的应用', - 'imageUrl': $r('app.media.ic_img_6'), - 'price': 0 + superId: 1, + superName: '热门课程', + id: 6, + courseName: '机器学习在图像分割场景中的应用', + imageUrl: $r('app.media.ic_img_6'), + price: 0 }, { - 'superId': 1, - 'superName': '热门课程', - 'id': 7, - 'courseName': '一分钟了解华为应用内支付服务', - 'imageUrl': $r('app.media.ic_img_7'), - 'price': 0 + superId: 1, + superName: '热门课程', + id: 7, + courseName: '一分钟了解华为应用内支付服务', + imageUrl: $r('app.media.ic_img_7'), + price: 0 }, { - 'superId': 1, - 'superName': '热门课程', - 'id': 8, - 'courseName': '一分钟了解华为位置服务', - 'imageUrl': $r('app.media.ic_img_8'), - 'price': 400 + superId: 1, + superName: '热门课程', + id: 8, + courseName: '一分钟了解华为位置服务', + imageUrl: $r('app.media.ic_img_8'), + price: 400 }, { - 'superId': 2, - 'superName': '最新课程', - 'id': 9, - 'courseName': 'Excel函数在商业中的应用', - 'imageUrl': $r('app.media.ic_img_9'), - 'price': 65 + superId: 2, + superName: '最新课程', + id: 9, + courseName: 'Excel函数在商业中的应用', + imageUrl: $r('app.media.ic_img_9'), + price: 65 }, { - 'superId': 2, - 'superName': '最新课程', - 'id': 10, - 'courseName': '“震动”手机锁屏制作', - 'imageUrl': $r('app.media.ic_img_10'), - 'price': 0 + superId: 2, + superName: '最新课程', + id: 10, + courseName: '“震动”手机锁屏制作', + imageUrl: $r('app.media.ic_img_10'), + price: 0 }, { - 'superId': 2, - 'superName': '最新课程', - 'id': 11, - 'courseName': '“流体动效”手机锁屏制作', - 'imageUrl': $r('app.media.ic_img_11'), - 'price': 50 + superId: 2, + superName: '最新课程', + id: 11, + courseName: '“流体动效”手机锁屏制作', + imageUrl: $r('app.media.ic_img_11'), + price: 50 }, { - 'superId': 2, - 'superName': '最新课程', - 'id': 12, - 'courseName': 'HUAWEI GT自定义表盘制作', - 'imageUrl': $r('app.media.ic_img_12'), - 'price': 70 + superId: 2, + superName: '最新课程', + id: 12, + courseName: 'HUAWEI GT自定义表盘制作', + imageUrl: $r('app.media.ic_img_12'), + price: 70 }, { - 'superId': 2, - 'superName': '最新课程', - 'id': 13, - 'courseName': '商务表盘制作', - 'imageUrl': $r('app.media.ic_img_13'), - 'price': 0 + superId: 2, + superName: '最新课程', + id: 13, + courseName: '商务表盘制作', + imageUrl: $r('app.media.ic_img_13'), + price: 0 }, { - 'superId': 2, - 'superName': '最新课程', - 'id': 14, - 'courseName': '5分钟了解跨应用、跨形态无缝登录', - 'imageUrl': $r('app.media.ic_img_14'), - 'price': 80 + superId: 2, + superName: '最新课程', + id: 14, + courseName: '5分钟了解跨应用、跨形态无缝登录', + imageUrl: $r('app.media.ic_img_14'), + price: 80 }, { - 'superId': 2, - 'superName': '最新课程', - 'id': 15, - 'courseName': 'oCPC进阶功能及最新政策解读', - 'imageUrl': $r('app.media.ic_img_15'), - 'price': 120 + superId: 2, + superName: '最新课程', + id: 15, + courseName: 'oCPC进阶功能及最新政策解读', + imageUrl: $r('app.media.ic_img_15'), + price: 120 }, { - 'superId': 2, - 'superName': '最新课程', - 'id': 16, - 'courseName': 'HUAWEI Ads 游戏行业投放指南', - 'imageUrl': $r('app.media.ic_img_16'), - 'price': 160 + superId: 2, + superName: '最新课程', + id: 16, + courseName: 'HUAWEI Ads 游戏行业投放指南', + imageUrl: $r('app.media.ic_img_16'), + price: 160 }, { - 'superId': 3, - 'superName': 'HarmonyOS', - 'id': 17, - 'courseName': 'HarmonyOS物联网开发课程', - 'imageUrl': $r('app.media.ic_img_17'), - 'price': 1020 + superId: 3, + superName: 'HarmonyOS', + id: 17, + courseName: 'HarmonyOS物联网开发课程', + imageUrl: $r('app.media.ic_img_17'), + price: 1020 }, { - 'superId': 3, - 'superName': 'HarmonyOS', - 'id': 18, - 'courseName': '【Hello系列直播课】第1期:手把手教你搭建开发环境', - 'imageUrl': $r('app.media.ic_img_18'), - 'price': 0 + superId: 3, + superName: 'HarmonyOS', + id: 18, + courseName: '【Hello系列直播课】第1期:手把手教你搭建开发环境', + imageUrl: $r('app.media.ic_img_18'), + price: 0 }, { - 'superId': 3, - 'superName': 'HarmonyOS', - 'id': 19, - 'courseName': 'HarmonyOS技术训练营-10分钟快速体验HarmonyOS分布式应用', - 'imageUrl': $r('app.media.ic_img_9'), - 'price': 0 + superId: 3, + superName: 'HarmonyOS', + id: 19, + courseName: 'HarmonyOS技术训练营-10分钟快速体验HarmonyOS分布式应用', + imageUrl: $r('app.media.ic_img_9'), + price: 0 }, { - 'superId': 3, - 'superName': 'HarmonyOS', - 'id': 20, - 'courseName': '应用开发基础:JS FA开发基础(第一期)', - 'imageUrl': $r('app.media.ic_img_10'), - 'price': 0 + superId: 3, + superName: 'HarmonyOS', + id: 20, + courseName: '应用开发基础:JS FA开发基础(第一期)', + imageUrl: $r('app.media.ic_img_10'), + price: 0 }, { - 'superId': 3, - 'superName': 'HarmonyOS', - 'id': 21, - 'courseName': 'HarmonyOS Connect设备开发基础:OpenHarmony基础', - 'imageUrl': $r('app.media.ic_img_1'), - 'price': 60 + superId: 3, + superName: 'HarmonyOS', + id: 21, + courseName: 'HarmonyOS Connect设备开发基础:OpenHarmony基础', + imageUrl: $r('app.media.ic_img_1'), + price: 60 }, { - 'superId': 3, - 'superName': 'HarmonyOS', - 'id': 22, - 'courseName': '组件开发和集成:SDK集成指南(第五期)', - 'imageUrl': $r('app.media.ic_img_2'), - 'price': 120 + superId: 3, + superName: 'HarmonyOS', + id: 22, + courseName: '组件开发和集成:SDK集成指南(第五期)', + imageUrl: $r('app.media.ic_img_2'), + price: 120 }, { - 'superId': 4, - 'superName': '精彩活动', - 'id': 23, - 'courseName': 'HUAWEI Developer Day•2018北京精彩回顾', - 'imageUrl': $r('app.media.ic_img_3'), - 'price': 0 + superId: 4, + superName: '精彩活动', + id: 23, + courseName: 'HUAWEI Developer Day•2018北京精彩回顾', + imageUrl: $r('app.media.ic_img_3'), + price: 0 }, { - 'superId': 4, - 'superName': '精彩活动', - 'id': 24, - 'courseName': '华为AR帮你轻松打造酷炫应用', - 'imageUrl': $r('app.media.ic_img_4'), - 'price': 99 + superId: 4, + superName: '精彩活动', + id: 24, + courseName: '华为AR帮你轻松打造酷炫应用', + imageUrl: $r('app.media.ic_img_4'), + price: 99 }, { - 'superId': 4, - 'superName': '精彩活动', - 'id': 25, - 'courseName': 'AR VR应用创新大赛获奖作品', - 'imageUrl': $r('app.media.ic_img_5'), - 'price': 30 + superId: 4, + superName: '精彩活动', + id: 25, + courseName: 'AR VR应用创新大赛获奖作品', + imageUrl: $r('app.media.ic_img_5'), + price: 30 }, { - 'superId': 4, - 'superName': '精彩活动', - 'id': 26, - 'courseName': '华为HiLink智能家居生态介绍', - 'imageUrl': $r('app.media.ic_img_6'), - 'price': 80 + superId: 4, + superName: '精彩活动', + id: 26, + courseName: '华为HiLink智能家居生态介绍', + imageUrl: $r('app.media.ic_img_6'), + price: 80 }, { - 'superId': 4, - 'superName': '精彩活动', - 'id': 27, - 'courseName': '华为校园千帆行丨武汉站', - 'imageUrl': $r('app.media.ic_img_7'), - 'price': 160 + superId: 4, + superName: '精彩活动', + id: 27, + courseName: '华为校园千帆行丨武汉站', + imageUrl: $r('app.media.ic_img_7'), + price: 160 }, { - 'superId': 4, - 'superName': '精彩活动', - 'id': 28, - 'courseName': 'HUAWEI Developer Day•杭州站精彩回顾', - 'imageUrl': $r('app.media.ic_img_8'), - 'price': 0 + superId: 4, + superName: '精彩活动', + id: 28, + courseName: 'HUAWEI Developer Day•杭州站精彩回顾', + imageUrl: $r('app.media.ic_img_8'), + price: 0 }, { - 'superId': 5, - 'superName': '开发者说', - 'id': 29, - 'courseName': '优秀实践分享 - 掌阅科技', - 'imageUrl': $r('app.media.ic_img_9'), - 'price': 0 + superId: 5, + superName: '开发者说', + id: 29, + courseName: '优秀实践分享 - 掌阅科技', + imageUrl: $r('app.media.ic_img_9'), + price: 0 }, { - 'superId': 5, - 'superName': '开发者说', - 'id': 30, - 'courseName': '极限试驾', - 'imageUrl': $r('app.media.ic_img_10'), - 'price': 130 + superId: 5, + superName: '开发者说', + id: 30, + courseName: '极限试驾', + imageUrl: $r('app.media.ic_img_10'), + price: 130 }, { - 'superId': 5, - 'superName': '开发者说', - 'id': 31, - 'courseName': 'AR狙击手', - 'imageUrl': $r('app.media.ic_img_11'), - 'price': 100 + superId: 5, + superName: '开发者说', + id: 31, + courseName: 'AR狙击手', + imageUrl: $r('app.media.ic_img_11'), + price: 100 }, { - 'superId': 5, - 'superName': '开发者说', - 'id': 32, - 'courseName': '宇宙解码', - 'imageUrl': $r('app.media.ic_img_12'), - 'price': 100 + superId: 5, + superName: '开发者说', + id: 32, + courseName: '宇宙解码', + imageUrl: $r('app.media.ic_img_12'), + price: 100 }, { - 'superId': 5, - 'superName': '开发者说', - 'id': 33, - 'courseName': 'Wars of Stone', - 'imageUrl': $r('app.media.ic_img_13'), - 'price': 1200 + superId: 5, + superName: '开发者说', + id: 33, + courseName: 'Wars of Stone', + imageUrl: $r('app.media.ic_img_13'), + price: 1200 }, { - 'superId': 5, - 'superName': '开发者说', - 'id': 34, - 'courseName': 'ROCK ME', - 'imageUrl': $r('app.media.ic_img_14'), - 'price': 156 + superId: 5, + superName: '开发者说', + id: 34, + courseName: 'ROCK ME', + imageUrl: $r('app.media.ic_img_14'), + price: 156 }, { - 'superId': 5, - 'superName': '开发者说', - 'id': 35, - 'courseName': '神奇AR智能宝宝', - 'imageUrl': $r('app.media.ic_img_15'), - 'price': 130 + superId: 5, + superName: '开发者说', + id: 35, + courseName: '神奇AR智能宝宝', + imageUrl: $r('app.media.ic_img_15'), + price: 130 }, { - 'superId': 6, - 'superName': '后端开发', - 'id': 36, - 'courseName': '从零开始学架构', - 'imageUrl': $r('app.media.ic_img_16'), - 'price': 120 + superId: 6, + superName: '后端开发', + id: 36, + courseName: '从零开始学架构', + imageUrl: $r('app.media.ic_img_16'), + price: 120 }, { - 'superId': 6, - 'superName': '后端开发', - 'id': 37, - 'courseName': '架构设计之异步化技术', - 'imageUrl': $r('app.media.ic_img_17'), - 'price': 0 + superId: 6, + superName: '后端开发', + id: 37, + courseName: '架构设计之异步化技术', + imageUrl: $r('app.media.ic_img_17'), + price: 0 }, { - 'superId': 6, - 'superName': '后端开发', - 'id': 38, - 'courseName': '架构设计之页面静态化技术', - 'imageUrl': $r('app.media.ic_img_18'), - 'price': 0 + superId: 6, + superName: '后端开发', + id: 38, + courseName: '架构设计之页面静态化技术', + imageUrl: $r('app.media.ic_img_18'), + price: 0 }, { - 'superId': 6, - 'superName': '后端开发', - 'id': 39, - 'courseName': 'Python极简入门', - 'imageUrl': $r('app.media.ic_img_9'), - 'price': 0 + superId: 6, + superName: '后端开发', + id: 39, + courseName: 'Python极简入门', + imageUrl: $r('app.media.ic_img_9'), + price: 0 }, { - 'superId': 6, - 'superName': '后端开发', - 'id': 40, - 'courseName': 'Python实践指南', - 'imageUrl': $r('app.media.ic_img_10'), - 'price': 2001 + superId: 6, + superName: '后端开发', + id: 40, + courseName: 'Python实践指南', + imageUrl: $r('app.media.ic_img_10'), + price: 2001 }, { - 'superId': 6, - 'superName': '后端开发', - 'id': 41, - 'courseName': 'Java高级特性', - 'imageUrl': $r('app.media.ic_img_1'), - 'price': 30 + superId: 6, + superName: '后端开发', + id: 41, + courseName: 'Java高级特性', + imageUrl: $r('app.media.ic_img_1'), + price: 30 }, { - 'superId': 6, - 'superName': '后端开发', - 'id': 42, - 'courseName': 'C++核心编程', - 'imageUrl': $r('app.media.ic_img_2'), - 'price': 50 + superId: 6, + superName: '后端开发', + id: 42, + courseName: 'C++核心编程', + imageUrl: $r('app.media.ic_img_2'), + price: 50 }, { - 'superId': 7, - 'superName': '移动开发', - 'id': 43, - 'courseName': 'EMUI 9.1主题转10.0主题适配指导', - 'imageUrl': $r('app.media.ic_img_3'), - 'price': 0 - }, + superId: 7, + superName: '移动开发', + id: 43, + courseName: 'EMUI 9.1主题转10.0主题适配指导', + imageUrl: $r('app.media.ic_img_3'), + price: 0 + }, { - 'superId': 7, - 'superName': '移动开发', - 'id': 44, - 'courseName': '“流体动效”手机锁屏制作', - 'imageUrl': $r('app.media.ic_img_4'), - 'price': 0 - }, + superId: 7, + superName: '移动开发', + id: 44, + courseName: '“流体动效”手机锁屏制作', + imageUrl: $r('app.media.ic_img_4'), + price: 0 + }, { - 'superId': 7, - 'superName': '移动开发', - 'id': 45, - 'courseName': '“震动”手机锁屏制作', - 'imageUrl': $r('app.media.ic_img_5'), - 'price': 0 - }, + superId: 7, + superName: '移动开发', + id: 45, + courseName: '“震动”手机锁屏制作', + imageUrl: $r('app.media.ic_img_5'), + price: 0 + }, { - 'superId': 8, - 'superName': '前端开发', - 'id': 46, - 'courseName': 'DevOps新技术入门', - 'imageUrl': $r('app.media.ic_img_6'), - 'price': 50 - }, + superId: 8, + superName: '前端开发', + id: 46, + courseName: 'DevOps新技术入门', + imageUrl: $r('app.media.ic_img_6'), + price: 50 + }, { - 'superId': 8, - 'superName': '前端开发', - 'id': 47, - 'courseName': 'Vue.js 框架开发系列课程', - 'imageUrl': $r('app.media.ic_img_7'), - 'price': 60 - }, + superId: 8, + superName: '前端开发', + id: 47, + courseName: 'Vue.js 框架开发系列课程', + imageUrl: $r('app.media.ic_img_7'), + price: 60 + }, { - 'superId': 8, - 'superName': '前端开发', - 'id': 48, - 'courseName': 'jQuery实例精讲', - 'imageUrl': $r('app.media.ic_img_8'), - 'price': 80 - }, + superId: 8, + superName: '前端开发', + id: 48, + courseName: 'jQuery实例精讲', + imageUrl: $r('app.media.ic_img_8'), + price: 80 + }, { - 'superId': 8, - 'superName': '前端开发', - 'id': 49, - 'courseName': 'JavaScript 编程技巧与实战', - 'imageUrl': $r('app.media.ic_img_9'), - 'price': 300 - }, + superId: 8, + superName: '前端开发', + id: 49, + courseName: 'JavaScript 编程技巧与实战', + imageUrl: $r('app.media.ic_img_9'), + price: 300 + }, { - 'superId': 8, - 'superName': '前端开发', - 'id': 50, - 'courseName': '基于 Bootstrap 框架开发技巧实战', - 'imageUrl': $r('app.media.ic_img_10'), - 'price': 150 - }, + superId: 8, + superName: '前端开发', + id: 50, + courseName: '基于 Bootstrap 框架开发技巧实战', + imageUrl: $r('app.media.ic_img_10'), + price: 150 + }, { - 'superId': 8, - 'superName': '前端开发', - 'id': 51, - 'courseName': 'Java Web开发课程', - 'imageUrl': $r('app.media.ic_img_11'), - 'price': 200 - }, + superId: 8, + superName: '前端开发', + id: 51, + courseName: 'Java Web开发课程', + imageUrl: $r('app.media.ic_img_11'), + price: 200 + }, { - 'superId': 8, - 'superName': '前端开发', - 'id': 52, - 'courseName': 'JavaScript 设计模式', - 'imageUrl': $r('app.media.ic_img_12'), - 'price': 0 - }, + superId: 8, + superName: '前端开发', + id: 52, + courseName: 'JavaScript 设计模式', + imageUrl: $r('app.media.ic_img_12'), + price: 0 + }, { - 'superId': 8, - 'superName': '前端开发', - 'id': 53, - 'courseName': 'HTML入门基础系列课程', - 'imageUrl': $r('app.media.ic_img_13'), - 'price': 0 - }, + superId: 8, + superName: '前端开发', + id: 53, + courseName: 'HTML入门基础系列课程', + imageUrl: $r('app.media.ic_img_13'), + price: 0 + }, { - 'superId': 8, - 'superName': '前端开发', - 'id': 54, - 'courseName': '前端系列第7期-微前端–架构介绍篇', - 'imageUrl': $r('app.media.ic_img_14'), - 'price': 100 - }, + superId: 8, + superName: '前端开发', + id: 54, + courseName: '前端系列第7期-微前端–架构介绍篇', + imageUrl: $r('app.media.ic_img_14'), + price: 100 + }, { - 'superId': 8, - 'superName': '前端开发', - 'id': 55, - 'courseName': 'Web安全系列课程', - 'imageUrl': $r('app.media.ic_img_15'), - 'price': 0 + superId: 8, + superName: '前端开发', + id: 55, + courseName: 'Web安全系列课程', + imageUrl: $r('app.media.ic_img_15'), + price: 0 } ] \ No newline at end of file diff --git a/ETSUI/SecondLevelLinkage/entry/src/main/ets/common/bean/CourseModel.ets b/ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/CourseModel.ets similarity index 94% rename from ETSUI/SecondLevelLinkage/entry/src/main/ets/common/bean/CourseModel.ets rename to ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/CourseModel.ets index d86284324237031a0f855958826e849e089132f7..9c2a9479be9362bc484dedc4c26532b455e97f6b 100644 --- a/ETSUI/SecondLevelLinkage/entry/src/main/ets/common/bean/CourseModel.ets +++ b/ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/CourseModel.ets @@ -16,7 +16,7 @@ /** * Course Model */ -export default class CourseModel { +export default interface CourseModel { classifyId: number; courseId: number; courseName: string; diff --git a/ETSUI/SecondLevelLinkage/entry/src/main/ets/common/bean/LinkDataModel.ets b/ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/LinkDataModel.ets similarity index 95% rename from ETSUI/SecondLevelLinkage/entry/src/main/ets/common/bean/LinkDataModel.ets rename to ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/LinkDataModel.ets index 347e46503f5b2b0342c1403bdb21643cfda3bc4c..31cf5a3dfb86b8a21e644d251ad476786637014b 100644 --- a/ETSUI/SecondLevelLinkage/entry/src/main/ets/common/bean/LinkDataModel.ets +++ b/ETSUI/SecondLevelLinkage/entry/src/main/ets/viewmodel/LinkDataModel.ets @@ -16,7 +16,7 @@ /** * initial data model. */ -export default class LinkDataModel { +export default interface LinkDataModel { /** * parentId */ diff --git a/ETSUI/SecondLevelLinkage/figures/oh_level_360.gif b/ETSUI/SecondLevelLinkage/figures/oh_level_360.gif deleted file mode 100644 index 3c6839560a00fc8069f1f24908e5e4b39f78e3f1..0000000000000000000000000000000000000000 Binary files a/ETSUI/SecondLevelLinkage/figures/oh_level_360.gif and /dev/null differ diff --git a/ETSUI/SecondLevelLinkage/figures/oh_level_360.png b/ETSUI/SecondLevelLinkage/figures/oh_level_360.png deleted file mode 100644 index 7225883931047652da4a2de360d757b74afe63be..0000000000000000000000000000000000000000 Binary files a/ETSUI/SecondLevelLinkage/figures/oh_level_360.png and /dev/null differ diff --git a/ETSUI/SecondLevelLinkage/figures/twolevel_320-0.png b/ETSUI/SecondLevelLinkage/figures/twolevel_320-0.png new file mode 100644 index 0000000000000000000000000000000000000000..a8044475b9ea5e2ecd5c95fba153fc9c54fffffa Binary files /dev/null and b/ETSUI/SecondLevelLinkage/figures/twolevel_320-0.png differ diff --git a/ETSUI/SecondLevelLinkage/figures/twolevel_320.gif b/ETSUI/SecondLevelLinkage/figures/twolevel_320.gif new file mode 100644 index 0000000000000000000000000000000000000000..7969508b12ef6dc34e563c0eac165df86ee37a89 Binary files /dev/null and b/ETSUI/SecondLevelLinkage/figures/twolevel_320.gif differ diff --git a/ETSUI/SecondLevelLinkage/figures/zh-cn_image_0000001554588725.png b/ETSUI/SecondLevelLinkage/figures/zh-cn_image_0000001681848240.png similarity index 100% rename from ETSUI/SecondLevelLinkage/figures/zh-cn_image_0000001554588725.png rename to ETSUI/SecondLevelLinkage/figures/zh-cn_image_0000001681848240.png diff --git a/ETSUI/SecondLevelLinkage/hvigor/hvigor-config.json5 b/ETSUI/SecondLevelLinkage/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/SecondLevelLinkage/hvigor/hvigor-config.json5 +++ b/ETSUI/SecondLevelLinkage/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/ETSUI/SimpleCalculator/README.md b/ETSUI/SimpleCalculator/README.md index 8beb9717d88644d97e331cc944dfdf60cdea65f5..d1d80634cbc3e22019f9e1f4ad3d4cb55195525d 100644 --- a/ETSUI/SimpleCalculator/README.md +++ b/ETSUI/SimpleCalculator/README.md @@ -8,8 +8,10 @@ >![](public_sys-resources/icon-note.gif) **说明:** >由于数字都是双精度浮点数,在计算机中是二进制存储数据的,因此小数和非安全整数(超过整数的安全范围[-Math.pow(2, 53),Math.pow(2, 53)]的数据)在计算过程中会存在精度丢失的情况。 ->1. 小数运算时:“0.2 + 2.22 = 2.4200000000000004”,当前示例的解决方法是将小数扩展到整数进行计算,计算完成之后再将结果缩小,计算过程为“(0.2 * 100 + 2.22 * 100) / 100 = 2.42”。 ->2. 非安全整数运算时:“9007199254740992 + 1 = 9.007199254740992”,当前示例中将长度超过15位的数字转换成科学计数法,计算结果为“9007199254740992 + 1 = 9.007199254740993e15”。 +> +>1、小数运算时:“0.2 + 2.22 = 2.4200000000000004”,当前示例的解决方法是将小数扩展到整数进行计算,计算完成之后再将结果缩小,计算过程为“(0.2 * 100 + 2.22 * 100) / 100 = 2.42”。 +> +>2、非安全整数运算时:“9007199254740992 + 1 = 9.007199254740992”,当前示例中将长度超过15位的数字转换成科学计数法,计算结果为“9007199254740992 + 1 = 9.007199254740993e15”。 ### 相关概念 @@ -21,13 +23,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -55,8 +57,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ └──PressKeysBean.ets // 按键bean类 │ │ ├──constants │ │ │ └──CommonConstants.ets // 公共常量类 │ │ └──util @@ -70,7 +70,8 @@ │ ├──pages │ │ └──HomePage.ets // 计算器页面 │ └──viewmodel -│ └──PresskeysBeanViewModel.ets // 计算器页面键盘数据 +│ ├──PressKeysItem.ets // 按键信息类 +│ └──PresskeysViewModel.ets // 计算器页面键盘数据 └──entry/src/main/resource // 应用静态资源目录 ``` @@ -124,11 +125,11 @@ Column() { ```typescript // HomePage.ets -ForEach(columnItem, (keyItem: PressKeysBean, keyItemIndex: number) => { +ForEach(columnItem, (keyItem: PressKeysItem, keyItemIndex?: number) => { Column() { Column() { if (keyItem.flag === 0) { - Image(keyItem.source) + Image(keyItem.source !== undefined ? keyItem.source : '') .width(keyItem.width) .height(keyItem.height) } else { @@ -160,7 +161,7 @@ ForEach(columnItem, (keyItem: PressKeysBean, keyItemIndex: number) => { (keyItemIndex === (columnItem.length - 1))) ? CommonConstants.TWO : 1 ) ... -}, keyItem => JSON.stringify(keyItem)) +}, (keyItem: PressKeysItem) => JSON.stringify(keyItem)) ``` ## 组装计算表达式 @@ -169,7 +170,7 @@ ForEach(columnItem, (keyItem: PressKeysBean, keyItemIndex: number) => { ```typescript // HomePage.ets -ForEach(columnItem, (keyItem: PressKeysBean, keyItemIndex: number) => { +ForEach(columnItem, (keyItem: PressKeysItem, keyItemIndex?: number) => { Column() { Column() { ... @@ -186,7 +187,7 @@ ForEach(columnItem, (keyItem: PressKeysBean, keyItemIndex: number) => { ... ) ... -}, keyItem => JSON.stringify(keyItem)) +}, (keyItem: PressKeysItem) => JSON.stringify(keyItem)) ``` >![](public_sys-resources/icon-note.gif) **说明:** @@ -369,7 +370,7 @@ inputOperators(len: number, value: string) { ```typescript // CalculateUtil.ets -parseExpression(expressions: Array) { +parseExpression(expressions: Array): string { ... let len = expressions.length; ... @@ -396,19 +397,24 @@ parseExpression(expressions: Array) { ```typescript // CalculateUtil.ets -parseExpression(expressions: Array) { +parseExpression(expressions: Array): string { ... while (expressions.length > 0) { let current = expressions.shift(); - if (this.isSymbol(current)) { - while (outputStack.length > 0 && - this.comparePriority(current, outputStack[outputStack.length - 1])) { - outputQueue.push(outputStack.pop()); - } - outputStack.push(current); - } else { - outputQueue.push(current); - } + if (current !== undefined) { + if (this.isSymbol(current)) { + while (outputStack.length > 0 && + this.comparePriority(current, outputStack[outputStack.length - 1])) { + let popValue: string | undefined = outputStack.pop(); + if (popValue !== undefined) { + outputQueue.push(popValue); + } + } + outputStack.push(current); + } else { + outputQueue.push(current); + } + } } while (outputStack.length > 0) { outputQueue.push(outputStack.pop()); @@ -427,24 +433,29 @@ parseExpression(expressions: Array) { // CalculateUtil.ets dealQueue(queue: Array) { ... - let outputStack = []; - while (queue.length > 0) { - let current = queue.shift(); - if (!this.isSymbol(current)) { - outputStack.push(current); - } else { - let second = outputStack.pop(); - let first = outputStack.pop(); - outputStack.push(this.calResult(first, second, current)); - } - } - if (outputStack.length !== 1) { - return NaN; - } else { - let end = outputStack[0].endsWith(CommonConstants.DOTS) ? + let outputStack: string[] = []; + while (queue.length > 0) { + let current: string | undefined = queue.shift(); + if (current !== undefined) { + if (!this.isSymbol(current)) { + outputStack.push(current); + } else { + let second: string | undefined = outputStack.pop(); + let first: string | undefined = outputStack.pop(); + if (first !== undefined && second !== undefined) { + let calResultValue: string = this.calResult(first, second, current) + outputStack.push(calResultValue); + } + } + } + } + if (outputStack.length !== 1) { + return 'NaN'; + } else { + let end = outputStack[0].endsWith(CommonConstants.DOTS) ? outputStack[0].substring(0, outputStack[0].length - 1) : outputStack[0]; - return end; - } + return end; + } } ``` diff --git a/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/CalculateUtil.ets b/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/CalculateUtil.ets index 9ef8acaa23e1530c33454d7cb76e8329951fe6a6..01d1b57418269dfcdd78f3b2396eb1c55bcdf671 100644 --- a/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/CalculateUtil.ets +++ b/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/CalculateUtil.ets @@ -66,7 +66,7 @@ class CalculateUtil { */ comparePriority(arg1: string, arg2: string): boolean { if (CheckEmptyUtil.isEmpty(arg1) || CheckEmptyUtil.isEmpty(arg2)) { - return; + return false; } return (this.getPriority(arg1) <= this.getPriority(arg2)); } @@ -76,13 +76,13 @@ class CalculateUtil { * * @param expressions Expressions. */ - parseExpression(expressions: Array) { + parseExpression(expressions: Array): string { if (CheckEmptyUtil.isEmpty(expressions)) { - return NaN; + return 'NaN'; } let len = expressions.length; - let outputStack = []; - let outputQueue = []; + let outputStack: string[] = []; + let outputQueue: string[] = []; expressions.forEach((item: string, index: number) => { // Handle % in the expression if (item.indexOf(CommonConstants.PERCENT_SIGN) !== -1) { @@ -96,20 +96,28 @@ class CalculateUtil { }); while (expressions.length > 0) { let current = expressions.shift(); - if (this.isSymbol(current)) { - // Processing addition, subtraction, multiplication and division. - while (outputStack.length > 0 && + if (current !== undefined) { + if (this.isSymbol(current)) { + // Processing addition, subtraction, multiplication and division. + while (outputStack.length > 0 && this.comparePriority(current, outputStack[outputStack.length - 1])) { - outputQueue.push(outputStack.pop()); + let popValue: string | undefined = outputStack.pop(); + if (popValue !== undefined) { + outputQueue.push(popValue); + } + } + outputStack.push(current); + } else { + // Processing the numbers. + outputQueue.push(current); } - outputStack.push(current); - } else { - // Processing the numbers. - outputQueue.push(current); } } while (outputStack.length > 0) { - outputQueue.push(outputStack.pop()); + let popValue: string | undefined = outputStack.pop(); + if (popValue !== undefined) { + outputQueue.push(popValue); + } } return this.dealQueue(outputQueue); } @@ -120,23 +128,28 @@ class CalculateUtil { * @param queue Expression Queue. * @return The end result. */ - dealQueue(queue: Array) { + dealQueue(queue: Array): string { if (CheckEmptyUtil.isEmpty(queue)) { - return NaN; + return 'NaN'; } - let outputStack = []; + let outputStack: string[] = []; while (queue.length > 0) { - let current = queue.shift(); - if (!this.isSymbol(current)) { - outputStack.push(current); - } else { - let second = outputStack.pop(); - let first = outputStack.pop(); - outputStack.push(this.calResult(first, second, current)); + let current: string | undefined = queue.shift(); + if (current !== undefined) { + if (!this.isSymbol(current)) { + outputStack.push(current); + } else { + let second: string | undefined = outputStack.pop(); + let first: string | undefined = outputStack.pop(); + if (first !== undefined && second !== undefined) { + let calResultValue: string = this.calResult(first, second, current) + outputStack.push(calResultValue); + } + } } } if (outputStack.length !== 1) { - return NaN; + return 'NaN'; } else { let end = outputStack[0].endsWith(CommonConstants.DOTS) ? outputStack[0].substring(0, outputStack[0].length - 1) : outputStack[0]; @@ -152,9 +165,9 @@ class CalculateUtil { * @param symbol Operators. * @return Calculation result. */ - calResult(arg1: string, arg2: string, symbol: string) { - if (CheckEmptyUtil.isEmpty(arg1) || CheckEmptyUtil.isEmpty(arg2), CheckEmptyUtil.isEmpty(symbol)) { - return NaN; + calResult(arg1: string, arg2: string, symbol: string): string { + if (CheckEmptyUtil.isEmpty(arg1) || CheckEmptyUtil.isEmpty(arg2) || CheckEmptyUtil.isEmpty(symbol)) { + return 'NaN'; } let result = 0; switch (symbol) { @@ -248,8 +261,8 @@ class CalculateUtil { * @param result Digital Results. */ numberToScientificNotation(result: number) { - if (result === Infinity) { - return NaN; + if (result === Number.NEGATIVE_INFINITY || result === Number.POSITIVE_INFINITY) { + return 'NaN'; } let resultStr = JSON.stringify(result); if ( this.containScientificNotation(resultStr)) { diff --git a/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/CheckEmptyUtil.ets b/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/CheckEmptyUtil.ets index 9443c1e2aa631795adb7bd933bd50b9e28842948..0a84fca859ace6be31ef783ebb59f1b3ca46bf3c 100644 --- a/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/CheckEmptyUtil.ets +++ b/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/CheckEmptyUtil.ets @@ -22,7 +22,7 @@ class CheckEmptyUtil { * @param {object} obj * @return {boolean} true(empty) */ - isEmpty(obj) { + isEmpty(obj: object | string): boolean { return (typeof obj === 'undefined' || obj === null || obj === ''); } @@ -32,7 +32,7 @@ class CheckEmptyUtil { * @param {string} str * @return {boolean} true(empty) */ - checkStrIsEmpty(str) { + checkStrIsEmpty(str: string): boolean { return str.trim().length === 0; } @@ -42,7 +42,7 @@ class CheckEmptyUtil { * @param {Array}arr * @return {boolean} true(empty) */ - isEmptyArr(arr) { + isEmptyArr(arr: Array): boolean { return arr.length === 0; } } diff --git a/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/Logger.ets b/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/Logger.ets index 059fd16db7bcc9578568affba99578f6fbb216f4..b6b493808fc2c9d82de9a4002d24a613b4c95ae4 100644 --- a/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/Logger.ets +++ b/ETSUI/SimpleCalculator/entry/src/main/ets/common/util/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/ETSUI/SimpleCalculator/entry/src/main/ets/model/CalculateModel.ets b/ETSUI/SimpleCalculator/entry/src/main/ets/model/CalculateModel.ets index fce0e8ef711cef91efa83dcc004b3c34617827f0..e00d32764fbbd499f06dd628b467732b85b9782a 100644 --- a/ETSUI/SimpleCalculator/entry/src/main/ets/model/CalculateModel.ets +++ b/ETSUI/SimpleCalculator/entry/src/main/ets/model/CalculateModel.ets @@ -17,12 +17,11 @@ import { CommonConstants, Symbol } from '../common/constants/CommonConstants'; import CalculateUtil from '../common/util/CalculateUtil'; import CheckEmptyUtil from '../common/util/CheckEmptyUtil'; import Logger from '../common/util/Logger'; - +import {IContext} from '../viewmodel/PressKeysBean'; export class CalculateModel { private expressions: Array = []; private context; - - constructor(context) { + constructor(context: IContext) { this.context = context; } @@ -225,12 +224,7 @@ export class CalculateModel { * @return deep copy expression. */ deepCopy(): Array { - let that = this; - let copyExpressions = Object.create(Object.getPrototypeOf(this.expressions)); - Object.getOwnPropertyNames(this.expressions).forEach((items: string) => { - let item = Object.getOwnPropertyDescriptor(that.expressions, items); - Object.defineProperty(copyExpressions, items, item); - }) + let copyExpressions: Array = Array.from(this.expressions); return copyExpressions; } @@ -241,7 +235,7 @@ export class CalculateModel { */ async getResult() { let calResult = CalculateUtil.parseExpression(this.deepCopy()); - if (isNaN(calResult)) { + if (calResult === 'NaN') { this.context.calValue = this.resourceToString($r('app.string.error')); return false; } @@ -256,7 +250,7 @@ export class CalculateModel { * @return Thousand percentile data. */ resultFormat(value: string) { - let reg = (value.indexOf('.') > -1) ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(?:\d{3})+$)/g; + let reg = (value.indexOf('.') > -1) ? new RegExp("/(\d)(?=(\d{3})+\.)/g") : new RegExp("/(\d)(?=(?:\d{3})+$)/g"); return value.replace(reg, '$1,'); } @@ -283,7 +277,7 @@ export class CalculateModel { * Thousands in the formatting result. */ formatInputValue() { - let deepExpressions = []; + let deepExpressions: Array = []; this.deepCopy().forEach((item: string, index: number) => { deepExpressions[index] = this.resultFormat(item); }); diff --git a/ETSUI/SimpleCalculator/entry/src/main/ets/pages/HomePage.ets b/ETSUI/SimpleCalculator/entry/src/main/ets/pages/HomePage.ets index e766e9b83d11a74ebe32b141ab778131d581d7cb..3fffda78686a47f2d059d3105003cb679eb3004c 100644 --- a/ETSUI/SimpleCalculator/entry/src/main/ets/pages/HomePage.ets +++ b/ETSUI/SimpleCalculator/entry/src/main/ets/pages/HomePage.ets @@ -15,8 +15,8 @@ import { CommonConstants } from '../common/constants/CommonConstants'; import { CalculateModel } from '../model/CalculateModel'; -import { PressKeysBean } from '../common/bean/PressKeysBean'; -import keysModel from '../viewmodel/PresskeysBeanViewModel'; +import { PressKeysItem } from '../viewmodel/PressKeysItem'; +import keysModel from '../viewmodel/PresskeysViewModel'; @Entry @Component @@ -24,7 +24,6 @@ struct HomePage { private model: CalculateModel = new CalculateModel(this); @State inputValue: string = ''; @State calValue: string = ''; - build() { Column() { Column() { @@ -62,13 +61,13 @@ struct HomePage { Column() { Row() { - ForEach(keysModel.getPressKeys(), (columnItem: Array, columnItemIndex: number) => { + ForEach(keysModel.getPressKeys(), (columnItem: Array, columnItemIndex?: number) => { Column() { - ForEach(columnItem, (keyItem: PressKeysBean, keyItemIndex: number) => { + ForEach(columnItem, (keyItem: PressKeysItem, keyItemIndex?: number) => { Column() { Column() { if (keyItem.flag === 0) { - Image(keyItem.source) + Image(keyItem.source !== undefined ? keyItem.source : '') .width(keyItem.width) .height(keyItem.height) } else { @@ -111,10 +110,10 @@ struct HomePage { ) .width(CommonConstants.FULL_PERCENT) .justifyContent(FlexAlign.Center) - }, keyItem => JSON.stringify(keyItem)) + }, (keyItem: PressKeysItem) => JSON.stringify(keyItem)) } .layoutWeight(1) - }, item => JSON.stringify(item)) + }, (item: Array>) => JSON.stringify(item)) } .height(CommonConstants.FULL_PERCENT) .alignItems(VerticalAlign.Top) diff --git a/ETSUI/SimpleCalculator/entry/src/main/ets/viewmodel/PressKeysItem.ets b/ETSUI/SimpleCalculator/entry/src/main/ets/viewmodel/PressKeysItem.ets new file mode 100644 index 0000000000000000000000000000000000000000..3e38a24587ab79aa0decab9c540e77a6f4f7e4e0 --- /dev/null +++ b/ETSUI/SimpleCalculator/entry/src/main/ets/viewmodel/PressKeysItem.ets @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class PressKeysItem { + flag: number; + width: string; + height: string; + value: string; + source?: Resource; + + constructor(flag: number, width: string, height: string, value: string, source?: Resource) { + this.flag = flag; + this.width = width; + this.height = height; + this.value = value; + this.source = source; + } +} +export class IContext{ + build: () => void; + inputValue: string; + calValue: string; + constructor(inputValue: string, calValue: string, build: () => void) { + this.calValue = calValue; + this.inputValue = inputValue; + this.build = build; + } +} \ No newline at end of file diff --git a/ETSUI/SimpleCalculator/entry/src/main/ets/viewmodel/PresskeysBeanViewModel.ets b/ETSUI/SimpleCalculator/entry/src/main/ets/viewmodel/PresskeysBeanViewModel.ets deleted file mode 100644 index c5dc0d27659f41b0c561adb6b193193b49cf9695..0000000000000000000000000000000000000000 --- a/ETSUI/SimpleCalculator/entry/src/main/ets/viewmodel/PresskeysBeanViewModel.ets +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { PressKeysBean } from '../common/bean/PressKeysBean'; - -export class PressKeysBeanViewModel { - - /** - * Key array data. - */ - getPressKeys(): Array>{ - return [ - [ - { - flag: 0, - width: '32vp', - height: '32vp', - value: 'clean', - source: $r('app.media.ic_clean') - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '7' - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '4' - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '1' - }, - { - flag: 1, - width: '25vp', - height: '43vp', - value: '%' - } - ], - [ - { - flag: 0, - width: '32vp', - height: '32vp', - value: 'div', - source: $r('app.media.ic_div') - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '8' - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '5' - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '2' - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '0' - } - ], - [ - { - flag: 0, - width: '32vp', - height: '32vp', - value: 'mul', - source: $r('app.media.ic_mul') - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '9' - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '6' - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '3' - }, - { - flag: 1, - width: '19vp', - height: '43vp', - value: '.' - } - ], - [ - { - flag: 0, - width: '30.48vp', - height: '20vp', - value: 'del', - source: $r('app.media.ic_del') - }, - { - flag: 0, - width: '24vp', - height: '24vp', - value: 'min', - source: $r('app.media.ic_min') - }, - { - flag: 0, - width: '32vp', - height: '32vp', - value: 'add', - source: $r('app.media.ic_add') - }, - { - flag: 0, - width: '32vp', - height: '32vp', - value: 'equ', - source: $r('app.media.ic_equ') - } - ] - ]; - } -} - -let keysModel = new PressKeysBeanViewModel(); -export default keysModel as PressKeysBeanViewModel; \ No newline at end of file diff --git a/ETSUI/SimpleCalculator/entry/src/main/ets/viewmodel/PresskeysViewModel.ets b/ETSUI/SimpleCalculator/entry/src/main/ets/viewmodel/PresskeysViewModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..585fcf3d8df69daa927285af9f41b2366eb8de25 --- /dev/null +++ b/ETSUI/SimpleCalculator/entry/src/main/ets/viewmodel/PresskeysViewModel.ets @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PressKeysItem } from './PressKeysItem'; + +export class PressKeysViewModel { + + /** + * Key array data. + */ + getPressKeys(): Array>{ + return [ + [ + new PressKeysItem(0, '32vp', '32vp', 'clean', $r('app.media.ic_clean')), + new PressKeysItem(1, '19vp', '43vp', '7'), + new PressKeysItem(1, '19vp', '43vp', '4'), + new PressKeysItem(1, '19vp', '43vp', '1'), + new PressKeysItem(1, '25vp', '43vp', '%') + // { + // flag: 0, + // width: '32vp', + // height: '32vp', + // value: 'clean', + // source: $r('app.media.ic_clean') + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '7' + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '4' + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '1' + // }, + // { + // flag: 1, + // width: '25vp', + // height: '43vp', + // value: '%' + // } + ], + [ + new PressKeysItem(0, '32vp', '32vp', 'div', $r('app.media.ic_div')), + new PressKeysItem(1, '19vp', '43vp', '8'), + new PressKeysItem(1, '19vp', '43vp', '5'), + new PressKeysItem(1, '19vp', '43vp', '2'), + new PressKeysItem(1, '19vp', '43vp', '0') + // { + // flag: 0, + // width: '32vp', + // height: '32vp', + // value: 'div', + // source: $r('app.media.ic_div') + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '8' + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '5' + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '2' + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '0' + // } + ], + [ + new PressKeysItem(0, '32vp', '32vp', 'mul', $r('app.media.ic_mul')), + new PressKeysItem(1, '19vp', '43vp', '9'), + new PressKeysItem(1, '19vp', '43vp', '6'), + new PressKeysItem(1, '19vp', '43vp', '3'), + new PressKeysItem(1, '19vp', '43vp', '.') + // { + // flag: 0, + // width: '32vp', + // height: '32vp', + // value: 'mul', + // source: $r('app.media.ic_mul') + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '9' + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '6' + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '3' + // }, + // { + // flag: 1, + // width: '19vp', + // height: '43vp', + // value: '.' + // } + ], + [ + new PressKeysItem(0, '30.48vp', '20vp', 'del', $r('app.media.ic_del')), + new PressKeysItem(0, '24vp', '24vp', 'min', $r('app.media.ic_min')), + new PressKeysItem(0, '32vp', '32vp', 'add', $r('app.media.ic_add')), + new PressKeysItem(0, '32vp', '32vp', 'equ', $r('app.media.ic_equ')) + // { + // flag: 0, + // width: '30.48vp', + // height: '20vp', + // value: 'del', + // source: $r('app.media.ic_del') + // }, + // { + // flag: 0, + // width: '24vp', + // height: '24vp', + // value: 'min', + // source: $r('app.media.ic_min') + // }, + // { + // flag: 0, + // width: '32vp', + // height: '32vp', + // value: 'add', + // source: $r('app.media.ic_add') + // }, + // { + // flag: 0, + // width: '32vp', + // height: '32vp', + // value: 'equ', + // source: $r('app.media.ic_equ') + // } + ] + ]; + } +} + +let keysModel = new PressKeysViewModel(); +export default keysModel as PressKeysViewModel; \ No newline at end of file diff --git a/ETSUI/SimpleCalculator/hvigor/hvigor-config.json5 b/ETSUI/SimpleCalculator/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/ETSUI/SimpleCalculator/hvigor/hvigor-config.json5 +++ b/ETSUI/SimpleCalculator/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/ETSUI/SliderExample/README.md b/ETSUI/SliderExample/README.md index a430d2252a048bec1b136a473aa65cc3b60ed9ff..7d287f85f1a4f28ccdb072a8939ae9394f9d92f6 100644 --- a/ETSUI/SliderExample/README.md +++ b/ETSUI/SliderExample/README.md @@ -16,13 +16,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -41,8 +41,7 @@ 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 - +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 │ ├──common @@ -57,7 +56,7 @@ ``` ## 页面结构 -整个程序的页面构造十分简洁,由Image组件构成风车。自定义组件PanelComponent由Text组件和Slider组件构成,用来显示文本和控制图像,具体效果如下图所示: +整个程序的页面构造十分简洁,由Image组件构成风车。自定义组件PanelComponent由Text组件和Slider组件构成,用来显示文本和控制图像,效果如图所示: ![](figures/image1.png) @@ -66,6 +65,7 @@ 在SliderPage文件中,添加Image组件,给定使用图片的路径,并配置通用属性[图形变换](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-transformation.md)中的rotate属性和scale属性。自此,页面中已经有了风车的图像。 ```typescript +// SliderPage.ets ... build() { Column() { @@ -89,7 +89,7 @@ ... ``` -效果如下: +效果如图所示: ![](figures/image2.png) @@ -98,16 +98,16 @@ 在speedChange\(\)函数中,以固定的时间间隔调整rotate的角度,也就是参数angle。onPageShow是SliderPage页面的生命周期方法,在其中调用speedChange\(\)函数,表示从程序启动时,便开始执行。自此我们已经实现了风车的旋转效果。代码如下: ```typescript +// SliderPage.ets ... - speedChange() { - let that = this; + speedChange(): void { this.angle = Constants.ANGLE; - this.interval = setInterval(function () { - that.angle += that.speed; + this.interval = setInterval(() => { + this.angle += this.speed; }, Constants.DELAY_TIME) } - onPageShow() { + onPageShow(): void { clearInterval(this.interval); this.speedChange(); } @@ -119,6 +119,8 @@ 在PanelComponent的构造参数中,给定调节转速的初始值和样式。在callback事件中,将子组件Slider滑动的value给到事先定义好的变量speed,实现Text组件的更新,并且通过调用speedChange\(\)方法实现转速的改变。代码如下: ```typescript +// SliderPage.ets +... PanelComponent({ mode: SliderMode.SPEED, title: $r('app.string.speed_text'), @@ -136,6 +138,7 @@ PanelComponent({ style: SliderStyle.InSet } }) +... ``` ## 调节风车的大小 @@ -143,6 +146,8 @@ PanelComponent({ 在PanelComponent的构造参数中,给定调节大小的初始值和样式。在callback事件中,将子组件Slider滑动的value给到事先定义好的变量imageSize,实现Text组件的更新和调节风车大小。代码如下: ```typescript +// SliderPage.ets +... PanelComponent({ mode: SliderMode.SCALE, title: $r('app.string.scale_text'), @@ -157,8 +162,12 @@ PanelComponent({ step: SliderScale.STEP, style: SliderStyle.InSet } -}).margin({ bottom: Constants.PANEL_MARGIN_BOTTOM, - top: Constants.PANEL_MARGIN_TOP }); +}) +.margin({ + bottom: Constants.PANEL_MARGIN_BOTTOM, + top: Constants.PANEL_MARGIN_TOP +}); +... ``` ## 总结 @@ -170,11 +179,3 @@ PanelComponent({ 4. 通用属性rotate和scale属性的使用。 ![](figures/finished.gif) - - - - - - - - diff --git a/ETSUI/SliderExample/entry/src/main/ets/common/Constants.ets b/ETSUI/SliderExample/entry/src/main/ets/common/Constants.ets index 25efaad77d30ec8f85c9de376d493575f36c3cf1..77208c654359a884b645057f3f627adc95f69285 100644 --- a/ETSUI/SliderExample/entry/src/main/ets/common/Constants.ets +++ b/ETSUI/SliderExample/entry/src/main/ets/common/Constants.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -202,16 +202,4 @@ export class Constants { * The margin of panel. */ static readonly PANEL_MARGIN = 10; -} - - - - - - - - - - - - +} \ No newline at end of file diff --git a/ETSUI/SliderExample/entry/src/main/ets/entryability/EntryAbility.ts b/ETSUI/SliderExample/entry/src/main/ets/entryability/EntryAbility.ts index 2f8dcfc131680b011887e97bc9ac7b26f7dc9bfb..7654d47695571fed01a5e1e6c58a99d558189af5 100644 --- a/ETSUI/SliderExample/entry/src/main/ets/entryability/EntryAbility.ts +++ b/ETSUI/SliderExample/entry/src/main/ets/entryability/EntryAbility.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,10 +15,12 @@ import hilog from '@ohos.hilog'; import UIAbility from '@ohos.app.ability.UIAbility'; -import Window from '@ohos.window'; +import type window from '@ohos.window'; +import type Want from '@ohos.app.ability.Want'; +import type AbilityConstant from '@ohos.app.ability.AbilityConstant'; export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { globalThis.abilityWant = want; hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); @@ -26,12 +28,12 @@ export default class EntryAbility extends UIAbility { hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); } - onDestroy() { + onDestroy(): void | Promise { hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); } - onWindowStageCreate(windowStage: Window.WindowStage) { + onWindowStageCreate(windowStage: window.WindowStage): void { // Main window is created, set main page for this ability hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); @@ -47,19 +49,19 @@ export default class EntryAbility extends UIAbility { }); } - onWindowStageDestroy() { + onWindowStageDestroy(): void { // Main window is destroyed, release UI related resources hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); } - onForeground() { + onForeground(): void { // Ability has brought to foreground hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); } - onBackground() { + onBackground(): void { // Ability has back to background hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); diff --git a/ETSUI/SliderExample/entry/src/main/ets/pages/SliderPage.ets b/ETSUI/SliderExample/entry/src/main/ets/pages/SliderPage.ets index 7c03890f31f920208164bf6b39eaa80c48c80411..99213acd99f7b32901eea84ae27abfc589031b0f 100644 --- a/ETSUI/SliderExample/entry/src/main/ets/pages/SliderPage.ets +++ b/ETSUI/SliderExample/entry/src/main/ets/pages/SliderPage.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -70,25 +70,24 @@ struct SliderPage { style: SliderStyle.InSet } }) - .margin({ - bottom: Constants.PANEL_MARGIN_BOTTOM, - top: Constants.PANEL_MARGIN_TOP - }); + .margin({ + bottom: Constants.PANEL_MARGIN_BOTTOM, + top: Constants.PANEL_MARGIN_TOP + }); } .justifyContent(FlexAlign.End) .height(Constants.PERCENTAGE_100) .backgroundColor($r('app.color.background_color')) } - speedChange() { - let that = this; + speedChange(): void { this.angle = Constants.ANGLE; - this.interval = setInterval(function () { - that.angle += that.speed; + this.interval = setInterval(() => { + this.angle += this.speed; }, Constants.DELAY_TIME) } - onPageShow() { + onPageShow(): void { clearInterval(this.interval); this.speedChange(); } diff --git a/ETSUI/SliderExample/entry/src/main/ets/view/PanelComponent.ets b/ETSUI/SliderExample/entry/src/main/ets/view/PanelComponent.ets index d4c76e15bb1ff46d06eb147e2c652f0cb15ea5d5..5d02671c3a98b15fb4cd4a9e910c5de036c1d646 100644 --- a/ETSUI/SliderExample/entry/src/main/ets/view/PanelComponent.ets +++ b/ETSUI/SliderExample/entry/src/main/ets/view/PanelComponent.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,11 +17,11 @@ import { Constants, SliderMode } from '../common/Constants'; @Component export struct PanelComponent { - @Prop text: string ; - private title: Resource; - private mode: SliderMode; + @Prop text: string = ''; + private title?: Resource; + private mode?: SliderMode; private options?: SliderOptions; - private callback: (value: number, mode: SliderChangeMode) => void; + private callback: (value: number, mode: SliderChangeMode) => void = () => {}; build() { Column() { diff --git a/ETSUI/SliderExample/hvigor/hvigor-config.json5 b/ETSUI/SliderExample/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/SliderExample/hvigor/hvigor-config.json5 +++ b/ETSUI/SliderExample/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/ETSUI/SwiperArkTS/README.md b/ETSUI/SwiperArkTS/README.md index 38a9c0c7675f37d6782a0f10034eddaae2a84430..fc8aed4d33b798999d2b74a7e6fca543ef3485c5 100644 --- a/ETSUI/SwiperArkTS/README.md +++ b/ETSUI/SwiperArkTS/README.md @@ -19,13 +19,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -53,10 +53,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──PictureItem.ets // 图片bean -│ │ │ ├──TopBarItem.ets // 顶部导航bean -│ │ │ └──VideoItem.ets // 视频bean │ │ └──constants │ │ ├──CommonConstant.ets // 公共常量 │ │ ├──PictureConstants.ets // 图片所使用的常量 @@ -89,9 +85,12 @@ │ │ ├──PageMovie.ets // 电影tab页 │ │ └──PageTV.ets // 电视tab页 │ └──viewmodel -│ ├──PictureViewModel.ets // 图片model -│ ├──TopBarViewModel.ets // 顶部导航model -│ └──VideoViewModel.ets // 视频model +│ ├──PictureItem.ets // 图片对象 +│ ├──PictureViewModel.ets // 图片模型 +│ ├──TopBarItem.ets // 顶部导航对象 +│ ├──TopBarViewModel.ets // 顶部导航模型 +│ ├──VideoItem.ets // 视频对象 +│ └──VideoViewModel.ets // 视频模型 └──entry/src/main/resources // 应用资源目录 ``` @@ -107,8 +106,6 @@ ```typescript // SwiperIndex.ets -@Entry -@Component struct SwiperIndex { // 索引值双向绑定 实现联动效果. @State index: number = 0; @@ -140,7 +137,6 @@ struct SwiperIndex { ```typescript // TopBar.ets -@Component export struct TopBar { // 索引值双向绑定 实现联动效果 @Link index: number; @@ -158,7 +154,7 @@ export struct TopBar { .onClick(() => { this.index = item.id; }) - }, item => JSON.stringify(item)) + }, (item: TopBarItem) => JSON.stringify(item)) } .margin({ left: CommonConstants.ADS_LEFT }) .width(CommonConstants.FULL_WIDTH) @@ -201,7 +197,7 @@ export function startPlay(swiperController: SwiperController) { // Banner.ets build() { Swiper(this.swiperController) { - ForEach(this.imageArray, item => { + ForEach(this.imageArray, (item: PictureItem) => { Stack({ alignContent: Alignment.TopStart }) { Image(item.image) ... @@ -216,7 +212,7 @@ build() { } .height(CommonConstants.FULL_HEIGHT) .width(CommonConstants.FULL_WIDTH) - }, item => JSON.stringify(item)) + }, (item: PictureItem) => JSON.stringify(item)) } ... } @@ -242,7 +238,7 @@ build() { item: item, barPosition: index }); - }, item => JSON.stringify(item)) + }, (item: VideoItem) => JSON.stringify(item)) } .width(CommonConstants.FULL_WIDTH) .height(CommonConstants.FULL_HEIGHT) @@ -267,7 +263,7 @@ build() { controller: this.videoController }) .controls(false) - .autoPlay(this.playState === PlayState.START ? true : false) // 首次可见状态自动播放 + .autoPlay(this.playState === PlayState.START ? true : false) .objectFit(ImageFit.Fill) .loop(true) .height(CommonConstants.WIDTH_VIDEO) diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/CommonConstant.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/CommonConstant.ets index 5cea07e0153a96516e34a04d74254c9e4e378d6e..f7f075d76aac5a6010d015615879594bc991b043 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/CommonConstant.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/CommonConstant.ets @@ -21,282 +21,226 @@ export class CommonConstants { * animation duration of content switching. */ static readonly DURATION_ADS = 200; - /** * Height of head portrait. */ static readonly HEIGHT_HEAD = 40; - /** * Height of carousel title. */ static readonly HEIGHT_CAROUSEL_TITLE = 90; - /** * Font size of tab page which content has only tab name. */ static readonly FONT_SIZE_PAGE_CONTENT = 28; - /** * Thinner font. */ static readonly FONT_WEIGHT_LIGHT = 400; - /** * Normal font. */ static readonly FONT_WEIGHT_NORMAL = 500; - /** * Bold font. */ static readonly FONT_WEIGHT_BOLD = 700; - /** * Page layout weight. */ static readonly LAYOUT_WEIGHT = 1; - /** * Border angle. */ static readonly BORDER_RADIUS = 12; - /** * Line height for more. */ static readonly LINE_HEIGHT_MORE = 19; - /** * Line height for navigation. */ static readonly LINE_HEIGHT_NAVIGATION = 28; - /** * Space of topBar. */ static readonly SPACE_TOP_BAR = 16; - /** * Space of navigation. */ static readonly SPACE_NAVIGATION = 8; - /** * Border width of head portrait. */ static readonly WIDTH_HEAD_BORDER = 2; - /** * Width of head portrait. */ static readonly WIDTH_HEAD = 40; - /** * Radius of head portrait. */ static readonly RADIUS_HEAD = 20; - /** * Rolling duration. */ static readonly SWIPER_TIME = 1500; - /** * Margin of play page. */ static readonly MARGIN_PLAY_PAGE = 10; - /** * Margin of text bottom. */ static readonly BOTTOM_TEXT = 4; - /** * Margin of banner top. */ static readonly TOP_ADS = 12; - /** * Margin of navigation left. */ static readonly LEFT_NAVIGATION = 20; - /** * Margin of banner left. */ static readonly ADS_LEFT = 12; - /** * Top margin of picture name. */ static readonly TOP_NAME = 8; - /** * Top margin of picture description. */ static readonly TOP_DESCRIPTION = 4; - /** * Top margin of vote icon. */ static readonly TOP_IMAGE_VOTE = 20; - /** * Top margin of head portrait. */ static readonly TOP_HEAD = 40; - /** * Maximum width. */ static readonly FULL_WIDTH = '100%'; - /** * Maximum height. */ static readonly FULL_HEIGHT = '100%'; - /** * Width of play model. */ static readonly WIDTH_PLAY = '95%'; - /** * Width of tab page. */ static readonly PAGE_WIDTH = '94.4%'; - /** * Width of sort name. */ static readonly WIDTH_SORT_NAME = '62.2%'; - /** * Sort content width of all. */ static readonly WIDTH_SORT = '92%'; - /** * Sort content width of movie. */ static readonly WIDTH_MOVIE_SORT = '90%'; - /** * Width of picture. */ static readonly WIDTH_PICTURE = '72%'; - /** * Height of banner. */ static readonly HEIGHT_BANNER = '27%'; - /** * Width of vote icon. */ static readonly WIDTH_VOTE = '8.9%'; - /** * Width of back icon. */ static readonly WIDTH_BACK_ICON = '6.7%'; - /** * Top margin of sort. */ static readonly MARGIN_TOP_SORT = '3.2%'; - /** * Bottom margin of sort. */ static readonly MARGIN_BOTTOM_SORT = '1.7%'; - /** * Bottom margin of grid. */ static readonly MARGIN_BOTTOM_GRID = '4.2%'; - /** * Height of video. */ static readonly WIDTH_VIDEO = '26.2%'; - /** * Number of columns. */ static readonly TWO_COLUMNS = '1fr 1fr'; - /** * Number of rows. */ static readonly TWO_ROWS = '1fr 1fr'; - /** * Number of columns. */ static readonly THREE_COLUMNS = '1fr 1fr 1fr'; - /** * Number of rows. */ static readonly THREE_ROWS = '1fr 1fr 1fr'; - /** * Gap of columns. */ static readonly GAP_COLUMNS = '2.2%'; - /** * Height of grid. */ static readonly HEIGHT_GRID = '45%'; - /** * Height of movie description. */ static readonly HEIGHT_DESCRIPTION = '12.3%'; - /** * Height of top bar. */ static readonly TOP_BAR_HEIGHT = '7.2%'; - /** * Height of comment icon. */ static readonly HEIGHT_COMMENT = '4.1%'; - /** * Height of back icon. */ static readonly HEIGHT_BACK_ICON = '3.1%'; - /** * Horizontal position of comment. */ static readonly OFFSET_COMMENT_X = '-5%'; - /** * Vertical position of comment. */ static readonly OFFSET_COMMENT_Y = '10%'; - /** * Vertical position of description. */ static readonly OFFSET_DESCRIPTION_Y = '45%'; - /** * Start position. */ static readonly START_POSITION = '0%'; - /** * Video play page. */ static readonly PLAY_PAGE = 'pages/PageVideo'; - /** * Home page. */ diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/PictureConstants.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/PictureConstants.ets index e5c48896f81692e1dd0a96805f422a6c26dddc77..3559ddfb81be22c5b7629f0dd0b0aead28979e06 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/PictureConstants.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/PictureConstants.ets @@ -13,50 +13,50 @@ * limitations under the License. */ -import { PictureItem } from '../bean/PictureItem'; +import { PictureItem } from '../../viewmodel/PictureItem'; /** * Pictures of banner. */ export const PICTURE_BANNER: PictureItem[] = [ - { 'id': '1', 'name': '怒海', 'description': '怒海波涛', 'image': $r("app.media.ic_image1") }, - { 'id': '2', 'name': '大山深处', 'description': '大山深处感人的亲情之歌', 'image': $r("app.media.ic_image2") }, - { 'id': '3', 'name': '荒漠', 'description': '荒漠的亲情之歌', 'image': $r("app.media.ic_image3") } + { id: '1', name: '怒海', description: '怒海波涛', image: $r("app.media.ic_image1") }, + { id: '2', name: '大山深处', description: '大山深处感人的亲情之歌', image: $r("app.media.ic_image2") }, + { id: '3', name: '荒漠', description: '荒漠的亲情之歌', image: $r("app.media.ic_image3") } ]; /** * pictures of recently play. */ export const PICTURE_RECENTLY: PictureItem[] = [ - { 'id': '1', 'name': '背影', 'description': '感人的亲情之歌', 'image': $r("app.media.ic_recently1") }, - { 'id': '2', 'name': '废墟之上', 'description': '勇闯无人之境', 'image': $r("app.media.ic_recently2") }, - { 'id': '3', 'name': '无根之人', 'description': '悬疑国产力作', 'image': $r("app.media.ic_recently3") }, - { 'id': '4', 'name': '摩天轮', 'description': '每个人心中都有一个童话', 'image': $r("app.media.ic_recently4") } + { id: '1', name: '背影', description: '感人的亲情之歌', image: $r("app.media.ic_recently1") }, + { id: '2', name: '废墟之上', description: '勇闯无人之境', image: $r("app.media.ic_recently2") }, + { id: '3', name: '无根之人', description: '悬疑国产力作', image: $r("app.media.ic_recently3") }, + { id: '4', name: '摩天轮', description: '每个人心中都有一个童话', image: $r("app.media.ic_recently4") } ]; /** * pictures of photo. */ export const PICTURE_PHOTO: PictureItem[] = [ - { 'id': '1', 'name': '蓝·静', 'description': '用放大镜看世界', 'image': $r("app.media.ic_photo1") }, - { 'id': '2', 'name': '花', 'description': '每个人心中都有一个童话', 'image': $r("app.media.ic_photo2") }, - { 'id': '3', 'name': '无根之人', 'description': '悬疑国产力作', 'image': $r("app.media.ic_recently3") }, - { 'id': '4', 'name': '摩天轮', 'description': '每个人心中都有一个童话', 'image': $r("app.media.ic_recently4") } + { id: '1', name: '蓝·静', description: '用放大镜看世界', image: $r("app.media.ic_photo1") }, + { id: '2', name: '花', description: '每个人心中都有一个童话', image: $r("app.media.ic_photo2") }, + { id: '3', name: '无根之人', description: '悬疑国产力作', image: $r("app.media.ic_recently3") }, + { id: '4', name: '摩天轮', description: '每个人心中都有一个童话', image: $r("app.media.ic_recently4") } ]; /** * pictures of newest. */ export const PICTURE_LATEST: PictureItem[] = [ - { 'id': '1', 'name': '潮·设计大会', 'description': '国际设计大师分...', 'image': $r('app.media.ic_movie1') }, - { 'id': '2', 'name': '食客', 'description': '味蕾爆炸', 'image': $r('app.media.ic_movie2') }, - { 'id': '3', 'name': '绿野仙踪', 'description': '热带雨林的故事', 'image': $r('app.media.ic_movie3') }, - { 'id': '4', 'name': '塔', 'description': '2021最期待的电...', 'image': $r('app.media.ic_movie4') }, - { 'id': '5', 'name': '微缩世界', 'description': '用放大镜看世界', 'image': $r('app.media.ic_movie5') }, - { 'id': '6', 'name': '非常规接触', 'description': '少年的奇妙之旅', 'image': $r('app.media.ic_movie6') }, - { 'id': '7', 'name': '绿野仙踪', 'description': '热带雨林的故事', 'image': $r('app.media.ic_movie7') }, - { 'id': '8', 'name': '塔', 'description': '用放大镜看世界', 'image': $r('app.media.ic_movie8') }, - { 'id': '9', 'name': '食客', 'description': '热带雨林的故事', 'image': $r('app.media.ic_movie9') } + { id: '1', name: '潮·设计大会', description: '国际设计大师分...', image: $r('app.media.ic_movie1') }, + { id: '2', name: '食客', description: '味蕾爆炸', image: $r('app.media.ic_movie2') }, + { id: '3', name: '绿野仙踪', description: '热带雨林的故事', image: $r('app.media.ic_movie3') }, + { id: '4', name: '塔', description: '2021最期待的电...', image: $r('app.media.ic_movie4') }, + { id: '5', name: '微缩世界', description: '用放大镜看世界', image: $r('app.media.ic_movie5') }, + { id: '6', name: '非常规接触', description: '少年的奇妙之旅', image: $r('app.media.ic_movie6') }, + { id: '7', name: '绿野仙踪', description: '热带雨林的故事', image: $r('app.media.ic_movie7') }, + { id: '8', name: '塔', description: '用放大镜看世界', image: $r('app.media.ic_movie8') }, + { id: '9', name: '食客', description: '热带雨林的故事', image: $r('app.media.ic_movie9') } ]; /** diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/TopBarConstants.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/TopBarConstants.ets index 6a0195d71509a3ad30d70d2229ce231522e7d73e..e912d139cc1dd08b2c234b9283014350cb5b63ee 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/TopBarConstants.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/TopBarConstants.ets @@ -13,16 +13,16 @@ * limitations under the License. */ -import { TopBarItem } from '../bean/TopBarItem'; +import { TopBarItem } from '../../viewmodel/TopBarItem'; /** * Data of top bar. */ export const TOP_BAR_DATA: TopBarItem[] = [ - { 'id': 0, 'name': '全部' }, - { 'id': 1, 'name': '电影' }, - { 'id': 2, 'name': '电视剧' }, - { 'id': 3, 'name': '综艺' }, - { 'id': 4, 'name': '直播' }, - { 'id': 5, 'name': '游戏' } + { id: 0, name: '全部' }, + { id: 1, name: '电影' }, + { id: 2, name: '电视剧' }, + { id: 3, name: '综艺' }, + { id: 4, name: '直播' }, + { id: 5, name: '游戏' } ] \ No newline at end of file diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/VideoConstants.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/VideoConstants.ets index 16313f0eab3580216986a419f855f1f04b96fed7..d54119fde0b821f75ce09a763e889434693a32c7 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/VideoConstants.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/common/constants/VideoConstants.ets @@ -13,27 +13,27 @@ * limitations under the License. */ -import { VideoItem } from '../bean/VideoItem'; +import { VideoItem } from '../../viewmodel/VideoItem'; /** * Data of video. */ export const VIDEO_DATA: VideoItem[] = [ { - 'id': '1', - 'src': $rawfile('video1.mp4'), - 'likesCount': 0, - 'isLikes': false, - 'comment': 102, - 'shareTimes': 666 + id: '1', + src: $rawfile('video1.mp4'), + likesCount: 0, + isLikes: false, + comment: 102, + shareTimes: 666 }, { - 'id': '2', - 'src': $rawfile('video2.mp4'), - 'likesCount': 8654, - 'isLikes': true, - 'comment': 0, - 'shareTimes': 0 + id: '2', + src: $rawfile('video2.mp4'), + likesCount: 8654, + isLikes: true, + comment: 0, + shareTimes: 0 } ]; diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/pages/PageVideo.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/pages/PageVideo.ets index 0cd08512d6b147763096bd7824b10dc5f9c7f8bb..987a479c93c1df4bbed35570b763fb3a660293ee 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/pages/PageVideo.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/pages/PageVideo.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { VideoItem } from '../common/bean/VideoItem'; +import { VideoItem } from '../viewmodel/VideoItem'; import { initializeOnStartup } from '../viewmodel/VideoViewModel'; import { PlayView } from '../view/play/PlayView'; import { CommonConstants } from '../common/constants/CommonConstant'; @@ -38,7 +38,7 @@ struct PageVideo { item: item, barPosition: index }); - }, item => JSON.stringify(item)) + }, (item: VideoItem) => JSON.stringify(item)) } .width(CommonConstants.FULL_WIDTH) .height(CommonConstants.FULL_HEIGHT) diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/pages/SwiperIndex.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/pages/SwiperIndex.ets index 99f3041830e262873bf4ba45d927b830b3760070..42e74aab39c2d5ba74b63e8a23b4be4362e8a580 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/pages/SwiperIndex.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/pages/SwiperIndex.ets @@ -15,7 +15,6 @@ import { TopBar } from '../view/common/TopBar'; import { PageAll } from '../view/tabcontent/PageAll'; -import { CommonConstants } from '../common/constants/CommonConstant'; import { PageLive } from '../view/tabcontent/PageLive'; import { PageGame } from '../view/tabcontent/PageGame'; import { PageEntertainment } from '../view/tabcontent/PageEntertainment'; diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/view/all/PictureSort.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/view/all/PictureSort.ets index a2a17a642b62f168e4f9292d338a2051db9faccf..39e081b64f4bc17769001864cdb7762deabe043e 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/view/all/PictureSort.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/view/all/PictureSort.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { PictureItem } from '../../common/bean/PictureItem'; +import { PictureItem } from '../../viewmodel/PictureItem'; import { initializePictures } from '../../viewmodel/PictureViewModel'; import { PictureView } from '../common/PictureView'; import { PictureType } from '../../common/constants/PictureConstants'; @@ -25,7 +25,8 @@ import { CommonConstants } from '../../common/constants/CommonConstant'; * @param fontSize Font size. * @param fontWeight Font weight. */ -@Extend(Text) function textStyle(fontSize: Resource, fontWeight: number) { +@Extend(Text) +function textStyle(fontSize: Resource, fontWeight: number) { .fontSize(fontSize) .fontWeight(fontWeight) .fontColor($r('app.color.font_black')) @@ -71,7 +72,7 @@ export struct PictureSort { GridItem() { PictureView({ photos: item }); } - }, item => JSON.stringify(item)) + }, (item: PictureItem) => JSON.stringify(item)) } .columnsTemplate(CommonConstants.TWO_COLUMNS) .rowsTemplate(CommonConstants.TWO_ROWS) diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/Banner.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/Banner.ets index 9b6cb83569b31c3de3f6525c8c1f0b99d7872324..06bae0a5d366509063ec0b81135d592746b7f87b 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/Banner.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/Banner.ets @@ -14,7 +14,7 @@ */ import router from '@ohos.router'; -import { PictureItem } from '../../common/bean/PictureItem'; +import { PictureItem } from '../../viewmodel/PictureItem'; import { PictureType } from '../../common/constants/PictureConstants'; import { initializePictures, startPlay, stopPlay } from '../../viewmodel/PictureViewModel'; import { CommonConstants } from '../../common/constants/CommonConstant'; @@ -25,7 +25,8 @@ import { CommonConstants } from '../../common/constants/CommonConstant'; * @param fontSize Font size. * @param fontWeight Font weight. */ -@Extend(Text) function textStyle(fontSize: Resource, fontWeight: number) { +@Extend(Text) +function textStyle(fontSize: Resource, fontWeight: number) { .fontSize(fontSize) .fontColor($r('app.color.start_window_background')) .fontWeight(fontWeight) @@ -54,7 +55,7 @@ export struct Banner { build() { Swiper(this.swiperController) { - ForEach(this.imageArray, item => { + ForEach(this.imageArray, (item: PictureItem) => { Stack({ alignContent: Alignment.TopStart }) { Image(item.image) .objectFit(ImageFit.Fill) @@ -82,7 +83,7 @@ export struct Banner { } .height(CommonConstants.FULL_HEIGHT) .width(CommonConstants.FULL_WIDTH) - }, item => JSON.stringify(item)) + }, (item: PictureItem) => JSON.stringify(item)) } .width(CommonConstants.PAGE_WIDTH) .height(CommonConstants.HEIGHT_BANNER) diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/PictureView.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/PictureView.ets index 8c5f652f461b381700dcd3f745c4351f58946eda..b86df2968ab0c4b3241a5ba902792227be19b50d 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/PictureView.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/PictureView.ets @@ -14,7 +14,7 @@ */ import router from '@ohos.router'; -import { PictureItem } from '../../common/bean/PictureItem'; +import { PictureItem } from '../../viewmodel/PictureItem'; import { CommonConstants } from '../../common/constants/CommonConstant'; /** @@ -22,7 +22,7 @@ import { CommonConstants } from '../../common/constants/CommonConstant'; */ @Component export struct PictureView { - private photos: PictureItem; + private photos: PictureItem = new PictureItem(); build() { Column() { diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/TopBar.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/TopBar.ets index 54ebbcfc0ab4ca692fc664941315e829357b2a5c..e6d28934dad40da3edb20229d94ebe4c8bc13c13 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/TopBar.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/view/common/TopBar.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { TopBarItem } from '../../common/bean/TopBarItem'; +import { TopBarItem } from '../../viewmodel/TopBarItem'; import { initializeOnStartup } from '../../viewmodel/TopBarViewModel'; import { CommonConstants } from '../../common/constants/CommonConstant'; @@ -38,7 +38,7 @@ export struct TopBar { .onClick(() => { this.index = item.id; }) - }, item => JSON.stringify(item)) + }, (item: TopBarItem) => JSON.stringify(item)) } .margin({ left: CommonConstants.ADS_LEFT }) .width(CommonConstants.FULL_WIDTH) diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/view/movie/MovieSort.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/view/movie/MovieSort.ets index fd00e38b546b14f877a1fe849b65f2e5b018abf5..7ed3e8f228644f792b148d076842368290741361 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/view/movie/MovieSort.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/view/movie/MovieSort.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { PictureItem } from '../../common/bean/PictureItem'; +import { PictureItem } from '../../viewmodel/PictureItem'; import { initializePictures } from '../../viewmodel/PictureViewModel'; import { PictureType } from '../../common/constants/PictureConstants'; import { PictureView } from '../common/PictureView'; @@ -40,7 +40,7 @@ export struct MovieSort { GridItem() { PictureView({ photos: item }) } - }, item => JSON.stringify(item)) + }, (item: PictureItem) => JSON.stringify(item)) } .columnsTemplate(CommonConstants.THREE_COLUMNS) .rowsTemplate(CommonConstants.THREE_ROWS) diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/CommentView.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/CommentView.ets index 512a01e544d190e2bfad20957398169c8813af89..10bc9e87d795867a831d087b1878bf22315d753f 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/CommentView.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/CommentView.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { VideoItem } from '../../common/bean/VideoItem'; +import { VideoItem } from '../../viewmodel/VideoItem'; import { CommonConstants } from '../../common/constants/CommonConstant'; /** @@ -22,7 +22,8 @@ import { CommonConstants } from '../../common/constants/CommonConstant'; * @param fontSize Font size. * @param fonWeight Font weight. */ -@Extend(Text) function textStyle(fontSize: Resource, fonWeight: number) { +@Extend(Text) +function textStyle(fontSize: Resource, fonWeight: number) { .fontSize(fontSize) .fontWeight(fonWeight) .fontColor($r('app.color.start_window_background')) diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/DescriptionView.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/DescriptionView.ets index 2c284c51467ec88eba47acba48452a473e67ec9c..a7aca9596148336138a45a66efe8868504334125 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/DescriptionView.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/DescriptionView.ets @@ -20,7 +20,8 @@ import { CommonConstants } from '../../common/constants/CommonConstant'; * @param fontSize Font size. * @param fonWeight Font weight. */ -@Extend(Text) function textStyle(fontSize: Resource, fonWeight: number) { +@Extend(Text) +function textStyle(fontSize: Resource, fonWeight: number) { .fontSize(fontSize) .fontWeight(fonWeight) .fontColor($r('app.color.start_window_background')) diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/PlayView.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/PlayView.ets index 0acc1c64d3ebc6538bbd4dff14111e671a4ef99e..ade6c38c9bbb505809c3f1ace7dd85cdb69011c5 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/PlayView.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/view/play/PlayView.ets @@ -13,8 +13,7 @@ * limitations under the License. */ -import { VideoItem } from '../../common/bean/VideoItem'; -import { needPageShow } from '../../viewmodel/VideoViewModel'; +import { VideoItem } from '../../viewmodel/VideoItem'; import { CommonConstants } from '../../common/constants/CommonConstant'; import { PlayState } from '../../common/constants/VideoConstants'; import { NavigationView } from './NavigationView'; @@ -30,8 +29,8 @@ export struct PlayView { // Change the video playing state according to the index and pageShow changes. @Link @Watch("needPageShow") index: number; @Link @Watch("needPageShow") pageShow: boolean; - private barPosition: number; - @State item: VideoItem = null; + private barPosition: number = 0; + @State item: VideoItem = new VideoItem(); @State private playState: number = PlayState.STOP; private videoController: VideoController = new VideoController(); @@ -42,7 +41,7 @@ export struct PlayView { controller: this.videoController }) .controls(false) - .autoPlay(this.playState === PlayState.START ? true : false) // Auto play in the first visible state. + .autoPlay(this.playState === PlayState.START ? true : false) .objectFit(ImageFit.Fill) .loop(true) .height(CommonConstants.WIDTH_VIDEO) @@ -66,8 +65,34 @@ export struct PlayView { .height(CommonConstants.FULL_HEIGHT) } - needPageShow() { - let needPlay = needPageShow.bind(this); - needPlay(); + onPageSwiperShow(): void { + if (this.playState != PlayState.START) { + this.playState = PlayState.START; + this.videoController.start(); + } + } + + onPageSwiperHide(): void { + if (this.playState != PlayState.STOP) { + this.playState = PlayState.STOP; + this.videoController.stop(); + } + } + + needPageShow(): void { + if (this.pageShow === true) { + if (this.barPosition === this.index) { + this.isShow = true; + this.onPageSwiperShow(); + } else { + if (this.isShow === true) { + this.isShow = false; + this.onPageSwiperHide(); + } + } + } else { + this.isShow = false; + this.onPageSwiperHide(); + } } } \ No newline at end of file diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/common/bean/PictureItem.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/PictureItem.ets similarity index 72% rename from ETSUI/SwiperArkTS/entry/src/main/ets/common/bean/PictureItem.ets rename to ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/PictureItem.ets index d004af0429c31afdf4c0de0decf25d4e3fc73784..7ffdbcb99dad7786e55adc2d1680b75f7f3433a6 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/common/bean/PictureItem.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/PictureItem.ets @@ -17,15 +17,8 @@ * Picture entity class. */ export class PictureItem { - id: string; - name: string; - description: string; - image: Resource; - - constructor(id: string, name: string, description: string, image: Resource) { - this.id = id; - this.name = name; - this.description = description; - this.image = image; - } + id: string = '1'; + name: string = '怒海'; + description: string = '怒海波涛'; + image: Resource = $r('app.media.ic_image1'); } \ No newline at end of file diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/PictureViewModel.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/PictureViewModel.ets index 932a6cf967eb876b651ae0ff77f7a7ffeac8b495..be1b49bdd7d711d30997ff99c27e86940c73cb26 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/PictureViewModel.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/PictureViewModel.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { PictureItem } from '../common/bean/PictureItem'; +import { PictureItem } from './PictureItem'; import { PICTURE_RECENTLY, PICTURE_PHOTO, PICTURE_LATEST, PICTURE_BANNER } from '../common/constants/PictureConstants'; import { PictureType } from '../common/constants/PictureConstants'; import { CommonConstants } from '../common/constants/CommonConstant'; @@ -28,22 +28,22 @@ export function initializePictures(initType: string): Array { switch (initType) { case PictureType.BANNER: PICTURE_BANNER.forEach((item) => { - imageDataArray.push(new PictureItem(item.id, item.name, item.description, item.image)); + imageDataArray.push(item); }) break; case PictureType.RECENTLY: PICTURE_RECENTLY.forEach((item) => { - imageDataArray.push(new PictureItem(item.id, item.name, item.description, item.image)); + imageDataArray.push(item); }) break; case PictureType.PHOTO: PICTURE_PHOTO.forEach((item) => { - imageDataArray.push(new PictureItem(item.id, item.name, item.description, item.image)); + imageDataArray.push(item); }) break; case PictureType.LATEST: PICTURE_LATEST.forEach((item) => { - imageDataArray.push(new PictureItem(item.id, item.name, item.description, item.image)); + imageDataArray.push(item); }) break; default: diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/common/bean/TopBarItem.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/TopBarItem.ets similarity index 85% rename from ETSUI/SwiperArkTS/entry/src/main/ets/common/bean/TopBarItem.ets rename to ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/TopBarItem.ets index 7ff22048027a448c774bb8e203e2848aaa038c84..ccbc6b90ca24a44f70211206cc3e46246a539249 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/common/bean/TopBarItem.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/TopBarItem.ets @@ -17,11 +17,6 @@ * TopBar entity class. */ export class TopBarItem { - id: number; - name: string; - - constructor(id: number, name: string) { - this.id = id; - this.name = name; - } + id: number = 0; + name: string = '全部'; } \ No newline at end of file diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/TopBarViewModel.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/TopBarViewModel.ets index e0da709c9223e4758f162531a5c994e5865800d7..a4ca4c7b422dad534840d3eddb0927b2d0247ff6 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/TopBarViewModel.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/TopBarViewModel.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { TopBarItem } from '../common/bean/TopBarItem'; +import { TopBarItem } from './TopBarItem'; import { TOP_BAR_DATA } from '../common/constants/TopBarConstants'; /** @@ -22,7 +22,7 @@ import { TOP_BAR_DATA } from '../common/constants/TopBarConstants'; export function initializeOnStartup(): Array { let tabDataArray: Array = [] TOP_BAR_DATA.forEach(item => { - tabDataArray.push(new TopBarItem(item.id, item.name)); + tabDataArray.push(item); }) return tabDataArray; } \ No newline at end of file diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/VideoItem.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/VideoItem.ets new file mode 100644 index 0000000000000000000000000000000000000000..83615f0d03582cb2844d24de9a491810814e51ed --- /dev/null +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/VideoItem.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Video entity class. + */ +@Observed +export class VideoItem { + id: string = '1'; + src: Resource = $rawfile('video1.mp4'); + likesCount: number = 0; + isLikes: boolean = false; + comment: number = 102; + shareTimes: number = 666; +} \ No newline at end of file diff --git a/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/VideoViewModel.ets b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/VideoViewModel.ets index f20e025dca0675bc6d2e9d707d5c4ba09470645c..05c0a7cc969ac533ad1116cb91bceab55e487e0c 100644 --- a/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/VideoViewModel.ets +++ b/ETSUI/SwiperArkTS/entry/src/main/ets/viewmodel/VideoViewModel.ets @@ -13,8 +13,8 @@ * limitations under the License. */ -import { VideoItem } from '../common/bean/VideoItem'; -import { VIDEO_DATA, PlayState } from '../common/constants/VideoConstants'; +import { VideoItem } from './VideoItem'; +import { VIDEO_DATA } from '../common/constants/VideoConstants'; /** * Init video data. @@ -22,47 +22,7 @@ import { VIDEO_DATA, PlayState } from '../common/constants/VideoConstants'; export function initializeOnStartup(): Array { let videoDataArray: Array = [] VIDEO_DATA.forEach(item => { - videoDataArray.push(new VideoItem(item.id, item.src, item.likesCount, item.isLikes, item.comment, item.shareTimes)); + videoDataArray.push(item); }) return videoDataArray; -} - -/** - * video show. - */ -export function onPageSwiperShow() { - if (this.playState != PlayState.START) { - this.playState = PlayState.START; - this.videoController.start(); - } -} - -/** - * video hide. - */ -export function onPageSwiperHide() { - if (this.playState != PlayState.STOP) { - this.playState = PlayState.STOP; - this.videoController.stop(); - } -} - -/** - * play page show. - */ -export function needPageShow() { - if (this.pageShow) { - if (this.barPosition === this.index) { // Judge whether the index is the same as the current location. - this.isShow = true; - onPageSwiperShow.call(this); - } else { - if (this.isShow) { // The already visible status is changed to invisible, and the invisible method callback is triggered. - this.isShow = false; - onPageSwiperHide.call(this); - } - } - } else { // Stop when the page goes back to the background. - this.isShow = false; - onPageSwiperHide.call(this); - } } \ No newline at end of file diff --git a/ETSUI/SwiperArkTS/hvigor/hvigor-config.json5 b/ETSUI/SwiperArkTS/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/SwiperArkTS/hvigor/hvigor-config.json5 +++ b/ETSUI/SwiperArkTS/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/ETSUI/TargetManagement/README.md b/ETSUI/TargetManagement/README.md index 9cbb520b9e17a7ec17aa59fd46efb9e3d6140472..2126aa5f88d203a651940f90283e81eae9abf492 100644 --- a/ETSUI/TargetManagement/README.md +++ b/ETSUI/TargetManagement/README.md @@ -15,13 +15,13 @@ ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -47,13 +47,11 @@ ``` ├──entry/src/main/ets // ArkTS代码区 │ ├──common -│ │ ├──bean -│ │ │ └──TaskItemBean.ets // 任务进展实体类 │ │ ├──constants │ │ │ └──CommonConstants.ets // 公共常量类 │ │ └──utils │ │ ├──DateUtil.ets // 获取格式化日期工具 -│ │ └──Logger.ts // 日志打印工具类 +│ │ └──Logger.ets // 日志打印工具类 │ ├──entryability │ │ └──EntryAbility.ts // 程序入口类 │ ├──pages @@ -66,10 +64,8 @@ │ │ └──TargetListItem.ets // 工作目标列表子项 │ └──viewmodel │ ├──DataModel.ets // 工作目标数据操作类 -│ ├──MainPageModel.ets // 主页面业务处理文件 -│ ├──TaskListItemModel // 工作目标列表子项业务处理文件 -│ └──TaskListViewModel.ets // 工作目标列表业务处理文件 -└──entry/src/main/resources // 资源文件目录 +│ └──TaskItemViewModel.ets // 任务进展实体类 +└──entry/src/main/resources // 资源文件目录 ``` ## 构建主界面 @@ -93,7 +89,7 @@ MainPage主要维护五个参数:子目标数组targetData、子目标总数to @Component struct MainPage { // 子目标数组 - @State targetData: Array = DataModel.getData(); + @State targetData: Array = DataModel.getData(); // 子目标总数 @State totalTasksNumber: number = 0; // 已完成子目标数 @@ -101,7 +97,7 @@ struct MainPage { // 最近更新时间 @State latestUpdateDate: string = CommonConstants.DEFAULT_PROGRESS_VALUE; // 监听数据变化的参数 - @Provide @Watch('onProgressChanged') overAllProgressChanged: boolean = false; + @Provide @Watch('onProgressChanged') overAllProgressChanged: boolean = false; ... /** @@ -128,7 +124,7 @@ struct MainPage { // 子目标列表 TargetList({ targetData: $targetData, - onAddClick: () => this.dialogController.open() + onAddClick: () :void => this.dialogController.open() }) ... } @@ -157,7 +153,7 @@ struct MainPage { struct MainPage { dialogController: CustomDialogController = new CustomDialogController({ builder: AddTargetDialog({ - onClickOk: saveTask.bind(this) + onClickOk: (value: string): void => this.saveTask(value) }), alignment: DialogAlignment.Bottom, offset: { @@ -177,24 +173,28 @@ struct MainPage { @CustomDialog export default struct AddTargetDialog { ... - private controller: CustomDialogController; - onClickOk: (value: string) => void; + private controller?: CustomDialogController; + onClickOk?: (value: string) => void; build() { Column() { ... - TextArea({ placeholder: $r('app.string.input_target_name')}) - ... - .onChange((value: string) => { - this.subtaskName = value; - }) + Text($r('app.string.add_task_dialog')) + ... + TextInput({ placeholder: $r('app.string.input_target_name')}) + ... + .onChange((value: string) => { + this.subtaskName = value; + }) Blank() Row() { ... Button($r('app.string.confirm_button')) .dialogButtonStyle() .onClick(() => { - this.onClickOk(this.subtaskName); + if (this.onClickOk !== undefined) { + this.onClickOk(this.subtaskName); + } }) } ... @@ -204,11 +204,11 @@ export default struct AddTargetDialog { } ``` -在MainPageModel.ets中,实现saveTask方法:保存数据至DataModel中,并更新targetData的值,完成添加子目标功能。 +在MainPage.ets中,实现saveTask方法:保存数据至DataModel中,并更新targetData的值,完成添加子目标功能。 ```typescript -// MainPageModel.ets -export function saveTask(taskName: string) { +// MainPage.ets +saveTask(taskName: string) { if (taskName === '') { promptAction.showToast({ message: $r('app.string.cannot_input_empty'), @@ -217,10 +217,9 @@ export function saveTask(taskName: string) { }); return; } - // 保存数据 - DataModel.addData(new TaskItemBean(taskName, 0, getCurrentTime())); - // 更新targetData刷新页面 + DataModel.addData(new TaskItemViewModel(taskName, 0, getCurrentTime())); this.targetData = DataModel.getData(); + this.overAllProgressChanged = !this.overAllProgressChanged; this.dialogController.close(); } ``` @@ -247,8 +246,8 @@ export function saveTask(taskName: string) { // TargetListItem.ets @Component export default struct TargetListItem { - @State latestProgress: number = 0; - @Watch('onClickIndexChanged') @Link clickIndex: number; + @State latestProgress?: number = 0; + @Link @Watch('onClickIndexChanged') clickIndex: number; @State isExpanded: boolean = false; ... // clickIndex改变的回调方法 @@ -256,7 +255,7 @@ export default struct TargetListItem { if (this.clickIndex !== this.index) { this.isExpanded = false; } - } +} build() { ... @@ -268,7 +267,15 @@ export default struct TargetListItem { ProgressEditPanel({ slidingProgress: this.latestProgress, onCancel: () => this.isExpanded = false, - onClickOK: changeProgress.bind(this), + onClickOK: (progress: number): void => { + this.latestProgress = progress; + this.updateDate = getCurrentTime(); + let result = DataModel.updateProgress(this.index, this.latestProgress, this.updateDate); + if (result) { + this.overAllProgressChanged = !this.overAllProgressChanged; + } + this.isExpanded = false; + }, sliderMode: $sliderMode }) ... @@ -300,9 +307,10 @@ export default struct TargetListItem { // ProgressEditPanel.ets @Component export default struct ProgressEditPanel { - @Prop slidingProgress: number; - onCancel: () => void; - onClickOK: (progress: number) => void; + @Link sliderMode: number; + @Prop slidingProgress: number = 0; + onCancel?: () => void; + onClickOK?: (progress: number) => void; build() { Column() { @@ -311,36 +319,36 @@ export default struct ProgressEditPanel { CustomButton({ buttonText: $r('app.string.cancel_button') }) - .onClick(() => this.onCancel()) - CustomButton({ - buttonText: $r('app.string.confirm_button') - }) - .onClick(() => this.onClickOK(this.slidingProgress)) + .onClick(() => { + if (this.onCancel !== undefined) { + this.onCancel(); + } + }) + CustomButton({ + buttonText: $r('app.string.cancel_button') + }) + .onClick(() => { + if (this.onClickOK !== undefined) { + this.onClickOK(this.slidingProgress); + } + }) } } } } ``` -在TaskListItemModel.ets中,编写changeProgress方法。此方法是onClickOK方法的实现,将依次完成以下步骤: - -1. 重新渲染TargetListItem的进度值和最近更新时间。 -2. 更新缓存的数据。 -3. 修改overAllProgressChanged的值,通知主页刷新整体进展详情TargetInformation。 +在DataModel.ets中,编写updateProgress方法。该方法根据索引和进度值以及更新日期更新数据。 ```typescript -// TaskListItemModel.ets -export function changeProgress(progress: number) { - // 更新TargetListItem的进度值 - this.latestProgress = progress; - // 更新TargetListItem的最近更新时间 - this.updateDate = getCurrentTime(); - // 更新缓存的数据 - let result = DataModel.updateProgress(this.index, this.latestProgress, this.updateDate); - if (result) { - this.overAllProgressChanged = !this.overAllProgressChanged; +// DataModel.ets +updateProgress(index: number, updateValue: number, updateDate: string): boolean { + if (!this.targetData[index]) { + return false; } - this.isExpanded = false; + this.targetData[index].progressValue = updateValue; + this.targetData[index].updateDate = updateDate; + return true; } ``` ### 实现列表多选 @@ -367,9 +375,9 @@ export default struct TargetList { Text($r('app.string.cancel_button')) ... .onClick(() => { - ... - this.isEditMode = false; - selectAllOrCancel.call(this, false); + this.selectAll = false; + this.isEditMode = false; + this.selectAllOrCancel(false); }) ... // 全选按钮 @@ -377,7 +385,7 @@ export default struct TargetList { ... .onClick(() => { ... - selectAllOrCancel.call(this, this.selectAll); + this.selectAllOrCancel(this.selectAll); }) } else { // 编辑按钮 @@ -385,7 +393,7 @@ export default struct TargetList { ... .onClick(() => { this.isEditMode = true; - selectAllOrCancel.call(this, false); + this.selectAllOrCancel(false); }) } ... @@ -397,9 +405,9 @@ export default struct TargetList { 点击全选Checkbox,将selectArray数组的值全赋值true或false,重新渲染列表为全选或者取消全选状态。 ```typescript -// TaskListViewModel.ets -export function selectAllOrCancel(selectStatus: boolean) { - let newSelectArray = []; +// TargetList.ets +selectAllOrCancel(selectStatus: boolean) { + let newSelectArray: Array = []; this.targetData.forEach(() => { newSelectArray.push(selectStatus); }); @@ -419,7 +427,7 @@ export default struct TargetListItem { ... @Link selectArr: Array; - private index: number; + public index: number = 0; build() { Stack({ alignContent: Alignment.Start }) { @@ -442,22 +450,18 @@ export default struct TargetListItem { ``` ### 实现删除选中列表项 -当点击“删除”时,调用TaskListViewModel.ets的deleteSelected方法,实现以下步骤完成列表项删除功能: +当点击“删除”时,TargetList.ets的deleteSelected方法,实现以下步骤完成列表项删除功能: 1. 调用DataModel的deleteData方法删除数据。 2. 更新targetData的数据重新渲染列表。 3. 修改overAllProgressChanged的值,通知主页刷新整体进展详情TargetInformation。 ```typescript -// TaskListViewModel.ets -export function deleteSelected() { - // 删除数据 +// TargetList.ets +deleteSelected() { DataModel.deleteData(this.selectArray); - // 更新targetData this.targetData = DataModel.getData(); - // 刷新整体进展详情 this.overAllProgressChanged = !this.overAllProgressChanged; - // 退出编辑模式 this.isEditMode = false; } ``` @@ -472,13 +476,14 @@ export class DataModel { if (!selectArr) { Logger.error(TAG, 'Failed to delete data because selectArr is ' + selectArr); } - for (let i = this.recordData.length - CommonConstants.TWO_RECORD; i >= 0; i--) { + let dataLen = this.targetData.length - CommonConstants.ONE_TASK; + for (let i = dataLen; i >= 0; i--) { if (selectArr[i]) { - this.recordData.splice(i, CommonConstants.ONE_RECORD); + this.targetData.splice(i, CommonConstants.ONE_TASK); } } } - getData(): Array { + getData(): Array { return this.targetData; } ... diff --git a/ETSUI/TargetManagement/entry/src/main/ets/common/utils/DateUtil.ets b/ETSUI/TargetManagement/entry/src/main/ets/common/utils/DateUtil.ets index 062d6e6dfabb088cbbd237f0a77ea73669076067..5c8dcbf8adc078ab43131b52b0e732d367f527ca 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/common/utils/DateUtil.ets +++ b/ETSUI/TargetManagement/entry/src/main/ets/common/utils/DateUtil.ets @@ -25,11 +25,11 @@ export default function getCurrentTime(): string { let day = date.getDate(); let hours = date.getHours(); let minutes = date.getMinutes().toString(); - if (parseInt(minutes) < CommonConstants.TEN) { + if (Number.parseInt(minutes) < CommonConstants.TEN) { minutes = `0${minutes}`; } let second = date.getSeconds().toString(); - if (parseInt(second) < CommonConstants.TEN) { + if (Number.parseInt(second) < CommonConstants.TEN) { second = `0${second}`; } return `${year}/${month}/${day} ${hours}:${minutes}:${second}`; diff --git a/ETSUI/TargetManagement/entry/src/main/ets/common/utils/Logger.ets b/ETSUI/TargetManagement/entry/src/main/ets/common/utils/Logger.ets index 3f639f0b4416eb149fae575b110caaa2ded20f82..9b2f698b047481a9699dec09e50e4230df254ad2 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/common/utils/Logger.ets +++ b/ETSUI/TargetManagement/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/ETSUI/TargetManagement/entry/src/main/ets/pages/MainPage.ets b/ETSUI/TargetManagement/entry/src/main/ets/pages/MainPage.ets index 66bfb70841567169cf7bfc4322aeddffc32b7d2c..346bee5a92bbb112cec05cfbc2f114243ffa0b76 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/pages/MainPage.ets +++ b/ETSUI/TargetManagement/entry/src/main/ets/pages/MainPage.ets @@ -16,23 +16,23 @@ import TargetInformation from '../view/TargetInformation'; import AddTargetDialog from '../view/AddTargetDialog'; import TargetList from '../view/TargetList'; -import TaskItemBean from '../common/bean/TaskItemBean'; import DataModel from '../viewmodel/DataModel'; -import { saveTask } from '../viewmodel/MainPageModel'; import { CommonConstants } from '../common/constant/CommonConstant'; import getCurrentTime from '../common/utils/DateUtil'; +import promptAction from '@ohos.promptAction'; +import TaskItemViewModel from '../viewmodel/TaskItemViewModel'; @Entry @Component struct MainPage { - @State targetData: Array = DataModel.getData(); + @State targetData: Array = DataModel.getData(); @State totalTasksNumber: number = 0; @State completedTasksNumber: number = 0; @State latestUpdateDate: string = CommonConstants.DEFAULT_PROGRESS_VALUE; @Provide @Watch('onProgressChanged') overAllProgressChanged: boolean = false; dialogController: CustomDialogController = new CustomDialogController({ builder: AddTargetDialog({ - onClickOk: saveTask.bind(this) + onClickOk: (value: string): void => this.saveTask(value) }), alignment: DialogAlignment.Bottom, offset: { @@ -48,7 +48,7 @@ struct MainPage { */ onProgressChanged() { this.totalTasksNumber = this.targetData.length; - this.completedTasksNumber = this.targetData.filter((item) => { + this.completedTasksNumber = this.targetData.filter((item: TaskItemViewModel) => { return item.progressValue === CommonConstants.SLIDER_MAX_VALUE; }).length; this.latestUpdateDate = getCurrentTime(); @@ -64,7 +64,7 @@ struct MainPage { }) TargetList({ targetData: $targetData, - onAddClick: () => this.dialogController.open() + onAddClick: (): void => this.dialogController.open() }) .height(CommonConstants.LIST_BOARD_HEIGHT) } @@ -86,4 +86,24 @@ struct MainPage { bottom: $r('app.float.title_margin') }) } + + /** + * Save the progress value and update time after you click OK in the dialog box. + * + * @param taskName Latest Progress Value. + */ + saveTask(taskName: string) { + if (taskName === '') { + promptAction.showToast({ + message: $r('app.string.cannot_input_empty'), + duration: CommonConstants.TOAST_TIME, + bottom: CommonConstants.TOAST_MARGIN_BOTTOM + }); + return; + } + DataModel.addData(new TaskItemViewModel(taskName, 0, getCurrentTime())); + this.targetData = DataModel.getData(); + this.overAllProgressChanged = !this.overAllProgressChanged; + this.dialogController.close(); + } } \ No newline at end of file diff --git a/ETSUI/TargetManagement/entry/src/main/ets/view/AddTargetDialog.ets b/ETSUI/TargetManagement/entry/src/main/ets/view/AddTargetDialog.ets index f16446f5183483a82b9a09ad0af1ba923b4a2b2d..0779ef180a7ebb666ae242ffaf323a86b81cd762 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/view/AddTargetDialog.ets +++ b/ETSUI/TargetManagement/entry/src/main/ets/view/AddTargetDialog.ets @@ -18,8 +18,8 @@ import { CommonConstants } from '../common/constant/CommonConstant'; @CustomDialog export default struct AddTargetDialog { @State subtaskName: string = ''; - private controller: CustomDialogController; - onClickOk: (value: string) => void; + private controller?: CustomDialogController; + onClickOk?: (value: string) => void; build() { Column() { @@ -47,14 +47,16 @@ export default struct AddTargetDialog { Button($r('app.string.cancel_button')) .dialogButtonStyle() .onClick(() => { - this.controller.close(); + this.controller?.close(); }) Divider() .vertical(true) Button($r('app.string.confirm_button')) .dialogButtonStyle() .onClick(() => { - this.onClickOk(this.subtaskName); + if (this.onClickOk !== undefined) { + this.onClickOk(this.subtaskName); + } }) } .width(CommonConstants.DIALOG_OPERATION_WIDTH) diff --git a/ETSUI/TargetManagement/entry/src/main/ets/view/ProgressEditPanel.ets b/ETSUI/TargetManagement/entry/src/main/ets/view/ProgressEditPanel.ets index c130e8891d7efeb3bc9fa96ca5e2b79a34a5c9fb..94ed804e56fddccbd23bee94e145e6d45fae023c 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/view/ProgressEditPanel.ets +++ b/ETSUI/TargetManagement/entry/src/main/ets/view/ProgressEditPanel.ets @@ -18,9 +18,9 @@ import { CommonConstants } from '../common/constant/CommonConstant'; @Component export default struct ProgressEditPanel { @Link sliderMode: number; - @Prop slidingProgress: number; - onCancel: () => void; - onClickOK: (progress: number) => void; + @Prop slidingProgress: number = 0; + onCancel?: () => void; + onClickOK?: (progress: number) => void; build() { Column() { @@ -51,11 +51,19 @@ export default struct ProgressEditPanel { CustomButton({ buttonText: $r('app.string.cancel_button') }) - .onClick(() => this.onCancel()) + .onClick(() => { + if (this.onCancel !== undefined) { + this.onCancel(); + } + }) CustomButton({ buttonText: $r('app.string.confirm_button') }) - .onClick(() => this.onClickOK(this.slidingProgress)) + .onClick(() => { + if (this.onClickOK !== undefined) { + this.onClickOK(this.slidingProgress); + } + }) } .margin({ top: CommonConstants.SLIDER_BUTTON_MARGIN }) .width(CommonConstants.DIALOG_OPERATION_WIDTH) @@ -70,7 +78,7 @@ export default struct ProgressEditPanel { @Component struct CustomButton { @State buttonColor: Resource = $r('app.color.start_window_background'); - buttonText: Resource; + buttonText?: Resource; build() { Text(this.buttonText) @@ -78,11 +86,11 @@ struct CustomButton { .backgroundColor(this.buttonColor) .borderRadius(CommonConstants.LIST_RADIUS) .textAlign(TextAlign.Center) - .onTouch((event: TouchEvent) => { - if (event.type === TouchType.Down) { + .onTouch((event?: TouchEvent) => { + if (event !== undefined && event.type === TouchType.Down) { this.buttonColor = $r('app.color.custom_button_color'); } - if (event.type === TouchType.Up) { + if (event !== undefined && event.type === TouchType.Up) { this.buttonColor = $r('app.color.start_window_background'); } }) diff --git a/ETSUI/TargetManagement/entry/src/main/ets/view/TargetInformation.ets b/ETSUI/TargetManagement/entry/src/main/ets/view/TargetInformation.ets index 23596f65bfe96be871c9e6519094de70822bb86a..d1c8d23e09919749db70b6c9e7b9e26e41ce83b9 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/view/TargetInformation.ets +++ b/ETSUI/TargetManagement/entry/src/main/ets/view/TargetInformation.ets @@ -17,9 +17,9 @@ import { CommonConstants } from '../common/constant/CommonConstant'; @Component export default struct TargetInformation { - @Prop latestUpdateDate: string; - @Prop totalTasksNumber: number; - @Prop completedTasksNumber: number; + @Prop latestUpdateDate: string = ''; + @Prop totalTasksNumber: number = 0; + @Prop completedTasksNumber: number = 0; build() { Column() { diff --git a/ETSUI/TargetManagement/entry/src/main/ets/view/TargetList.ets b/ETSUI/TargetManagement/entry/src/main/ets/view/TargetList.ets index a3b8f1794a38e7339e3150a3f7ec3b6c0edc4d98..d82116e21f2445244ed99bb9b711c4e2856a4433 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/view/TargetList.ets +++ b/ETSUI/TargetManagement/entry/src/main/ets/view/TargetList.ets @@ -13,10 +13,11 @@ * limitations under the License. */ -import TaskItemBean from '../common/bean/TaskItemBean'; + import TargetListItem from './TargetListItem'; -import { selectAllOrCancel, deleteSelected, isSelectAll, isSelectRows } from '../viewmodel/TaskListViewModel'; import { CommonConstants } from '../common/constant/CommonConstant'; +import DataModel from '../viewmodel/DataModel'; +import TaskItemBean from '../viewmodel/TaskItemViewModel'; @Component export default struct TargetList { @@ -26,7 +27,7 @@ export default struct TargetList { @State clickIndex: number = CommonConstants.DEFAULT_CLICK_INDEX; @State selectAll: boolean = false; @Link targetData: Array; - onAddClick: () => void; + onAddClick?: () => void; build() { Column() { @@ -44,7 +45,7 @@ export default struct TargetList { .onClick(() => { this.selectAll = false; this.isEditMode = false; - selectAllOrCancel.call(this, false); + this.selectAllOrCancel(false); }) Text($r('app.string.select_all_button')) .operateTextStyle($r('app.color.main_blue')) @@ -52,19 +53,19 @@ export default struct TargetList { left: $r('app.float.operate_button_margin') }) Checkbox() - .select(isSelectAll.call(this)) + .select(this.isSelectAll()) .selectedColor($r('app.color.main_blue')) .width(CommonConstants.CHECKBOX_WIDTH) .onClick(() => { this.selectAll = !this.selectAll; - selectAllOrCancel.call(this, this.selectAll); + this.selectAllOrCancel(this.selectAll); }) } else { Text($r('app.string.edit_button')) .operateTextStyle($r('app.color.main_blue')) .onClick(() => { this.isEditMode = true; - selectAllOrCancel.call(this, false); + this.selectAllOrCancel(false); }) } } @@ -77,7 +78,7 @@ export default struct TargetList { }) List({ space: CommonConstants.LIST_SPACE }) { - ForEach(this.targetData, (item: TaskItemBean, index: number) => { + ForEach(this.targetData, (item: TaskItemBean, index: number | undefined) => { ListItem() { TargetListItem({ taskItem: item, @@ -87,7 +88,7 @@ export default struct TargetList { clickIndex: $clickIndex }) } - }, (item, index) => JSON.stringify(item) + index) + }, (item: TaskItemBean) => JSON.stringify(item)) } .edgeEffect(EdgeEffect.None) .margin({ top: $r('app.float.list_margin_top') }) @@ -97,24 +98,74 @@ export default struct TargetList { Blank() if (this.isEditMode) { Button($r('app.string.delete_button')) - .opacity(isSelectRows.call(this) ? CommonConstants.NO_OPACITY : CommonConstants.OPACITY) - .enabled(isSelectRows.call(this) ? true : false) + .opacity(this.isSelectRows() ? CommonConstants.NO_OPACITY : CommonConstants.OPACITY) + .enabled(this.isSelectRows() ? true : false) .operateButtonStyle($r('app.color.main_red')) .onClick(() => { - deleteSelected.call(this); - selectAllOrCancel.call(this, false); + this.deleteSelected(); + this.selectAllOrCancel(false); this.selectAll = false; }) } else { Button($r('app.string.add_task')) .operateButtonStyle($r('app.color.main_blue')) - .onClick(() => this.onAddClick()) + .onClick(() => { + if (this.onAddClick !== undefined) { + this.onAddClick() + } + }) } } .width(CommonConstants.MAIN_BOARD_WIDTH) .height(CommonConstants.FULL_HEIGHT) .padding({ top: $r('app.float.operate_row_margin') }) } + + /** + * Delete the selected item and exit the editing mode. + */ + deleteSelected() { + DataModel.deleteData(this.selectArray); + this.targetData = DataModel.getData(); + this.overAllProgressChanged = !this.overAllProgressChanged; + this.isEditMode = false; + } + + /** + * Select or deselect all. + * + * @param selectStatus true: Select all. Otherwise, deselect all. + */ + selectAllOrCancel(selectStatus: boolean) { + let newSelectArray: Array = []; + this.targetData.forEach(() => { + newSelectArray.push(selectStatus); + }); + this.selectArray = newSelectArray; + } + + /** + * Whether to select all. + */ + isSelectAll(): boolean { + if (this.selectArray.length === 0) { + return false; + } + let deSelectCount: Length = this.selectArray.filter((selected: boolean) => selected === false).length; + if (deSelectCount === 0) { + this.selectAll = true; + return true; + } + this.selectAll = false; + return false; + } + + /** + * Check whether there are selected rows. + */ + isSelectRows(): boolean { + return this.selectArray.filter((selected: boolean) => selected === true).length !== 0; + } } /** diff --git a/ETSUI/TargetManagement/entry/src/main/ets/view/TargetListItem.ets b/ETSUI/TargetManagement/entry/src/main/ets/view/TargetListItem.ets index 1f227a66d2f182b91eb68bc6ceb954996bf8b170..61552bace0be27cabf948b464312549939159b9d 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/view/TargetListItem.ets +++ b/ETSUI/TargetManagement/entry/src/main/ets/view/TargetListItem.ets @@ -13,27 +13,29 @@ * limitations under the License. */ -import TaskItemBean from '../common/bean/TaskItemBean'; + import { CommonConstants } from '../common/constant/CommonConstant'; -import { changeProgress } from '../viewmodel/TaskListItemModel'; +import getCurrentTime from '../common/utils/DateUtil'; +import DataModel from '../viewmodel/DataModel'; +import TaskItemViewModel from '../viewmodel/TaskItemViewModel'; import ProgressEditPanel from './ProgressEditPanel'; @Component export default struct TargetListItem { - private taskItem: TaskItemBean; - @State latestProgress: number = 0; - @State updateDate: string = ''; + private taskItem?: TaskItemViewModel; + @State latestProgress?: number = 0; + @State updateDate?: string = ''; @Link selectArr: Array; - @Prop isEditMode: boolean; + @Prop isEditMode: boolean = false; @Link @Watch('onClickIndexChanged') clickIndex: number; @State isExpanded: boolean = false; @Consume overAllProgressChanged: boolean; @State sliderMode: number = CommonConstants.DEFAULT_SLIDER_MODE; - private index: number; + public index: number = 0; aboutToAppear() { - this.latestProgress = this.taskItem.progressValue; - this.updateDate = this.taskItem.updateDate; + this.latestProgress = this.taskItem?.progressValue; + this.updateDate = this.taskItem?.updateDate; } /** @@ -54,7 +56,15 @@ export default struct TargetListItem { ProgressEditPanel({ slidingProgress: this.latestProgress, onCancel: () => this.isExpanded = false, - onClickOK: changeProgress.bind(this), + onClickOK: (progress: number): void => { + this.latestProgress = progress; + this.updateDate = getCurrentTime(); + let result = DataModel.updateProgress(this.index, this.latestProgress, this.updateDate); + if (result) { + this.overAllProgressChanged = !this.overAllProgressChanged; + } + this.isExpanded = false; + }, sliderMode: $sliderMode }) .transition({ @@ -113,7 +123,7 @@ export default struct TargetListItem { @Builder TargetItem() { Row() { - Text(this.taskItem.taskName) + Text(this.taskItem?.taskName) .fontSize($r('app.float.list_font')) .fontWeight(CommonConstants.FONT_WEIGHT) .fontColor($r('app.color.title_black_color')) diff --git a/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/DataModel.ets b/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/DataModel.ets index f4c8b4d57176a99976db54efbfe88be27e154e73..abd457a45c2830327c406ceaa408870ead7d1c4c 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/DataModel.ets +++ b/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/DataModel.ets @@ -15,7 +15,8 @@ import { CommonConstants } from '../common/constant/CommonConstant'; import Logger from '../common/utils/Logger'; -import TaskItemBean from '../common/bean/TaskItemBean'; +import TaskItemViewModel from './TaskItemViewModel'; + const TAG = '[DataModel]'; @@ -27,12 +28,12 @@ export class DataModel { /** * Saved data. */ - private targetData: Array = []; + private targetData: Array = []; /** * Get the latest data. */ - getData(): Array { + getData(): Array { return this.targetData; } @@ -58,7 +59,7 @@ export class DataModel { * * @param Data of the RecordItemBean type to be added. */ - addData(data: TaskItemBean) { + addData(data: TaskItemViewModel) { if (!data) { Logger.error(TAG, 'addData error because data is: ' + data); return; diff --git a/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/MainPageModel.ets b/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/MainPageModel.ets deleted file mode 100644 index effbdc802a2c09efe37f61e418c60375477797e0..0000000000000000000000000000000000000000 --- a/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/MainPageModel.ets +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License,Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import promptAction from '@ohos.promptAction'; -import DataModel from './DataModel'; -import getCurrentTime from '../common/utils/DateUtil'; -import TaskItemBean from '../common/bean/TaskItemBean'; -import { CommonConstants } from '../common/constant/CommonConstant'; - -/** - * Save the progress value and update time after you click OK in the dialog box. - * - * @param context context from view. - * @param value Latest Progress Value. - */ -export function saveTask(taskName: string) { - if (taskName === '') { - promptAction.showToast({ - message: $r('app.string.cannot_input_empty'), - duration: CommonConstants.TOAST_TIME, - bottom: CommonConstants.TOAST_MARGIN_BOTTOM - }); - return; - } - DataModel.addData(new TaskItemBean(taskName, 0, getCurrentTime())); - this.targetData = DataModel.getData(); - this.overAllProgressChanged = !this.overAllProgressChanged; - this.dialogController.close(); -} \ No newline at end of file diff --git a/ETSUI/TargetManagement/entry/src/main/ets/common/bean/TaskItemBean.ets b/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/TaskItemViewModel.ets similarity index 96% rename from ETSUI/TargetManagement/entry/src/main/ets/common/bean/TaskItemBean.ets rename to ETSUI/TargetManagement/entry/src/main/ets/viewmodel/TaskItemViewModel.ets index a40a0df93a272696f0267ba671d27541deff9518..cd85184ebd6cec1fedda77be9cc593e8fcd48151 100644 --- a/ETSUI/TargetManagement/entry/src/main/ets/common/bean/TaskItemBean.ets +++ b/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/TaskItemViewModel.ets @@ -16,7 +16,7 @@ /** * Task item entity class. */ -export default class TaskItemBean { +export default class TaskItemViewModel { /** * Progress value of task item. */ diff --git a/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/TaskListViewModel.ets b/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/TaskListViewModel.ets deleted file mode 100644 index de9aaaa6f993a39bab80fa865157af0aafd7cd9e..0000000000000000000000000000000000000000 --- a/ETSUI/TargetManagement/entry/src/main/ets/viewmodel/TaskListViewModel.ets +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License,Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import DataModel from '../viewmodel/DataModel'; - -/** - * Delete the selected item and exit the editing mode. - */ -export function deleteSelected() { - DataModel.deleteData(this.selectArray); - this.targetData = DataModel.getData(); - this.overAllProgressChanged = !this.overAllProgressChanged; - this.isEditMode = false; -} - -/** - * Select or deselect all. - * - * @param selectStatus true: Select all. Otherwise, deselect all. - */ -export function selectAllOrCancel(selectStatus: boolean) { - let newSelectArray = []; - this.targetData.forEach(() => { - newSelectArray.push(selectStatus); - }); - this.selectArray = newSelectArray; -} - -/** - * Whether to select all. - */ -export function isSelectAll(): boolean { - if (this.selectArray.length === 0) { - return false; - } - let deSelectCount = this.selectArray.filter(selected => selected === false).length; - if (deSelectCount === 0) { - this.selectAll = true; - return true; - } - this.selectAll = false; - return false; -} - -/** - * Check whether there are selected rows. - */ -export function isSelectRows(): boolean { - return this.selectArray.filter((selected) => selected === true).length !== 0; -} \ No newline at end of file diff --git a/ETSUI/TargetManagement/hvigor/hvigor-config.json5 b/ETSUI/TargetManagement/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/TargetManagement/hvigor/hvigor-config.json5 +++ b/ETSUI/TargetManagement/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/ETSUI/ToDoListArkTS/README.md b/ETSUI/ToDoListArkTS/README.md index 1e7de33a55c6b507d64649d6684acafa31f6dcf2..af635f5eebfda9d0c4900034b0d5b91b4a5dec04 100644 --- a/ETSUI/ToDoListArkTS/README.md +++ b/ETSUI/ToDoListArkTS/README.md @@ -7,7 +7,7 @@ ### 相关概念 -- [ArkTS语法](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-get-started.md):ArkTS是OpenHarmony的主要应用开发语言。ArkTS基于TypeScript(简称TS)语言扩展而来,是TS的超集。 +- [ArkTS语法](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-get-started.md):ArkTS是HarmonyOS的主要应用开发语言。ArkTS基于TypeScript(简称TS)语言扩展而来,是TS的超集。 - [Text组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-text.md):显示一段文本的组件。 - [Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md):沿垂直方向布局的容器。 - [Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md):沿水平方向布局的容器。 @@ -16,13 +16,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -58,7 +58,7 @@ │ │ └──ToDoItem.ets // 自定义单项待办组件 │ └──viewmodel │ └──DataModel.ets // 列表数据获取文件 -└──entry/src/main/resources // 资源文件目录 +└──entry/src/main/resources // 资源文件目录 ``` ## 构建主界面 @@ -102,9 +102,9 @@ struct ToDoListPage { Column({ space: CommonConstants.COLUMN_SPACE }) { Text($r('app.string.page_title')) ... - ForEach(this.totalTasks, (item) => { + ForEach(this.totalTasks, (item: string) => { ToDoItem({ content: item }) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } ... } @@ -119,10 +119,10 @@ struct ToDoListPage { ... @Component export default struct ToDoItem { - private content: string; + private content: string = ''; @State isComplete: boolean = false; - @Builder labelIcon(icon) { + @Builder labelIcon(icon: Resource) { Image(icon) ... } @@ -153,10 +153,4 @@ export default struct ToDoItem { 1. ArkTS声明式语法。 2. Image、Text、Column、Row等基础组件的使用。 - ![](figures/zh-cn_image_0000001596934629.gif) - - - - - - + ![](figures/zh-cn_image_0000001596934629.gif) \ No newline at end of file diff --git a/ETSUI/ToDoListArkTS/entry/src/main/ets/pages/ToDoListPage.ets b/ETSUI/ToDoListArkTS/entry/src/main/ets/pages/ToDoListPage.ets index 675a52a86c35100702a73b53a2b317afed8ce842..3c1be2538a6f0d6b751daf21a8898715dbe12187 100644 --- a/ETSUI/ToDoListArkTS/entry/src/main/ets/pages/ToDoListPage.ets +++ b/ETSUI/ToDoListArkTS/entry/src/main/ets/pages/ToDoListPage.ets @@ -39,9 +39,9 @@ struct ToDoListPage { }) .textAlign(TextAlign.Start) - ForEach(this.totalTasks, (item) => { + ForEach(this.totalTasks, (item: string) => { ToDoItem({ content: item }) - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } .width(CommonConstants.FULL_LENGTH) .height(CommonConstants.FULL_LENGTH) diff --git a/ETSUI/ToDoListArkTS/entry/src/main/ets/view/ToDoItem.ets b/ETSUI/ToDoListArkTS/entry/src/main/ets/view/ToDoItem.ets index 434553dde99382c76e2127a6fae9e506eb10c551..7878f00eeeb9fa2b94524a7d8bd2b14da87b1678 100644 --- a/ETSUI/ToDoListArkTS/entry/src/main/ets/view/ToDoItem.ets +++ b/ETSUI/ToDoListArkTS/entry/src/main/ets/view/ToDoItem.ets @@ -17,10 +17,10 @@ import CommonConstants from '../common/constant/CommonConstant'; @Component export default struct ToDoItem { - private content: string; + private content: string = ''; @State isComplete: boolean = false; - @Builder labelIcon(icon) { + @Builder labelIcon(icon: Resource) { Image(icon) .objectFit(ImageFit.Contain) .width($r('app.float.checkbox_width')) diff --git a/ETSUI/ToDoListArkTS/hvigor/hvigor-config.json5 b/ETSUI/ToDoListArkTS/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/ToDoListArkTS/hvigor/hvigor-config.json5 +++ b/ETSUI/ToDoListArkTS/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/ETSUI/TransitionAnimation/README.md b/ETSUI/TransitionAnimation/README.md index cb4a5f22b7721491f57012a882619732b83d71c6..90bef782651336f3936eec77c9961a43994b7fdb 100644 --- a/ETSUI/TransitionAnimation/README.md +++ b/ETSUI/TransitionAnimation/README.md @@ -2,7 +2,7 @@ ## 介绍 -基于ArkTS的声明式开发范式及OpenHarmony系统的转场动画接口,实现一系列页面动画切换的功能。在本教程中,我们将会通过一个简单的样例,学习如何基于ArkTS的声明式开发范式开发转场动画。其中包含页面间转场、组件内转场以及共享元素转场,效果如图所示: +在本教程中,我们将会通过一个简单的样例,学习如何基于ArkTS的声明式开发范式开发转场动画。其中包含页面间转场、组件内转场以及共享元素转场。效果如图所示: ![](figures/TransitionAnimation.gif) @@ -12,20 +12,22 @@ ### 相关概念 - [页面间转场](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-page-transition-animation.md):页面转场通过在全局pageTransition方法内配置页面入场组件和页面退场组件来自定义页面转场动效。 + - [组件内转场](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-transition-animation-component.md):组件转场主要通过transition属性进行配置转场参数,在组件插入和删除时进行过渡动效,主要用于容器组件子组件插入删除时提升用户体验(需要配合animateTo才能生效,动效时长、曲线、延时跟随animateTo中的配置)。 + - [共享元素转场](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-transition-animation-shared-elements.md):通过修改共享元素的sharedTransition属性设置元素在不同页面之间过渡动效。例如,如果两个页面使用相同的图片(但位置和大小不同),图片就会在这两个页面之间流畅地平移和缩放。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -48,7 +50,7 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 @@ -56,9 +58,10 @@ │ │ ├──constants │ │ │ └──CommonConstants.ets // 公共常量类 │ │ └──utils -│ │ └──DimensionUtil.ets // 屏幕适配工具类 +│ │ ├──DimensionUtil.ets // 屏幕适配工具类 +│ │ └──GlobalContext.ets // 全局上下文工具类 │ ├──entryability -│ │ └──EntryAbility.ts // 程序入口类 +│ │ └──EntryAbility.ets // 程序入口类 │ ├──pages │ │ ├──BottomTransition.ets // 底部滑出页面 │ │ ├──ComponentTransition.ets // 移动动画转场页面 @@ -67,9 +70,11 @@ │ │ ├──Index.ets // 应用首页 │ │ ├──ShareItem.ets // 共享元素转场部件 │ │ └──SharePage.ets // 共享元素转场页面 -│ └──view -│ ├──BackContainer.ets // 自定义头部返回组件 -│ └──TransitionElement.ets // 自定义动画元素 +│ ├──view +│ │ ├──BackContainer.ets // 自定义头部返回组件 +│ │ └──TransitionElement.ets // 自定义动画元素 +│ └──viewmodel +│ └──AnimationModel.ets // 动画封装的model类 └──entry/src/main/resources // 资源文件目录 ``` @@ -88,27 +93,26 @@ 2. 在Index.ets中引入首页所需要图片和路由信息,声明子组件的UI布局并添加样式,使用ForEach方法循环渲染首页列表常量数据“INDEX\_ANIMATION\_MODE”,其中imgRes是设置按钮的背景图片,url用于设置页面路由的地址。 ```typescript - export const INDEX_ANIMATION_MODE = [ - { imgRes: $r('app.media.bg_bottom_anim_transition'), url: 'pages/BottomTransition' }, - { imgRes: $r('app.media.bg_custom1_anim_transition'), url: 'pages/CustomTransition' }, - { imgRes: $r('app.media.bg_custom2_anim_transition'), url: 'pages/FullCustomTransition' }, - { imgRes: $r('app.media.bg_element_anim_transition'), url: 'pages/ComponentTransition' }, - { imgRes: $r('app.media.bg_share_anim_transition'), url: 'pages/ShareItem' } - ]; + // Index.ets + import { INDEX_ANIMATION_MODE } from '../common/constants/CommonConstants'; Column() { - ForEach(INDEX_ANIMATION_MODE, ({ imgRes , url }) => { - Button() - .backgroundImage(imgRes) + ForEach(INDEX_ANIMATION_MODE, (item: AnimationModel) => { + Row() + .backgroundImage(item.imgRes) .backgroundImageSize(ImageSize.Cover) .backgroundColor($r('app.color.trans_parent')) .height(DimensionUtil.getVp($r('app.float.main_page_body_height'))) .margin({ bottom: DimensionUtil.getVp($r('app.float.main_page_body_margin')) }) .width(FULL_LENGTH) + .borderRadius(BORDER_RADIUS) .onClick(() => { - router.push({ url: url }); + router.pushUrl({ url: item.url }) + .catch((err: Error) => { + hilog.error(DOMAIN, PREFIX, FORMAT, err); + }); }) - }, item => item.toString()) + }, (item: AnimationModel) => JSON.stringify(item)) } ``` @@ -123,6 +127,7 @@ 通过设置PageTransitionEnter和PageTransitionExit的slide属性为SlideEffect.Bottom,来实现BottomTransition入场时从底部滑入,退场时从底部滑出。 ```typescript +// BottomTransition.ets @Entry @Component struct BottomTransition { @@ -154,6 +159,7 @@ struct BottomTransition { 在CustomTransition.ets的Column组件中添加TransitionElement组件,并且定义pageTransition方法。 ```typescript +// CustomTransition.ets @Entry @Component struct CustomTransition { @@ -191,6 +197,7 @@ struct CustomTransition { 在FullCustomTransition.ets的Column组件中添加TransitionElement组件,并且定义pageTransition方法。给Stack组件添加opacity、scale、rotate属性,定义变量animValue用来控制Stack组件的动效,在PageTransitionEnter和PageTransitionExit组件中动态改变myProgress的值。 ```typescript +// FullCustomTransition.ets @Entry @Component struct FullCustomTransition { @@ -216,12 +223,18 @@ struct FullCustomTransition { */ pageTransition() { PageTransitionEnter({ duration: TRANSITION_ANIMATION_DURATION, curve: Curve.Smooth }) - .onEnter((type: RouteType, progress: number) => { - this.animValue = progress + .onEnter((type?: RouteType, progress?: number) => { + if (!progress) { + return; + } + this.animValue = progress; }); PageTransitionExit({ duration: TRANSITION_ANIMATION_DURATION, curve: Curve.Smooth }) - .onExit((type: RouteType, progress: number) => { - this.animValue = FULL_CUSTOM_TRANSITION_DEFAULT_ANIM_VALUE - progress + .onExit((type?: RouteType, progress?: number) => { + if (!progress) { + return; + } + this.animValue = FULL_CUSTOM_TRANSITION_DEFAULT_ANIM_VALUE - progress; }); } } @@ -238,6 +251,7 @@ struct FullCustomTransition { 1. 在ComponentTransition.ets文件中,新建Image子组件,并添加两个transition属性,分别用于定义组件的添加动效和移除动效。 ```typescript + // ComponentTransition.ets Image($r('app.media.bg_element')) .TransitionEleStyles() .transition({ @@ -252,9 +266,10 @@ struct FullCustomTransition { }) ``` -2. 在ComponentTransition组件定义一个变量,用于控制ComponentItem的添加和移除,在Button组件的onClick事件中添加animateTo方法,来使ComponentItem子组件动效生效。 +2. 在ComponentTransition代码中,定义一个isShow变量,用于控制Image子组件的添加和移除,在Button组件的onClick事件中添加animateTo方法,来使Image子组件子组件动效生效。 ```typescript + // ComponentTransition.ets @State isShow: boolean = false; Button($r('app.string.Component_transition_toggle')) @@ -280,6 +295,7 @@ struct FullCustomTransition { 1. 在ShareItem.ets中给Image组件设置sharedTransition属性,组件转场id设置为“SHARE\_TRANSITION\_ID”。 ```typescript + // ShareItem.ets Image($r('app.media.bg_transition')) .width(FULL_LENGTH) .height(DimensionUtil.getVp($r('app.float.share_item_element_height'))) @@ -291,13 +307,17 @@ struct FullCustomTransition { delay: SHARE_ITEM_ANIMATION_DELAY }) .onClick(() => { - router.push({ url: SHARE_PAGE_URL }); + router.pushUrl({ url: SHARE_PAGE_URL }) + .catch((err: Error) => { + hilog.error(DOMAIN, PREFIX, FORMAT, err); + }); }) ``` 2. 在SharePage.ets中给Image组件设置sharedTransition属性,组件转场id设置为“SHARE\_TRANSITION\_ID”。 ```typescript + // SharePage.ets @Entry @Component struct SharePage { diff --git a/ETSUI/TransitionAnimation/entry/oh-package.json5 b/ETSUI/TransitionAnimation/entry/oh-package.json5 index 19b9234a98d43a4711a0fc32cef604159228d3cd..225946cb11a2c405c8dc81eea89c22f923556638 100644 --- a/ETSUI/TransitionAnimation/entry/oh-package.json5 +++ b/ETSUI/TransitionAnimation/entry/oh-package.json5 @@ -7,4 +7,4 @@ "main": "", "version": "1.0.0", "dependencies": {} -} \ No newline at end of file +} diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/common/constants/CommonConstants.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/common/constants/CommonConstants.ets index e09d2e166f382daccd18b68838dd5b8e8ff164df..5f97eac9adc3aa8314272ac0601ab4219c693007 100644 --- a/ETSUI/TransitionAnimation/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/common/constants/CommonConstants.ets @@ -13,19 +13,22 @@ * limitations under the License. */ +import AnimationModel from '../../viewmodel/AnimationModel' + /** * Index page button animation mode. */ -export const INDEX_ANIMATION_MODE = [ - { imgRes: $r('app.media.bg_bottom_anim_transition'), url: 'pages/BottomTransition' }, - { imgRes: $r('app.media.bg_custom1_anim_transition'), url: 'pages/CustomTransition' }, - { imgRes: $r('app.media.bg_custom2_anim_transition'), url: 'pages/FullCustomTransition' }, - { imgRes: $r('app.media.bg_element_anim_transition'), url: 'pages/ComponentTransition' }, - { imgRes: $r('app.media.bg_share_anim_transition'), url: 'pages/ShareItem' } + +export const INDEX_ANIMATION_MODE: AnimationModel[] = [ + new AnimationModel($r('app.media.bg_bottom_anim_transition'), 'pages/BottomTransition'), + new AnimationModel($r('app.media.bg_custom1_anim_transition'), 'pages/CustomTransition'), + new AnimationModel($r('app.media.bg_custom2_anim_transition'), 'pages/FullCustomTransition'), + new AnimationModel($r('app.media.bg_element_anim_transition'), 'pages/ComponentTransition'), + new AnimationModel($r('app.media.bg_share_anim_transition'), 'pages/ShareItem') ]; /** - * common full length + * common full length. */ export const FULL_LENGTH = '100%'; @@ -47,22 +50,34 @@ export const SHARE_TRANSITION_ID: string = 'shareId'; /** * Component transition scale. */ -export const COMPONENT_TRANSITION_SCALE = { x: 0.5, y: 0.5 }; +export const COMPONENT_TRANSITION_SCALE: CustomTransition = { x: 0.5, y: 0.5 }; /** * Component transition opacity. */ export const COMPONENT_TRANSITION_OPACITY = 0; +class ComponentTransitionRotate { + x: number = 0; + y: number = 0; + z: number = 0; + angle: number = 360; +} + /** * Component transition rotate. */ -export const COMPONENT_TRANSITION_ROTATE = { x: 0, y: 1, z: 0, angle: 360 }; +export const COMPONENT_TRANSITION_ROTATE: ComponentTransitionRotate = { x: 0, y: 1, z: 0, angle: 360 }; + +class CustomTransition { + x: number = 0; + y: number = 0; +} /** * Custom transition scale. */ -export const CUSTOM_TRANSITION_SCALE = { x: 0, y: 0 }; +export const CUSTOM_TRANSITION_SCALE: CustomTransition = { x: 0, y: 0 }; /** * Custom transition opacity. @@ -72,7 +87,7 @@ export const CUSTOM_TRANSITION_OPACITY = 0.2; /** * Custom transition translate. */ -export const CUSTOM_TRANSITION_TRANSLATE = { x: 500, y: 500 }; +export const CUSTOM_TRANSITION_TRANSLATE: CustomTransition = { x: 500, y: 500 }; /** * Full custom transition default animation value. diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/common/utils/DimensionUtil.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/common/utils/DimensionUtil.ets index a9ac6b91b5aec4c8762cc93f4bd4d114b16e6d53..f6f3041e94d753ccfebbe8e8b8a4cc498419eda6 100644 --- a/ETSUI/TransitionAnimation/entry/src/main/ets/common/utils/DimensionUtil.ets +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/common/utils/DimensionUtil.ets @@ -14,8 +14,10 @@ */ import ctx from '@ohos.app.ability.common'; +import display from '@ohos.display'; +import { GlobalContext } from './GlobalContext'; -var context = getContext(this) as ctx.Context; +let context = getContext(this) as ctx.Context; /** * Design drawing width. @@ -37,7 +39,7 @@ export default class DimensionUtil { * @return number */ static adaptDimension(value: number): number { - let deviceDisplay = globalThis.display; + let deviceDisplay: display.Display = GlobalContext.getContext().getObject('display') as display.Display; let widthScale = deviceDisplay.width / DESIGN_WIDTH; let virtualHeight = widthScale * DESIGN_HEIGHT; let designDim = Math.sqrt(DESIGN_WIDTH * DESIGN_WIDTH + DESIGN_HEIGHT * DESIGN_HEIGHT); @@ -52,7 +54,7 @@ export default class DimensionUtil { */ static getPx(value: Resource): number { let beforeVp = context.resourceManager.getNumber(value.id); - return this.adaptDimension(beforeVp); + return DimensionUtil.adaptDimension(beforeVp); } /** @@ -62,7 +64,7 @@ export default class DimensionUtil { */ static getVp(value: Resource): number { let beforeVp = context.resourceManager.getNumber(value.id); - return px2vp(this.adaptDimension(beforeVp)); + return px2vp(DimensionUtil.adaptDimension(beforeVp)); } /** @@ -72,6 +74,6 @@ export default class DimensionUtil { */ static getFp(value: Resource): number { let beforeFp = context.resourceManager.getNumber(value.id); - return px2fp(this.adaptDimension(beforeFp)); + return px2fp(DimensionUtil.adaptDimension(beforeFp)); } } \ No newline at end of file diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/common/utils/GlobalContext.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/common/utils/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..677db0cb7cce13a483f076991499a50d7fcdae94 --- /dev/null +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/common/utils/GlobalContext.ets @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { } + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/entryAbility/EntryAbility.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/entryAbility/EntryAbility.ets index f697649e35f2d30d2800aff096e35698057517d2..04ee0a6de15fc47005af4043597f117e851e193d 100644 --- a/ETSUI/TransitionAnimation/entry/src/main/ets/entryAbility/EntryAbility.ets +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/entryAbility/EntryAbility.ets @@ -15,14 +15,17 @@ import UIAbility from '@ohos.app.ability.UIAbility'; import display from '@ohos.display'; +import Want from '@ohos.app.ability.Want'; +import { GlobalContext } from '../common/utils/GlobalContext'; +import window from '@ohos.window'; export default class EntryAbility extends UIAbility { - onCreate(want) { - globalThis.abilityWant = want; + onCreate(want: Want) { + GlobalContext.getContext().setObject('abilityWant', want); } - async onWindowStageCreate(windowStage) { - globalThis.display = await display.getDefaultDisplaySync(); - windowStage.setUIContent(this.context, "pages/Index", null); + async onWindowStageCreate(windowStage: window.WindowStage) { + GlobalContext.getContext().setObject('display', await display.getDefaultDisplaySync()); + windowStage.loadContent("pages/Index"); } }; \ No newline at end of file diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/pages/BottomTransition.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/pages/BottomTransition.ets index 7f438af0490056a442e7dfb92a6edb516abc49fe..9e45b9fec37ad5d7b71fd1234375b70bb7aba5db 100644 --- a/ETSUI/TransitionAnimation/entry/src/main/ets/pages/BottomTransition.ets +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/pages/BottomTransition.ets @@ -26,13 +26,15 @@ struct BottomTransition { } /** - * 页面转场通过全局pageTransition方法进行配置转场参数 + * Page transition parameters are configured using the global pageTransition method. * - * SlideEffect.Bottom 入场时从屏幕下方滑入。 - * SlideEffect.Bottom 退场时从屏幕下方滑出。 + * SlideEffect.Bottom Slides in from the bottom of the screen when entering. + * SlideEffect.Bottom slides out from the bottom of the screen when exiting. */ pageTransition() { - PageTransitionEnter({ duration: TRANSITION_ANIMATION_DURATION, curve: Curve.Smooth }).slide(SlideEffect.Bottom); - PageTransitionExit({ duration: TRANSITION_ANIMATION_DURATION, curve: Curve.Smooth }).slide(SlideEffect.Bottom); + PageTransitionEnter({ duration: TRANSITION_ANIMATION_DURATION, curve: Curve.Smooth }) + .slide(SlideEffect.Bottom); + PageTransitionExit({ duration: TRANSITION_ANIMATION_DURATION, curve: Curve.Smooth }) + .slide(SlideEffect.Bottom); } } \ No newline at end of file diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/pages/CustomTransition.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/pages/CustomTransition.ets index d567efc4f8fc3bb50f380e785ab90c9094b35c0f..0d061f127212c391e5f0df10aec7f05d65ecd314 100644 --- a/ETSUI/TransitionAnimation/entry/src/main/ets/pages/CustomTransition.ets +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/pages/CustomTransition.ets @@ -31,10 +31,10 @@ struct CustomTransition { } /** - * 页面转场通过全局pageTransition方法进行配置转场参数 + * Page transition parameters are configured using the global pageTransition method. * - * 进场时透明度设置从0.2到1;x、y轴缩放从0变化到1 - * 退场时x、y轴的偏移量为500 + * The transparency is set from 0.2 to 1 when entering the site. The x and y axes are scaled from 0 to 1. + * The offset of the x and y axes at exit is 500. */ pageTransition() { PageTransitionEnter({ duration: TRANSITION_ANIMATION_DURATION, curve: Curve.Smooth }) diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/pages/FullCustomTransition.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/pages/FullCustomTransition.ets index d5accca389406c2f1ac48af8f491e452279a6f54..870483b701ab6585c86577907a520d311a885915 100644 --- a/ETSUI/TransitionAnimation/entry/src/main/ets/pages/FullCustomTransition.ets +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/pages/FullCustomTransition.ets @@ -39,19 +39,27 @@ struct FullCustomTransition { } /** - * 页面转场通过全局pageTransition方法进行配置转场参数 + * Page transition parameters are configured using the global pageTransition method. * - * 进场过程中会逐帧触发onEnter回调,入参为动效的归一化进度(0 - 1) - * 进场过程中会逐帧触发onExit回调,入参为动效的归一化进度(0 - 1) + * Enter: During the entry process, the onEnter callback is triggered frame by frame. + * The input parameter is the normalization progress of the dynamic effect (0–1). + * Exit: The onExit callback is triggered frame by frame during entry. + * The input parameter is the normalization progress of the dynamic effect (0–1). */ pageTransition() { PageTransitionEnter({ duration: TRANSITION_ANIMATION_DURATION, curve: Curve.Smooth }) - .onEnter((type: RouteType, progress: number) => { - this.animValue = progress + .onEnter((type?: RouteType, progress?: number) => { + if (!progress) { + return; + } + this.animValue = progress; }); PageTransitionExit({ duration: TRANSITION_ANIMATION_DURATION, curve: Curve.Smooth }) - .onExit((type: RouteType, progress: number) => { - this.animValue = FULL_CUSTOM_TRANSITION_DEFAULT_ANIM_VALUE - progress + .onExit((type?: RouteType, progress?: number) => { + if (!progress) { + return; + } + this.animValue = FULL_CUSTOM_TRANSITION_DEFAULT_ANIM_VALUE - progress; }); } } \ No newline at end of file diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/pages/Index.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/pages/Index.ets index 5170d5046a6aa5c788e3d3f11e37e3b9c081f36d..4918e10d50cff23406a333a8c639eadb1d59b75a 100644 --- a/ETSUI/TransitionAnimation/entry/src/main/ets/pages/Index.ets +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/pages/Index.ets @@ -25,6 +25,7 @@ import { } from '../common/constants/CommonConstants'; import DimensionUtil from '../common/utils/DimensionUtil'; import hilog from '@ohos.hilog'; +import AnimationModel from '../viewmodel/AnimationModel'; @Entry @Component @@ -43,9 +44,9 @@ struct Index { Scroll() { Column() { - ForEach(INDEX_ANIMATION_MODE, ({ imgRes , url }) => { + ForEach(INDEX_ANIMATION_MODE, (item: AnimationModel) => { Row() - .backgroundImage(imgRes) + .backgroundImage(item.imgRes) .backgroundImageSize(ImageSize.Cover) .backgroundColor($r('app.color.trans_parent')) .height(DimensionUtil.getVp($r('app.float.main_page_body_height'))) @@ -53,12 +54,12 @@ struct Index { .width(FULL_LENGTH) .borderRadius(BORDER_RADIUS) .onClick(() => { - router.pushUrl({ url: url }) - .catch(err => { + router.pushUrl({ url: item.url }) + .catch((err: Error) => { hilog.error(DOMAIN, PREFIX, FORMAT, err); }); }) - }, item => JSON.stringify(item)) + }, (item: AnimationModel) => JSON.stringify(item)) } } .align(Alignment.Top) diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/pages/ShareItem.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/pages/ShareItem.ets index 949a8ade95da389446c3e29d8a99f587ecabecd5..3e93f7612805f6b0ec3118f30eb725546adcc3c9 100644 --- a/ETSUI/TransitionAnimation/entry/src/main/ets/pages/ShareItem.ets +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/pages/ShareItem.ets @@ -45,7 +45,7 @@ struct ShareItem { }) .onClick(() => { router.pushUrl({ url: SHARE_PAGE_URL }) - .catch(err => { + .catch((err: Error) => { hilog.error(DOMAIN, PREFIX, FORMAT, err); }); }) diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/view/BackContainer.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/view/BackContainer.ets index d0a4598073f9a1ef8e0dcfeac592367dd90d3b58..b9a90c8fd3505a4f4940bb00a227c4e82c4c65cd 100644 --- a/ETSUI/TransitionAnimation/entry/src/main/ets/view/BackContainer.ets +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/view/BackContainer.ets @@ -19,7 +19,7 @@ import DimensionUtil from '../common/utils/DimensionUtil'; @Component export default struct BackContainer { - private header: string | Resource; + private header?: string | Resource; build() { Row() { diff --git a/ETSUI/TransitionAnimation/entry/src/main/ets/viewmodel/AnimationModel.ets b/ETSUI/TransitionAnimation/entry/src/main/ets/viewmodel/AnimationModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..cca3137aababf03586500e84e676c4f09945b3e8 --- /dev/null +++ b/ETSUI/TransitionAnimation/entry/src/main/ets/viewmodel/AnimationModel.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Animation model. + */ +export default class ClassifyModel { + imgRes: Resource; + url: string; + + constructor(imgRes: Resource, url: string) { + this.imgRes = imgRes; + this.url = url; + } +} \ No newline at end of file diff --git a/ETSUI/TransitionAnimation/entry/src/main/module.json5 b/ETSUI/TransitionAnimation/entry/src/main/module.json5 index 9181d6d7e3afaecd2e166586fa40d87381b1722c..f5a22fd6d79a63c99b63cc1f38009e9e850a28c3 100644 --- a/ETSUI/TransitionAnimation/entry/src/main/module.json5 +++ b/ETSUI/TransitionAnimation/entry/src/main/module.json5 @@ -13,7 +13,7 @@ "abilities": [ { "name": "EntryAbility", - "srcEntry": "./ets/entryAbility/EntryAbility.ets", + "srcEntry": "./ets/entryability/EntryAbility.ets", "description": "$string:EntryAbility_desc", "icon": "$media:icon", "label": "$string:EntryAbility_label", diff --git a/ETSUI/TransitionAnimation/hvigor/hvigor-config.json5 b/ETSUI/TransitionAnimation/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/TransitionAnimation/hvigor/hvigor-config.json5 +++ b/ETSUI/TransitionAnimation/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } -} +} \ No newline at end of file diff --git a/ETSUI/WebComponent/HttpServerOfWeb/app.js b/ETSUI/WebComponent/HttpServerOfWeb/app.js new file mode 100644 index 0000000000000000000000000000000000000000..0efcd0f30837ed1d7e183d346e5c5926485d2610 --- /dev/null +++ b/ETSUI/WebComponent/HttpServerOfWeb/app.js @@ -0,0 +1,43 @@ +var createError = require('http-errors'); +var express = require('express'); +var path = require('path'); +var cookieParser = require('cookie-parser'); +var logger = require('morgan'); +var fileUpload = require('express-fileupload'); +var bodyParser = require('body-parser'); + + +var app = express(); + +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'jade'); + +app.use(logger('dev')); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, 'public'))); +app.use(fileUpload()); + +// catch 404 and forward to error handler +app.use(function (req, res, next) { + next(createError(404)); +}); + +// error handler +app.use(function (err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.render('error'); +}); + +app.listen(9588, () => { + console.log('服务器启动成功!'); +}); + +module.exports = app; diff --git a/ETSUI/WebComponent/HttpServerOfWeb/bin/www b/ETSUI/WebComponent/HttpServerOfWeb/bin/www new file mode 100644 index 0000000000000000000000000000000000000000..7786c6db00be23d931a1e59e87171c13b49eb94d --- /dev/null +++ b/ETSUI/WebComponent/HttpServerOfWeb/bin/www @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var app = require('../app'); +var debug = require('debug')('httpserver:server'); +var http = require('http'); + +/** + * Get port from environment and store in Express. + */ + +var port = normalizePort(process.env.PORT || '3000'); +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} diff --git a/ETSUI/WebComponent/HttpServerOfWeb/package.json b/ETSUI/WebComponent/HttpServerOfWeb/package.json new file mode 100644 index 0000000000000000000000000000000000000000..9fdf4c8dcbbc26f3b4f1cdca0d94997e54c55c34 --- /dev/null +++ b/ETSUI/WebComponent/HttpServerOfWeb/package.json @@ -0,0 +1,19 @@ +{ + "name": "httpserverofweb", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www", + "dev": "nodemon ./bin/www" + }, + "dependencies": { + "cookie-parser": "1.4.6", + "debug": "2.6.9", + "express": "4.16.1", + "express-fileupload": "1.4.0", + "express-session": "1.17.3", + "http-errors": "1.6.3", + "jade": "1.11.0", + "morgan": "1.9.1" + } +} diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/css/index.css b/ETSUI/WebComponent/HttpServerOfWeb/public/css/index.css new file mode 100644 index 0000000000000000000000000000000000000000..95033c1d1c3a2a6233c50045230aab51789779be --- /dev/null +++ b/ETSUI/WebComponent/HttpServerOfWeb/public/css/index.css @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2022 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. + */ + +/* Reset Style */ +* { + margin: 0; + padding: 0; + list-style: none; + text-decoration: none; +} + +/* Picture Style */ +img { + width: 100%; + height: 100%; + margin: auto; + display: block; +} + +/* Sweepstakes List */ +.prizes { + width: 96.5%; + height: 96.7%; + position: absolute; +} + +/* Start Sweepstakes Text */ +.trigger { + font-size: 22px; + text-align: center; + display:block; +} + +/* Prize Plaid */ +.prizes li { + width: 30.6%; + height: 30.6%; + box-sizing: border-box; + position: absolute; +} + + +/* Prize Grid Position */ +.prizes li:nth-of-type(1) { + left: 3.0%; + top: 2.7%; +} + +.prizes li:nth-of-type(2) { + left: 34.9%; + top: 2.6%; +} + +.prizes li:nth-of-type(3) { + left: 66.8%; + top: 2.7%; +} + +.prizes li:nth-of-type(4) { + left: 66.8%; + top: 34.6%; +} + +.prizes li:nth-of-type(5) { + left: 66.8%; + top: 66.5%; +} + +.prizes li:nth-of-type(6) { + left: 34.9%; + top: 66.5%; +} + +.prizes li:nth-of-type(7) { + left: 3.0%; + top: 66.5%; +} + +.prizes li:nth-of-type(8) { + left: 3.0%; + top: 34.6%; +} + +.prizes li:nth-of-type(9) { + left: 34.9%; + top: 34.6%; +} + +/* Draw effect */ +.active:after { + top: 0; + left: 0; + width: 100%; + content: ""; + height: 100%; + position: absolute; + opacity : 0.6; + background-size: contain; + background-image:url('../img/background.svg'); +} \ No newline at end of file diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/1-beer.png b/ETSUI/WebComponent/HttpServerOfWeb/public/img/1-beer.png new file mode 100644 index 0000000000000000000000000000000000000000..3ad7f2eb5035b3091b64adf375fc96b15eeec8ef Binary files /dev/null and b/ETSUI/WebComponent/HttpServerOfWeb/public/img/1-beer.png differ diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/2-milk.png b/ETSUI/WebComponent/HttpServerOfWeb/public/img/2-milk.png new file mode 100644 index 0000000000000000000000000000000000000000..b59a3ef92092196e81c10f2bf057f060faaa8f7a Binary files /dev/null and b/ETSUI/WebComponent/HttpServerOfWeb/public/img/2-milk.png differ diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/3-hamburg.png b/ETSUI/WebComponent/HttpServerOfWeb/public/img/3-hamburg.png new file mode 100644 index 0000000000000000000000000000000000000000..a0c6e9c2b8e6fceced942155619093460215151e Binary files /dev/null and b/ETSUI/WebComponent/HttpServerOfWeb/public/img/3-hamburg.png differ diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/4-coffee.png b/ETSUI/WebComponent/HttpServerOfWeb/public/img/4-coffee.png new file mode 100644 index 0000000000000000000000000000000000000000..7140307d6f09ddc57835a934a717375e10665f07 Binary files /dev/null and b/ETSUI/WebComponent/HttpServerOfWeb/public/img/4-coffee.png differ diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/5-watermelon.png b/ETSUI/WebComponent/HttpServerOfWeb/public/img/5-watermelon.png new file mode 100644 index 0000000000000000000000000000000000000000..e8aef10df1537d01f06f5b1c9354ef0610b5caf8 Binary files /dev/null and b/ETSUI/WebComponent/HttpServerOfWeb/public/img/5-watermelon.png differ diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/6-drumstick.png b/ETSUI/WebComponent/HttpServerOfWeb/public/img/6-drumstick.png new file mode 100644 index 0000000000000000000000000000000000000000..79921aefbe0b1b129500453834a3fd1ef91b5570 Binary files /dev/null and b/ETSUI/WebComponent/HttpServerOfWeb/public/img/6-drumstick.png differ diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/7-lemon.png b/ETSUI/WebComponent/HttpServerOfWeb/public/img/7-lemon.png new file mode 100644 index 0000000000000000000000000000000000000000..8c74a7c45a20a0963aa8ebbb072496b2a8643755 Binary files /dev/null and b/ETSUI/WebComponent/HttpServerOfWeb/public/img/7-lemon.png differ diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/8-cake.png b/ETSUI/WebComponent/HttpServerOfWeb/public/img/8-cake.png new file mode 100644 index 0000000000000000000000000000000000000000..0379c43a77e9bb63ebd9f7a7d28ce39bde8256cc Binary files /dev/null and b/ETSUI/WebComponent/HttpServerOfWeb/public/img/8-cake.png differ diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/9-prizes.png b/ETSUI/WebComponent/HttpServerOfWeb/public/img/9-prizes.png new file mode 100644 index 0000000000000000000000000000000000000000..87af1039895dfc1cc1e6bac4fdad79dba099a1bd Binary files /dev/null and b/ETSUI/WebComponent/HttpServerOfWeb/public/img/9-prizes.png differ diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/background.svg b/ETSUI/WebComponent/HttpServerOfWeb/public/img/background.svg new file mode 100644 index 0000000000000000000000000000000000000000..cbc212d61a5f8f13a0bc304bb3ae33e05e2c7372 --- /dev/null +++ b/ETSUI/WebComponent/HttpServerOfWeb/public/img/background.svg @@ -0,0 +1,26 @@ + + + 蒙层 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/img/ic_public_back.png b/ETSUI/WebComponent/HttpServerOfWeb/public/img/ic_public_back.png new file mode 100644 index 0000000000000000000000000000000000000000..744c4cfa740ab0d07130eda0b11629318b3b8e30 Binary files /dev/null and b/ETSUI/WebComponent/HttpServerOfWeb/public/img/ic_public_back.png differ diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/index.html b/ETSUI/WebComponent/HttpServerOfWeb/public/index.html new file mode 100644 index 0000000000000000000000000000000000000000..4293b5de119e9b614c1313bb63a12d22b3d416d9 --- /dev/null +++ b/ETSUI/WebComponent/HttpServerOfWeb/public/index.html @@ -0,0 +1,48 @@ + + + + + + + + 抽奖页面 + + + +
+ +
    +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
+
+ + + \ No newline at end of file diff --git a/ETSUI/WebComponent/HttpServerOfWeb/public/js/index.js b/ETSUI/WebComponent/HttpServerOfWeb/public/js/index.js new file mode 100644 index 0000000000000000000000000000000000000000..eb884d6634d25e67dedfc19cdc55f5f203eaef7b --- /dev/null +++ b/ETSUI/WebComponent/HttpServerOfWeb/public/js/index.js @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022 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. + */ + +// Award name array +let prizesArr = ["啤酒", "奶茶", "汉堡", "咖啡", "西瓜", "鸡腿", "柠檬", "蛋糕"]; +// Image array +let arrBigImg = ["./img/1-beer.png", "./img/2-milk.png", "./img/3-hamburg.png", + "./img/4-coffee.png", "./img/5-watermelon.png", "./img/6-drumstick.png", + "./img/7-lemon.png", "./img/8-cake.png", "./img/9-prizes.png"]; + +// Get All Award Cells +let allPrizesLi = document.querySelectorAll('.prizes-li'); +// Get Pictures +let prizesImg = document.querySelectorAll('.pic'); + +// Initial value of rotation +let count = 0; +let isClick = true; +let index = 3; +// Turn to which position +let prizesPosition = 0; + +// Bind an IMG +for (let j = 0;j < prizesImg.length; j++) { + prizesImg[j].src = arrBigImg[j]; +} +// Rotation speed. The larger the value, the slower the speed +let speed = 500; + +// rotation function +function roll() { + // velocity decay + speed -= 50; + if (speed <= 10) { + speed = 10; + } + + // Remove all active class names for each call + for (let j = 0; j < allPrizesLi.length; j++) { + allPrizesLi[j].classList.remove('active'); + } + prizesPosition++; + + // Calculate the number of turns + if (prizesPosition >= allPrizesLi.length - 1) { + prizesPosition = 0; + count++; + } + + allPrizesLi[prizesPosition].classList.add('active'); + let initSpeed = 500; + let timer; + // Total number of revolutions at least + let totalCount = 5; + + // Stop when the number of turns and the specified position are met + if (count >= totalCount && (prizesPosition + 1) === index) { + clearTimeout(timer); + isClick = true; + speed = initSpeed; + // Wait for 1s to open the pop-up window + timer = setTimeout(openDialog, 1000); + } else { + // Wait for 1s to open the pop-up window + timer = setTimeout(roll, speed); + // Last lap deceleration + if (count >= totalCount - 1 || speed <= 50) { + speed += 100; + } + } +} + +// Draw Start Function +function startDraw() { + // Prevent multiple triggering of the lottery + if (isClick) { + count = 0; + // Randomly generate the winning position + index = Math.floor(Math.random() * prizesArr.length + 1); + roll(); + isClick = false; + } +} + +function openDialog() { + confirm(prizesArr[prizesPosition]); +} \ No newline at end of file diff --git a/ETSUI/WebComponent/HttpServerOfWeb/views/error.jade b/ETSUI/WebComponent/HttpServerOfWeb/views/error.jade new file mode 100644 index 0000000000000000000000000000000000000000..51ec12c6a26323d9f5bc51fb98cb1324a739ea4c --- /dev/null +++ b/ETSUI/WebComponent/HttpServerOfWeb/views/error.jade @@ -0,0 +1,6 @@ +extends layout + +block content + h1= message + h2= error.status + pre #{error.stack} diff --git a/ETSUI/WebComponent/HttpServerOfWeb/views/index.jade b/ETSUI/WebComponent/HttpServerOfWeb/views/index.jade new file mode 100644 index 0000000000000000000000000000000000000000..3d63b9a044a859b59259d5e23dd4e68ec8e1f2be --- /dev/null +++ b/ETSUI/WebComponent/HttpServerOfWeb/views/index.jade @@ -0,0 +1,5 @@ +extends layout + +block content + h1= title + p Welcome to #{title} diff --git a/ETSUI/WebComponent/HttpServerOfWeb/views/layout.jade b/ETSUI/WebComponent/HttpServerOfWeb/views/layout.jade new file mode 100644 index 0000000000000000000000000000000000000000..15af079bf7c34e638ba14844efd979ac9111628b --- /dev/null +++ b/ETSUI/WebComponent/HttpServerOfWeb/views/layout.jade @@ -0,0 +1,7 @@ +doctype html +html + head + title= title + link(rel='stylesheet', href='/stylesheets/style.css') + body + block content diff --git a/ETSUI/WebComponent/README.md b/ETSUI/WebComponent/README.md index 1f48688d665d1a1845dc7c1a8065d016f6aeee76..8a6ffc9219fadceecab639d7e71c6ac1c2491dd1 100644 --- a/ETSUI/WebComponent/README.md +++ b/ETSUI/WebComponent/README.md @@ -5,22 +5,21 @@ 本篇Codelab是基于ArkTS的声明式开发范式的样例,主要介绍了Web组件如何加载本地和云端H5小程序。所加载的页面是一个由HTML+CSS+JavaScript实现的完整小应用。样例主要包含以下功能: 1. web组件加载H5页面。 -2. eTS和H5页面交互。 - -效果如下图所示: +2. ArkTS和H5页面交互。 ![image](figures/web_oh.gif) ### 相关概念 - [Web](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-web.md):提供具有网页显示能力的Web组件。 -- [runJavaScript](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-web.md#runjavascript):异步执行JavaScript脚本,并通过回调方式返回脚本执行的结果。 + +- [runJavaScript](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-webview.md#runjavascript):异步执行JavaScript脚本,并通过回调方式返回脚本执行的结果。 ### 相关权限 -本Codelab使用了在线网页,需要在配置文件module.json5文件里添加网络权限:ohos.permission.INTERNET。 +本篇Codelab使用了在线网页,需要在配置文件module.json5文件里添加网络权限:ohos.permission.INTERNET。 -```typescript +```json { "module": { "name": "entry", @@ -33,17 +32,39 @@ } } ``` +### 约束与限制 + +本篇Codelab需要搭建服务端环境,服务端搭建流程如下: + +1. 搭建nodejs环境:本篇Codelab的服务端是基于nodejs实现的,需要安装nodejs,如果您本地已有nodejs环境可以跳过此步骤。 + + 1. 检查本地是否安装nodejs:打开命令行工具(如Windows系统的cmd和Mac电脑的Terminal,这里以Windows为例),输入node -v,如果可以看到版本信息,说明已经安装nodejs。 + + ![](figures/node.PNG) + + 2. 如果本地没有nodejs环境,您可以去nodejs官网上下载所需版本进行安装配置。 + + 3. 配置完环境变量后,重新打开命令行工具,输入node -v,如果可以看到版本信息,说明已安装成功。 + +2. 运行服务端代码:在本项目的HttpServerOfWeb目录下打开命令行工具,输入npm install 安装服务端依赖包,安装成功后输入npm start点击回车。看到“服务器启动成功!"则表示服务端已经在正常运行。 + + ![](figures/npm.PNG) + +3. 构建局域网环境:测试本Codelab时要确保运行服务端代码的电脑和测试机连接的是同一局域网下的网络,您可以用您的手机开一个个人热点,然后将测试机和运行服务端代码的电脑都连接您的手机热点进行测试。 + +4. 连接服务器地址:打开命令行工具,输入ipconfig命令查看本地ip,将本地ip地址复制到entry/src/main/ets/common/constants/Constants.ets文件下的23行,注意只替换ip地址部分,不要修改端口号,保存好ip之后即可运行Codelab进行测试。 + ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -71,68 +92,78 @@ │ ├──common │ │ └──Constant.ets // 常量类 │ ├──entryability -│ │ └──EntryAbility.ets // 程序入口类 +│ │ └──EntryAbility.ts // 程序入口类 │ └──pages │ ├──MainPage.ets // 主页入口文件 │ └──WebPage.ets // 抽奖页入口文件 -└──entry/src/main/resources - ├──base - │ ├──element // 尺寸、颜色、文字等资源文件存放位置 - │ ├──media // 媒体资源存放位置 - │ └──profile // 页面配置文件存放位置 - ├──en_US // 国际化英文 - ├──rawfile // 本地html代码存放位置 - └──zh_CN // 国际化中文 +├──entry/src/main/resources +│ ├──base +│ │ ├──element // 尺寸、颜色、文字等资源文件存放位置 +│ │ ├──media // 媒体资源存放位置 +│ │ └──profile // 页面配置文件存放位置 +│ ├──en_US // 国际化英文 +│ ├──rawfile // 本地html代码存放位置 +│ └──zh_CN // 国际化中文 +└──HttpServerOfWeb // 服务端代码 ``` ## H5小程序 -抽奖小程序由HTML+CSS+JS实现,主要的代码展示: +抽奖小程序由HTML+CSS+JS实现,HTML代码使用无序列表实现抽奖盘页面布局: -```javascript +```html
-
    +
      ... -
    • 点击抽奖
    • +
- - -/* 抽奖div */ -.luckyDraw { - width: 93.3%; - margin: 0 auto; +``` +CSS代码设置抽奖盘的样式: + +```css +/* css/index.css */ +/* 抽奖列表 */ +.prizes { + width: 96.5%; + height: 96.7%; + position: absolute; } ... /* 点击抽奖 */ .prizes li:nth-of-type(9) { - width: 25.8%; - height: 25.8%; + width: 34.9%; + height: 34.6%; ... } ... +``` - +JS代码实现抽奖的业务逻辑,并返回抽奖结果: + +```javascript +// js/index.js function roll() { - ... - // 满足转圈数和指定位置就停止 - if (count >= totalCount && (prizesPosition + 1) === index) { - clearTimeout(timer); - isClick = true; - speed = initSpeed; - timer = setTimeout(openDialog, 1000); // 等待1s打开弹窗 - } - ... + ... + // 满足转圈数和指定位置就停止 + if (count >= totalCount && (prizesPosition + 1) === index) { + clearTimeout(timer); + isClick = true; + speed = initSpeed; + // 等待1s打开弹窗 + timer = setTimeout(openDialog, 1000); + } + ... } function startDraw() { + ... + if (isClick) { ... - if (isClick) { - ... - roll(); - isClick = false; - } + roll(); + isClick = false; + } } function openDialog() { @@ -140,18 +171,17 @@ function openDialog() { confirm(prizesArr[prizesPosition]); } ``` -## Web组件 - -应用首页: -![](figures/2022092300914.png) +## Web组件 启动应用进入首页,页面提供两个按钮,分别对应加载本地H5和加载云端H5,点击按钮跳转到抽奖页面。 -代码如下: +![](figures/2022092300914.png) ```typescript +// MainPage.ets Column() { + ... Navigator({ target: WEB_PAGE_URI, type: NavigationType.Push }) { Button($r('app.string.loadLocalH5')) ... @@ -167,17 +197,14 @@ Column() { ``` >![](public_sys-resources/icon-note.gif) **说明:** ->H5页面本地存放在resources\\rawfile目录下,通过$rawfile\(\)访问;云端则存放在服务器上面,开发者可以自己搭建服务端。 +>H5页面本地存放在resources/rawfile目录下,通过$rawfile()访问;云端则存放在HttpServerOfWeb服务器上,开发者可以根据约束与限制章节服务端搭建流程进行服务器搭建。 -抽奖页面: +抽奖页面主要是由“点击抽奖”按钮和Web组件构成。给“点击抽奖”按钮绑定点击事件,实现点击按钮调用H5页面的JavaScript函数,并且通过onConfirm回调返回抽奖结果,在原生页面弹窗显示,完成ArkTS和H5的双向交互。 ![](figures/图片2.png) -页面主要是由“点击抽奖”按钮和Web组件构成。给“点击抽奖”按钮绑定点击事件,实现点击按钮调用H5页面的JavaScript函数,并且通过onConfirm回调返回抽奖结果,在原生页面弹窗显示,完成eTS和H5的双向交互。 - -代码如下: - ```typescript +// WebPage.ets Column() { ... Web({ src: this.params['path'], controller: this.webController }) @@ -191,18 +218,25 @@ Column() { }) return true; }) + ... + Column() { + Text($r('app.string.textValue')) + ... + Text(this.params['tips']) + ... + } Button($r('app.string.btnValue')) ... .onClick(() => { // 异步执行JavaScript脚本 - this.webController.runJavaScript({ script: 'startDraw()' }); + this.webController.runJavaScript('startDraw()'); }) } ``` ## 总结 -目前你已经成功完成了Codelab并且学到了: +您已经完成了本次Codelab的学习,并了解到以下知识点: 1. 使用Web组件加载H5页面。 2. 使用ArkTS与H5页面进行交互。 diff --git a/ETSUI/WebComponent/entry/src/main/ets/common/Constant.ets b/ETSUI/WebComponent/entry/src/main/ets/common/Constant.ets index dd80578daa0571f302014764b3d2d72ca3c6dea9..6bf5249fd4f7c78c53d40b37dd1570ae3f44790c 100644 --- a/ETSUI/WebComponent/entry/src/main/ets/common/Constant.ets +++ b/ETSUI/WebComponent/entry/src/main/ets/common/Constant.ets @@ -17,51 +17,67 @@ export const WEB_PAGE_URI: string = 'pages/WebPage'; export const LOCAL_PATH: Resource = $rawfile('index.html'); -// 运行时需要修改为自己服务器的地址 -export const CLOUD_PATH: string = 'http://***/index.html'; +/** + * The host address of the server. + */ +export const CLOUD_PATH: string = 'http://xxx.xxx.xxx.xxx:9588/index.html'; export const WEB_ALERT_DIALOG_TEXT_VALUE: string = '恭喜您抽中:'; -export const WebConstant = { - FULL_WIDTH: '100%', - FULL_HEIGHT: '100%', - WIDTH: '93.3%', - HEIGHT: '55.9%', - MARGIN_TOP: '7.1%', - MARGIN_LEFT: '3.3%', - MARGIN_RIGHT: '3.3%', - TOP_ROW_HEIGHT: '7.2%', - IMAGE_WIDTH: '5.6%', - IMAGE_HEIGHT: '32%', - IMAGE_MARGIN_LEFT: '7.2%', - TEXT_VALUE_WIDTH: '35.6%', - TEXT_VALUE_HEIGHT: '3.1%', - TEXT_VALUE_MARGIN_TOP: '3.1%', - TEXT_VALUE_FONT_SIZE: 18, - TEXT_VALUE_FONT_WEIGHT: 500, - TIP_TEXT_VALUE_WIDTH: '15.6%', - TIP_TEXT_VALUE_HEIGHT: '2.4%', - TIP_TEXT_VALUE_FONT_SIZE: 14, - TIP_TEXT_VALUE_MARGIN_TOP: '0.9%', - TIP_TEXT_VALUE_OPACITY: 0.6, - TOP_TEXT_WIDTH: '82.2%', - TOP_TEXT_HEIGHT: '50%', - TOP_TEXT_MARGIN_LEFT: '5%', - TOP_TEXT_FONT_SIZE: 20, - BUTTON_WIDTH: '86.7%', - BUTTON_HEIGHT: '5.1%', - BUTTON_MARGIN_TOP: '10%', - BUTTON_BORDER_RADIUS: '20', - BUTTON_FONT_SIZE: 16, +export class WebConstant { + static readonly FULL_WIDTH: string = '100%' + static readonly FULL_HEIGHT: string = '100%' + static readonly WIDTH: string = '93.3%' + static readonly HEIGHT: string = '55.9%' + static readonly MARGIN_TOP: string = '7.1%' + static readonly MARGIN_LEFT: string = '3.3%' + static readonly MARGIN_RIGHT: string = '3.3%' + static readonly TOP_ROW_HEIGHT: string = '7.2%' + static readonly IMAGE_WIDTH: string = '5.6%' + static readonly IMAGE_HEIGHT: string = '32%' + static readonly IMAGE_MARGIN_LEFT: string = '7.2%' + static readonly TEXT_VALUE_WIDTH: string = '35.6%' + static readonly TEXT_VALUE_HEIGHT: string = '3.1%' + static readonly TEXT_VALUE_MARGIN_TOP: string = '3.1%' + static readonly TEXT_VALUE_FONT_SIZE: number = 18 + static readonly TEXT_VALUE_FONT_WEIGHT: number = 500 + static readonly TIP_TEXT_VALUE_WIDTH: string = '15.6%' + static readonly TIP_TEXT_VALUE_HEIGHT: string = '2.4%' + static readonly TIP_TEXT_VALUE_FONT_SIZE: number = 14 + static readonly TIP_TEXT_VALUE_MARGIN_TOP: string = '0.9%' + static readonly TIP_TEXT_VALUE_OPACITY: number = 0.6 + static readonly TOP_TEXT_WIDTH: string = '82.2%' + static readonly TOP_TEXT_HEIGHT: string = '50%' + static readonly TOP_TEXT_MARGIN_LEFT: string = '5%' + static readonly TOP_TEXT_FONT_SIZE: number = 20 + static readonly BUTTON_WIDTH: string = '86.7%' + static readonly BUTTON_HEIGHT: string = '5.1%' + static readonly BUTTON_MARGIN_TOP: string = '10%' + static readonly BUTTON_BORDER_RADIUS: string = '20' + static readonly BUTTON_FONT_SIZE: number = 16 + static readonly DURATION: number = 3000 + static readonly PROGRESS_MIN: number = 0 + static readonly PROGRESS_MAX: number = 100 + static readonly PROGRESS_STEP: number = 6.67 + static readonly MILLI_SECONDS: number = 100 + static readonly PROGRESS_STROKE_WIDTH: number = 15 + static readonly PROGRESS_SCALE_COUNT: number = 15 + static readonly PROGRESS_SCALE_WIDTH: number = 5 + static readonly PROGRESS_WIDTH: number = 80 + static readonly PROGRESS_POSITION_X: string = '40%' + static readonly PROGRESS_POSITION_Y: string = '35%' } -export const MainConstant = { - FULL_HEIGHT: '100%', - IMAGE_HEIGHT: '38.7%', - BUTTON_MARGIN_TOP_BUTTON: '3.1%', - BUTTON_HEIGHT: '5.1%', - BUTTON_MARGIN_TOP: '4.6%', - BUTTON_WIDTH: '86.7%', - BUTTON_BORDER_RADIUS: 20, - BUTTON_FONT_SIZE: 16 +export class MainConstant { + static readonly FULL_HEIGHT: string = '100%' + static readonly IMAGE_HEIGHT: string = '38.7%' + static readonly BUTTON_MARGIN_TOP_BUTTON: string = '3.1%' + static readonly BUTTON_HEIGHT: string = '5.1%' + static readonly BUTTON_MARGIN_TOP: string = '4.6%' + static readonly BUTTON_WIDTH: string = '86.7%' + static readonly BUTTON_BORDER_RADIUS: number = 20 + static readonly BUTTON_FONT_SIZE: number = 16 } + + + diff --git a/ETSUI/WebComponent/entry/src/main/ets/entryability/EntryAbility.ts b/ETSUI/WebComponent/entry/src/main/ets/entryability/EntryAbility.ts index 7b0dd84958e7c90f2459b317ed8d5a0555e2e1f3..beb71a161c6902275451a7a9ebe18019280e37e0 100644 --- a/ETSUI/WebComponent/entry/src/main/ets/entryability/EntryAbility.ts +++ b/ETSUI/WebComponent/entry/src/main/ets/entryability/EntryAbility.ts @@ -3,49 +3,49 @@ import hilog from '@ohos.hilog'; import Window from '@ohos.window'; export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); - hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); - hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); - } + onCreate(want, launchParam) { + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); + hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); + } - onDestroy() { - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); - } + onDestroy() { + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } - onWindowStageCreate(windowStage: Window.WindowStage) { - // Main window is created, set main page for this ability - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + onWindowStageCreate(windowStage: Window.WindowStage) { + // Main window is created, set main page for this ability + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); - windowStage.loadContent('pages/MainPage', (err, data) => { - if (err.code) { - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.ERROR); - hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); - return; - } - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); - }); - } + windowStage.loadContent('pages/MainPage', (err, data) => { + if (err.code) { + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.ERROR); + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); + }); + } - onWindowStageDestroy() { - // Main window is destroyed, release UI related resources - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); - } + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } - onForeground() { - // Ability has brought to foreground - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); - } + onForeground() { + // Ability has brought to foreground + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } - onBackground() { - // Ability has back to background - hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); - } + onBackground() { + // Ability has back to background + hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } } diff --git a/ETSUI/WebComponent/entry/src/main/ets/pages/WebPage.ets b/ETSUI/WebComponent/entry/src/main/ets/pages/WebPage.ets index c87032355e7e3f003966355a71aae963710b190f..5bfcfb5964901280aa67c0dc6082029eb54905c7 100644 --- a/ETSUI/WebComponent/entry/src/main/ets/pages/WebPage.ets +++ b/ETSUI/WebComponent/entry/src/main/ets/pages/WebPage.ets @@ -14,14 +14,25 @@ */ import router from '@ohos.router'; -import web_webview from '@ohos.web.webview'; +import webview from '@ohos.web.webview'; +import prompt from '@ohos.promptAction'; import { WebConstant, MainConstant, WEB_ALERT_DIALOG_TEXT_VALUE } from '../common/Constant'; @Entry @Component struct WebPage { - webController: web_webview.WebviewController = new web_webview.WebviewController(); + webController: webview.WebviewController = new webview.WebviewController(); @State params: object = router.getParams(); + @State progressVal: number = 0; + @State isLoading: boolean = true; + @State intervalLoading: number = -1; + + aboutToAppear() { + this.intervalLoading = setInterval(() => { + this.progressVal = this.progressVal >= WebConstant.PROGRESS_MAX ? + WebConstant.PROGRESS_MIN : (this.progressVal + WebConstant.PROGRESS_STEP); + }, WebConstant.MILLI_SECONDS); + } build() { Stack({ alignContent: Alignment.TopStart }) { @@ -47,34 +58,60 @@ struct WebPage { }.height(WebConstant.TOP_ROW_HEIGHT) - // web组件加载本地H5 + // Web component loading H5. Web({ src: this.params['path'], controller: this.webController }) .zoomAccess(false) .width(WebConstant.WIDTH) .aspectRatio(1) .margin({ left: WebConstant.MARGIN_LEFT, right: WebConstant.MARGIN_RIGHT, top: WebConstant.MARGIN_TOP }) - .onConfirm((event) => { + .onConfirm((event?) => { AlertDialog.show({ - message: `${WEB_ALERT_DIALOG_TEXT_VALUE}` + `${event.message}`, + message: WEB_ALERT_DIALOG_TEXT_VALUE + event?.message, confirm: { value: $r('app.string.web_alert_dialog_button_value'), action: () => { - event.result.handleConfirm(); + event?.result.handleConfirm(); } }, cancel: () => { - event.result.handleCancel(); + event?.result.handleCancel(); } }); return true; }) + .onErrorReceive((event?) => { + if (event?.error.getErrorInfo() === 'ERR_INTERNET_DISCONNECTED') { + prompt.showToast({ + message: $r('app.string.internet_err'), + duration: WebConstant.DURATION + }) + } + if (event?.error.getErrorInfo() === 'ERR_CONNECTION_TIMED_OUT') { + prompt.showToast({ + message: $r('app.string.internet_err'), + duration: WebConstant.DURATION + }) + } + if (event?.error.getErrorInfo() === 'ERR_TIMED_OUT') { + prompt.showToast({ + message: $r('app.string.internet_err'), + duration: WebConstant.DURATION + }) + } + }) + .onProgressChange((event?) => { + if (event?.newProgress === WebConstant.PROGRESS_MAX) { + this.isLoading = false; + clearInterval(this.intervalLoading); + this.intervalLoading = -1; + } + }) Column() { Text($r('app.string.textValue')) .fontSize(WebConstant.TEXT_VALUE_FONT_SIZE) .textAlign(TextAlign.Center) .fontColor($r('app.color.text_value_font_color')) - .width(WebConstant.TEXT_VALUE_WIDTH) .height(WebConstant.TEXT_VALUE_HEIGHT) .fontWeight(WebConstant.TEXT_VALUE_FONT_WEIGHT) .margin({ top: WebConstant.TEXT_VALUE_MARGIN_TOP }) @@ -103,6 +140,27 @@ struct WebPage { .width(WebConstant.FULL_WIDTH) .height(WebConstant.FULL_HEIGHT) } + + if (this.isLoading) { + Progress({ + value: WebConstant.PROGRESS_MIN, + total: WebConstant.PROGRESS_MAX, + type: ProgressType.ScaleRing + }) + .color(Color.Grey) + .value(this.progressVal) + .width(WebConstant.PROGRESS_WIDTH) + .style({ + strokeWidth: WebConstant.PROGRESS_STROKE_WIDTH, + scaleCount: WebConstant.PROGRESS_SCALE_COUNT, + scaleWidth: WebConstant.PROGRESS_SCALE_WIDTH + }) + .zIndex(1) + .position({ + x: WebConstant.PROGRESS_POSITION_X, + y: WebConstant.PROGRESS_POSITION_Y + }) + } } .backgroundColor($r('app.color.navy_blue')) } diff --git a/ETSUI/WebComponent/entry/src/main/module.json5 b/ETSUI/WebComponent/entry/src/main/module.json5 index d9ced40f9d41d6522194bad554f008891ee20841..1955e8fc4ba0c9f38c8d8f7847f8c65e06f09b92 100644 --- a/ETSUI/WebComponent/entry/src/main/module.json5 +++ b/ETSUI/WebComponent/entry/src/main/module.json5 @@ -5,8 +5,7 @@ "description": "$string:module_desc", "mainElement": "EntryAbility", "deviceTypes": [ - "default", - "tablet" + "default" ], "deliveryWithInstall": true, "installationFree": false, diff --git a/ETSUI/WebComponent/entry/src/main/resources/base/element/string.json b/ETSUI/WebComponent/entry/src/main/resources/base/element/string.json index a549babcad43c2f31f0f6efade526cad10a652a6..d96337e4db409a03b1f438f0a82248af1e090e77 100644 --- a/ETSUI/WebComponent/entry/src/main/resources/base/element/string.json +++ b/ETSUI/WebComponent/entry/src/main/resources/base/element/string.json @@ -14,47 +14,51 @@ }, { "name": "promptsLocal", - "value": "本地H5小程序" + "value": "Local H5 applet" }, { "name": "promptsCloud", - "value": "云端H5小程序" + "value": "Cloud H5 applet" }, { "name": "loadLocalH5", - "value": "加载本地H5" + "value": "Load the local H5" }, { "name": "loadCloudH5", - "value": "加载云端H5" + "value": "Load cloud H5" }, { "name": "textValue", - "value": "以上为Web组件" + "value": "These are web components" }, { "name": "local", - "value": "(本地)" + "value": "(Local)" }, { "name": "online", - "value": "(在线)" + "value": "(online)" }, { "name": "btnValue", - "value": "点击抽奖" + "value": "Click on the raffle" }, { "name": "prompts", - "value": "抽奖应用" + "value": "Sweepstakes App" }, { "name": "web_alert_dialog_button_value", - "value": "确定" + "value": "Confirm" }, { "name": "web_width", "value": "93.3%" + }, + { + "name": "internet_err", + "value": "Failed to load the network." } ] } \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/src/main/resources/en_US/element/string.json b/ETSUI/WebComponent/entry/src/main/resources/en_US/element/string.json index a549babcad43c2f31f0f6efade526cad10a652a6..d96337e4db409a03b1f438f0a82248af1e090e77 100644 --- a/ETSUI/WebComponent/entry/src/main/resources/en_US/element/string.json +++ b/ETSUI/WebComponent/entry/src/main/resources/en_US/element/string.json @@ -14,47 +14,51 @@ }, { "name": "promptsLocal", - "value": "本地H5小程序" + "value": "Local H5 applet" }, { "name": "promptsCloud", - "value": "云端H5小程序" + "value": "Cloud H5 applet" }, { "name": "loadLocalH5", - "value": "加载本地H5" + "value": "Load the local H5" }, { "name": "loadCloudH5", - "value": "加载云端H5" + "value": "Load cloud H5" }, { "name": "textValue", - "value": "以上为Web组件" + "value": "These are web components" }, { "name": "local", - "value": "(本地)" + "value": "(Local)" }, { "name": "online", - "value": "(在线)" + "value": "(online)" }, { "name": "btnValue", - "value": "点击抽奖" + "value": "Click on the raffle" }, { "name": "prompts", - "value": "抽奖应用" + "value": "Sweepstakes App" }, { "name": "web_alert_dialog_button_value", - "value": "确定" + "value": "Confirm" }, { "name": "web_width", "value": "93.3%" + }, + { + "name": "internet_err", + "value": "Failed to load the network." } ] } \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/css/index.css b/ETSUI/WebComponent/entry/src/main/resources/rawfile/css/index.css index d525c8bc0be67e841ab318a28d1ba7242022b6e9..95033c1d1c3a2a6233c50045230aab51789779be 100644 --- a/ETSUI/WebComponent/entry/src/main/resources/rawfile/css/index.css +++ b/ETSUI/WebComponent/entry/src/main/resources/rawfile/css/index.css @@ -13,15 +13,15 @@ * limitations under the License. */ -/* 重置样式 */ +/* Reset Style */ * { margin: 0; - padding: 0; /* 去除无序列表的样式 */ - list-style: none; /* 去除文本的样式 */ + padding: 0; + list-style: none; text-decoration: none; } -/* 图片样式 */ +/* Picture Style */ img { width: 100%; height: 100%; @@ -29,21 +29,21 @@ img { display: block; } -/* 抽奖列表 */ +/* Sweepstakes List */ .prizes { width: 96.5%; height: 96.7%; position: absolute; } -/* 开始抽奖文本 */ +/* Start Sweepstakes Text */ .trigger { font-size: 22px; text-align: center; display:block; } -/* 奖品格子 */ +/* Prize Plaid */ .prizes li { width: 30.6%; height: 30.6%; @@ -52,7 +52,7 @@ img { } -/* 奖品格子位置 */ +/* Prize Grid Position */ .prizes li:nth-of-type(1) { left: 3.0%; top: 2.7%; @@ -98,7 +98,7 @@ img { top: 34.6%; } -/* 抽奖效果 */ +/* Draw effect */ .active:after { top: 0; left: 0; @@ -109,14 +109,4 @@ img { opacity : 0.6; background-size: contain; background-image:url('../img/background.svg'); -} - - - - - - - - - - +} \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/index.html b/ETSUI/WebComponent/entry/src/main/resources/rawfile/index.html index 605a017094f78a31812c1075dfaba0cc70dfc167..4293b5de119e9b614c1313bb63a12d22b3d416d9 100644 --- a/ETSUI/WebComponent/entry/src/main/resources/rawfile/index.html +++ b/ETSUI/WebComponent/entry/src/main/resources/rawfile/index.html @@ -18,33 +18,31 @@ limitations under the License. 抽奖页面 -
- -
    -
  • -
  • -
  • -
  • -
  • -
  • -
  • -
  • -
  • -
-
- - +
+ +
    +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
+
+ \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/js/index.js b/ETSUI/WebComponent/entry/src/main/resources/rawfile/js/index.js index 3ac79cbb2858212c9dbbe9a3d4db6e67bf98c321..eb884d6634d25e67dedfc19cdc55f5f203eaef7b 100644 --- a/ETSUI/WebComponent/entry/src/main/resources/rawfile/js/index.js +++ b/ETSUI/WebComponent/entry/src/main/resources/rawfile/js/index.js @@ -13,84 +13,87 @@ * limitations under the License. */ -// 奖品名数组 +// Award name array let prizesArr = ["啤酒", "奶茶", "汉堡", "咖啡", "西瓜", "鸡腿", "柠檬", "蛋糕"]; -// 图片数组 +// Image array let arrBigImg = ["./img/1-beer.png", "./img/2-milk.png", "./img/3-hamburg.png", -"./img/4-coffee.png", "./img/5-watermelon.png", "./img/6-drumstick.png", -"./img/7-lemon.png", "./img/8-cake.png", "./img/9-prizes.png"]; + "./img/4-coffee.png", "./img/5-watermelon.png", "./img/6-drumstick.png", + "./img/7-lemon.png", "./img/8-cake.png", "./img/9-prizes.png"]; -// 获取全部奖品单元格 +// Get All Award Cells let allPrizesLi = document.querySelectorAll('.prizes-li'); -// 获取图片 +// Get Pictures let prizesImg = document.querySelectorAll('.pic'); -let count = 0; // 转圈初始值 +// Initial value of rotation +let count = 0; let isClick = true; let index = 3; -let prizesPosition = 0; // 转到哪个位置 +// Turn to which position +let prizesPosition = 0; -// 绑定img +// Bind an IMG for (let j = 0;j < prizesImg.length; j++) { - prizesImg[j].src = arrBigImg[j]; + prizesImg[j].src = arrBigImg[j]; } -let speed = 500; //转圈速度,值越大越慢 +// Rotation speed. The larger the value, the slower the speed +let speed = 500; -// 旋转函数 +// rotation function function roll() { + // velocity decay + speed -= 50; + if (speed <= 10) { + speed = 10; + } - // 速度衰减 - speed -= 50; - if (speed <= 10) { - speed = 10; - } - - // 每次调用都去掉全部active类名 - for (let j = 0; j < allPrizesLi.length; j++) { - allPrizesLi[j].classList.remove('active'); - } - prizesPosition++; + // Remove all active class names for each call + for (let j = 0; j < allPrizesLi.length; j++) { + allPrizesLi[j].classList.remove('active'); + } + prizesPosition++; - // 计算转圈次数 - if (prizesPosition >= allPrizesLi.length - 1) { - prizesPosition = 0; - count++; - } + // Calculate the number of turns + if (prizesPosition >= allPrizesLi.length - 1) { + prizesPosition = 0; + count++; + } - allPrizesLi[prizesPosition].classList.add('active'); - let initSpeed = 500; - let timer; - let totalCount = 5; // 至少转动的总圈数 + allPrizesLi[prizesPosition].classList.add('active'); + let initSpeed = 500; + let timer; + // Total number of revolutions at least + let totalCount = 5; - // 满足转圈数和指定位置就停止 - if (count >= totalCount && (prizesPosition + 1) == index) { - clearTimeout(timer); - isClick = true; - speed = initSpeed; - timer = setTimeout(openDialog, 1000); // 等待1s打开弹窗 - } else { - timer = setTimeout(roll, speed); // 不满足条件时调用定时器 - // 最后一圈减速 - if (count >= totalCount - 1 || speed <= 50) { - speed += 100; - } + // Stop when the number of turns and the specified position are met + if (count >= totalCount && (prizesPosition + 1) === index) { + clearTimeout(timer); + isClick = true; + speed = initSpeed; + // Wait for 1s to open the pop-up window + timer = setTimeout(openDialog, 1000); + } else { + // Wait for 1s to open the pop-up window + timer = setTimeout(roll, speed); + // Last lap deceleration + if (count >= totalCount - 1 || speed <= 50) { + speed += 100; } + } } -// 抽奖开始函数 +// Draw Start Function function startDraw() { - - // 防止抽奖多次触发 - if (isClick) { - count = 0; - - // 随机产生中奖位置 - index = Math.floor(Math.random() * prizesArr.length + 1); - roll(); - isClick = false; - } + // Prevent multiple triggering of the lottery + if (isClick) { + count = 0; + // Randomly generate the winning position + index = Math.floor(Math.random() * prizesArr.length + 1); + roll(); + isClick = false; + } } function openDialog() { - confirm(prizesArr[prizesPosition]); -} + confirm(prizesArr[prizesPosition]); +} \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/src/main/resources/zh_CN/element/string.json b/ETSUI/WebComponent/entry/src/main/resources/zh_CN/element/string.json index 3b33b5ddc7571b1b8f3658fd1b0c35f8225fdd3a..c4b5a195ba5dd0f4304b4b6e15fef81d7440eb74 100644 --- a/ETSUI/WebComponent/entry/src/main/resources/zh_CN/element/string.json +++ b/ETSUI/WebComponent/entry/src/main/resources/zh_CN/element/string.json @@ -55,6 +55,10 @@ { "name": "web_width", "value": "93.3%" + }, + { + "name": "internet_err", + "value": "网络加载失败!" } ] } \ No newline at end of file diff --git a/ETSUI/WebComponent/figures/node.PNG b/ETSUI/WebComponent/figures/node.PNG new file mode 100644 index 0000000000000000000000000000000000000000..39c41b9799190f4f212578293531425c452325a8 Binary files /dev/null and b/ETSUI/WebComponent/figures/node.PNG differ diff --git a/ETSUI/WebComponent/figures/npm.PNG b/ETSUI/WebComponent/figures/npm.PNG new file mode 100644 index 0000000000000000000000000000000000000000..1c9d84ca40d241f441ae0831103fcbb8f16d6a41 Binary files /dev/null and b/ETSUI/WebComponent/figures/npm.PNG differ diff --git a/ETSUI/WebComponent/hvigor/hvigor-config.json5 b/ETSUI/WebComponent/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/ETSUI/WebComponent/hvigor/hvigor-config.json5 +++ b/ETSUI/WebComponent/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/ETSUI/WebCookie/README.md b/ETSUI/WebCookie/README.md index 20cb02d6f28d607628abc2bb298aa12e7ecb5b2f..92240fccebc66f5b2dd6f2b05b06afc61bc48b7a 100644 --- a/ETSUI/WebCookie/README.md +++ b/ETSUI/WebCookie/README.md @@ -1,6 +1,6 @@ # Web组件的使用(ArkTS) -# 介绍 +## 介绍 本篇Codelab使用ArkTS语言实现一个简单的免登录过程,向大家介绍基本的cookie管理操作。主要包含以下功能: @@ -11,7 +11,7 @@ ![](figures/Web.gif) -## 原理说明 +### 原理说明 本应用旨在说明Web组件中cookie的管理操作。结合应用弹框和免登录两种方式进行讲解。 @@ -28,12 +28,12 @@ ![](figures/process.png) -## 相关概念 +### 相关概念 - [Web](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-web.md):提供网页显示能力的组件。 - [WebCookie](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-web.md#webcookie):WebCookie可以控制Web组件中的cookie的各种行为,其中每个应用中的所有Web组件共享一个WebCookie。通过controller方法中的getCookieManager方法可以获取WebCookie对象,进行后续的cookie管理操作。 -## 相关权限 +### 相关权限 本篇Codelab使用的是在线网页,需添加网络权限:ohos.permission.INTERNET。在配置文件module.json5中添加对应信息: @@ -51,19 +51,19 @@ } ``` -# 环境搭建 +## 环境搭建 -## 软件要求 +### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 -## 硬件要求 +### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 -## 环境搭建 +### 环境搭建 完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: @@ -82,9 +82,9 @@ 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 -# 代码结构解读 +## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 @@ -104,9 +104,9 @@ └──entry/src/main/resources // 应用资源目录 ``` -# 实现步骤 +## 实现步骤 -## 应用首页 +### 应用首页 首次打开应用时,应用首页的Web组件内呈现的是登录界面。用户完成登录操作后,会跳转至账号中心界面。在用户不点击“删除cookies”按钮的情况下,用户关闭并再次打开应用,首页仍会跳转至账号中心界面。Web组件会自动存储所加载界面的cookie信息,包括登录的cookie信息。用户可以通过点击“删除cookies”按钮,清除所有cookie信息。首页呈现效果如图: @@ -115,6 +115,7 @@ 首页布局简单,由应用标题“Web组件”、内部标题“Web组件内”、中间加载的网页和底部一排按钮组成。分别对应两个Text组件、一个Web组件以及一个Row容器组件。Row容器组件内包含四个链接按钮,为LinkButton自定义组件。 ```typescript +// WebIndex.ets Column() { Text($r('app.string.navigator_name')) ... @@ -142,6 +143,7 @@ Column() { 自定义组件LinkButton由Text组件和Divider分隔器组件组成。最后一个按钮没有分隔器,通过isNeedDivider标识符判断是否需要添加Divider分隔器组件。 ```typescript +// LinkButton.ets Row() { Text(this.buttonType) ... @@ -156,6 +158,7 @@ Row() { 每个按钮被点击时,都是调用operationMethod函数。函数根据不同操作,执行不同的代码内容。包括cookie的读、写和删除操作,以及页面跳转操作。 ```typescript +// LinkButton.ets operationMethod() { switch (this.buttonType) { case CookieOperation.GET_COOKIE: @@ -182,8 +185,8 @@ operationMethod() { case CookieOperation.VERIFY_COOKIE: router.pushUrl({ url: CommonConstants.PAGE_VERIFY - }).catch(err => { - Logger.error('[LinkButton] push url fail: ' + err); + }).catch((err: Error) => { + Logger.error('[LinkButton] push url fail: ' + JSON.stringify(err)); }); break; default: @@ -192,7 +195,7 @@ operationMethod() { } ``` -## 免登录验证页 +### 免登录验证页 当用户在应用内已完成登录操作,在应用的其他位置使用Web组件访问需要相同授权的页面时,可免去多余的登录操作。一个应用中的所有Web组件共享一个WebCookie,因此一个应用中Web组件存储的cookie信息,也是可以共享的。界面呈现效果如图: @@ -201,8 +204,9 @@ operationMethod() { 该页面布局同样简单,由应用导航标题“Web组件”、内部标题“Web组件内”、加载的网页组成。分别对应一个Navigator导航组件、一个Text组件和一个Web组件。Navigator导航组件类型设置为返回(NavigationType.Back),内容由返回图标和应用标题组成,呈水平排列展示。 ```typescript +// Verify.ets Column() { - Navigator({ target: PAGE_INDEX, type: NavigationType.Back }) { + Navigator({ target: CommonConstants.PAGE_INDEX, type: NavigationType.Back }) { Row() { Image($r('app.media.ic_back')) ... @@ -218,11 +222,12 @@ Column() { ... Web({ - src: USER_ABOUT_URL, + src: CommonConstants.USER_ABOUT_URL, controller: this.controller }) ... } +... ``` ## 总结 diff --git a/ETSUI/WebCookie/entry/src/main/ets/common/utils/Logger.ets b/ETSUI/WebCookie/entry/src/main/ets/common/utils/Logger.ets index da000c758072b38ea9163b6daa0a198ff718670a..ff9a12fcf0420408ff13626fa57be70129c07699 100644 --- a/ETSUI/WebCookie/entry/src/main/ets/common/utils/Logger.ets +++ b/ETSUI/WebCookie/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/ETSUI/WebCookie/entry/src/main/ets/pages/Verify.ets b/ETSUI/WebCookie/entry/src/main/ets/pages/Verify.ets index 83c8d7b522a4db5be6ba8c622d1569aa4d16139b..b9167cd8899f428ce9fec4abc4d94ea5e06db62a 100644 --- a/ETSUI/WebCookie/entry/src/main/ets/pages/Verify.ets +++ b/ETSUI/WebCookie/entry/src/main/ets/pages/Verify.ets @@ -25,7 +25,7 @@ import { CommonConstants } from '../common/constants/CommonConstant'; struct Verify { fileAccess: boolean = true; controller: web_webview.WebviewController = new web_webview.WebviewController(); - isRedirect: boolean; + isRedirect: boolean = false; onPageShow(): void { this.isRedirect = false; diff --git a/ETSUI/WebCookie/entry/src/main/ets/view/LinkButton.ets b/ETSUI/WebCookie/entry/src/main/ets/view/LinkButton.ets index 6bd1560fd0e1a9656e771baed059d02139fcaee8..7e0df036eca0a4261f44672afa93169e9ad2e04f 100644 --- a/ETSUI/WebCookie/entry/src/main/ets/view/LinkButton.ets +++ b/ETSUI/WebCookie/entry/src/main/ets/view/LinkButton.ets @@ -24,8 +24,8 @@ import Logger from '../common/utils/Logger'; */ @Component export struct LinkButton { - buttonType: string; - isNeedDivider: boolean; + buttonType: string = ''; + isNeedDivider: boolean = false; build() { Row() { @@ -73,8 +73,8 @@ export struct LinkButton { case CookieOperation.VERIFY_COOKIE: router.pushUrl({ url: CommonConstants.PAGE_VERIFY - }).catch(err => { - Logger.error('[LinkButton] push url fail: ' + err); + }).catch((err: Error) => { + Logger.error('[LinkButton] push url fail: ' + JSON.stringify(err)); }); break; default: diff --git a/ETSUI/WebCookie/figures/1.png b/ETSUI/WebCookie/figures/1.png index 3347edd2277791c50202505f54469b21bb75b3ec..e3f2b84ed32c27f788d7acfc36d52b63c5a16b6d 100644 Binary files a/ETSUI/WebCookie/figures/1.png and b/ETSUI/WebCookie/figures/1.png differ diff --git a/ETSUI/WebCookie/hvigor/hvigor-config.json5 b/ETSUI/WebCookie/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ETSUI/WebCookie/hvigor/hvigor-config.json5 +++ b/ETSUI/WebCookie/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/EfficiencyEnhancementKit/SuperVisualSample/README.md b/EfficiencyEnhancementKit/SuperVisualSample/README.md index 9cb646dec4f6f8209936133c65ff1fcb47de5a09..2f1dbbbd44077a9f590a016f83c1e88616f4a580 100644 --- a/EfficiencyEnhancementKit/SuperVisualSample/README.md +++ b/EfficiencyEnhancementKit/SuperVisualSample/README.md @@ -17,20 +17,22 @@ 低代码开发方式具有丰富的UI界面编辑功能,通过可视化界面开发方式快速构建布局,可有效降低开发者的上手成本并提升开发者构建UI界面的效率。 - [List](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md):List 是很常用的滚动类容器组件之一,它按照水平或者竖直方向线性排列子组件, List 的子组件必须是 ListItem ,它的宽度默认充满 List 的宽度。 + - [循环渲染](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-rendering-control-foreach.md):开发框架提供循环渲染(ForEach组件)来迭代数组,并为每个数组项创建相应的组件。 + - [警告弹窗](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-methods-alert-dialog-box.md):显示警告弹窗组件,可设置文本内容与响应回调。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -51,13 +53,11 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 - ``` └──entry/src/main/ets // 代码区 │ ├──common │ │ ├──images // 图片 -│ │ └──Const.ets // 常量类 +│ │ └──Const.ets // 常量类 │ ├──entryability │ │ └──EntryAbility.ets // 程序入口类 │ └──pages diff --git a/EfficiencyEnhancementKit/SuperVisualSample/entry/oh-package.json5 b/EfficiencyEnhancementKit/SuperVisualSample/entry/oh-package.json5 index 225946cb11a2c405c8dc81eea89c22f923556638..19b9234a98d43a4711a0fc32cef604159228d3cd 100644 --- a/EfficiencyEnhancementKit/SuperVisualSample/entry/oh-package.json5 +++ b/EfficiencyEnhancementKit/SuperVisualSample/entry/oh-package.json5 @@ -7,4 +7,4 @@ "main": "", "version": "1.0.0", "dependencies": {} -} +} \ No newline at end of file diff --git a/EfficiencyEnhancementKit/SuperVisualSample/entry/src/main/ets/pages/TaskDetailPage.ets b/EfficiencyEnhancementKit/SuperVisualSample/entry/src/main/ets/pages/TaskDetailPage.ets index de6e8757a1ff57ef6e018f0f3798ededb83073e2..3ae0595f1a9d67770d665d67a8b8f7a007cdf132 100644 --- a/EfficiencyEnhancementKit/SuperVisualSample/entry/src/main/ets/pages/TaskDetailPage.ets +++ b/EfficiencyEnhancementKit/SuperVisualSample/entry/src/main/ets/pages/TaskDetailPage.ets @@ -16,12 +16,12 @@ import router from '@ohos.router'; import { SLEEP, TASK_NAME, TASK_TARGET, TASK_PROGRESS, FREQUENCY, REMIND_TIME, EVERYDAY } from '../common/Const'; -class DetailModel { +interface DetailModel { title: string; value: string; } -const DETAILS = [ +const DETAILS: DetailModel[] = [ { title: TASK_NAME, value: SLEEP }, { title: TASK_TARGET, value: SLEEP }, { title: TASK_PROGRESS, value: '100%' }, diff --git a/EfficiencyEnhancementKit/SuperVisualSample/entry/src/main/ets/pages/TaskPage.ets b/EfficiencyEnhancementKit/SuperVisualSample/entry/src/main/ets/pages/TaskPage.ets index 877a3cd2d781946cd078c1490533f865cb8da720..f2011fda2f520fb6f926d370eafaad5e98e2c025 100644 --- a/EfficiencyEnhancementKit/SuperVisualSample/entry/src/main/ets/pages/TaskPage.ets +++ b/EfficiencyEnhancementKit/SuperVisualSample/entry/src/main/ets/pages/TaskPage.ets @@ -16,14 +16,14 @@ import router from '@ohos.router'; import { APPLE, SMILE, BRUSH_TEETH, SLEEP, DRINK, GET_UP } from '../common/Const'; -class TaskInfo { +interface TaskInfo { taskID: number; taskName: string; icon: string; targetValue: string; } -const TASK_LIST = [ +const TASK_LIST: TaskInfo[] = [ { taskID: 1, taskName: GET_UP, diff --git a/EfficiencyEnhancementKit/SuperVisualSample/hvigor/hvigor-config.json5 b/EfficiencyEnhancementKit/SuperVisualSample/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/EfficiencyEnhancementKit/SuperVisualSample/hvigor/hvigor-config.json5 +++ b/EfficiencyEnhancementKit/SuperVisualSample/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/EfficiencyEnhancementKit/SuperVisualSample/oh-package.json5 b/EfficiencyEnhancementKit/SuperVisualSample/oh-package.json5 index 7c97ce461b6231cfb419ea76bc4540a7e2c85ce3..dd66f2ec61964f428aa3154d8f82df40d3d92c11 100644 --- a/EfficiencyEnhancementKit/SuperVisualSample/oh-package.json5 +++ b/EfficiencyEnhancementKit/SuperVisualSample/oh-package.json5 @@ -9,4 +9,4 @@ "main": "", "version": "1.0.0", "dependencies": {} -} +} \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/README.md b/ExcellentCase/Healthy_life/README.md index d6ed1570772d9d0b83e19d6134a5e0e9de0b9946..1d9fe0963c76dda1332cc098a45283a79da08e18 100644 --- a/ExcellentCase/Healthy_life/README.md +++ b/ExcellentCase/Healthy_life/README.md @@ -6,35 +6,46 @@ 1. 用户可以创建最多6个健康生活任务(早起,喝水,吃苹果,每日微笑,刷牙,早睡),并设置任务目标、是否开启提醒、提醒时间、每周任务频率。 2. 用户可以在主页面对设置的健康生活任务进行打卡,其中早起、每日微笑、刷牙和早睡只需打卡一次即可完成任务,喝水、吃苹果需要根据任务目标量多次打卡完成。 + 3. 主页可显示当天的健康生活任务完成进度,当天所有任务都打卡完成后,进度为100%,并且用户的连续打卡天数加一。 + 4. 当用户连续打卡天数达到3、7、30、50、73、99天时,可以获得相应的成就。成就在获得时会以动画形式弹出,并可以在“成就”页面查看。 + 5. 用户可以查看以前的健康生活任务完成情况。 本应用的运行效果如下图所示: + ![](figures/健康生活.gif) ### 相关概念 -- [@AppStorage](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-appstorage.md):应用程序中的单例对象,为应用程序范围内的可变状态属性提供中央存储。 -- [@Observed 和 @ObjectLink](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-observed-and-objectlink.md):@Observed适用于类,表示类中的数据变化由UI页面管理;@ObjectLink应用于被@Observed装饰类的对象。 -- [@Consume 和 @Provide](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-provide-and-consume.md):@Provide作为数据提供者,可以更新子节点的数据,触发页面渲染。@Consume检测到@Provide数据更新后,会发起当前视图的重新渲染。 -- [Flex](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md):一个功能强大的容器组件,支持横向布局,竖向布局,子组件均分和流式换行布局。 -- [List](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md):List是很常用的滚动类容器组件之一,它按照水平或者竖直方向线性排列子组件, List的子组件必须是ListItem,它的宽度默认充满List的宽度。 -- [TimePicker](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-timepicker.md):TimePicker是选择时间的滑动选择器组件,默认以00:00至23:59的时间区创建滑动选择器。 -- [Toggle](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-toggle.md):组件提供勾选框样式、状态按钮样式及开关样式。 -- [关系型数据库(Relational Database,RDB)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-data-rdb.md):一种基于关系模型来管理数据的数据库。 +- [@Observed 和 @ObjectLink](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-state-mgmt-page-level.md#observed%E5%92%8Cobjectlink%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86):@Observed适用于类,表示类中的数据变化由UI页面管理;@ObjectLink应用于被@Observed装饰类的对象。 + +- [@Consume 和 @Provide](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-state-mgmt-page-level.md#consume%E5%92%8Cprovide):@Provide作为数据提供者,可以更新子节点的数据,触发页面渲染。@Consume检测到@Provide数据更新后,会发起当前视图的重新渲染。 + +- [Flex](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md):一个功能强大的容器组件,支持横向布局,竖向布局,子组件均分和流式换行布局。 + +- [List](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md):List是很常用的滚动类容器组件之一,它按照水平或者竖直方向线性排列子组件, List的子组件必须是ListItem,它的宽度默认充满List的宽度。 + +- [TimePicker](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-timepicker.md):TimePicker是选择时间的滑动选择器组件,默认以00:00至23:59的时间区创建滑动选择器。 + +- [Toggle](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-toggle.md):组件提供勾选框样式、状态按钮样式及开关样式。 + +- [后台代理提醒](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-reminderAgentManager.md):使用后台代理提醒能力后,应用可以被冻结或退出,计时和弹出提醒的功能将被后台系统服务代理。 + +- [关系型数据库(Relational Database,RDB)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-data-rdb.md):一种基于关系模型来管理数据的数据库。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -55,81 +66,92 @@ ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` -├──entry/src/main/ets // 代码区 -│ ├──common -│ │ ├──bean -│ │ │ ├──ColumnInfo.ets // 数据表信息接口 -│ │ │ ├──DayInfo.ets // 每日信息接口 -│ │ │ ├──GlobalInfo.ets // 全局信息接口 -│ │ │ └──TaskInfo.ets // 任务信息接口 -│ │ ├──constants -│ │ │ └──CommonConstants.ets // 公共常量 -│ │ ├──database -│ │ │ ├──rdb // 数据库封装类 -│ │ │ │ ├──RdbHelper.ets -│ │ │ │ ├──RdbHelperImp.ets -│ │ │ │ ├──RdbUtils.ets -│ │ │ │ └──TableHelper.ets -│ │ │ └──tables // 数据表 -│ │ │ ├──DayInfoApi.ets -│ │ │ ├──GlobalInfoApi.ets -│ │ │ └──TaskInfoApi.ets -│ │ └──utils -│ │ ├──Logger.ets // 日志类 -│ │ ├──BroadCast.ets // 通知 -│ │ ├──HealthDataSrcMgr.ets // 数据管理单例 -│ │ └──Utils.ets // 工具类 -│ ├──entryability -│ │ └──EntryAbility.ts // 程序入口类 -│ ├──model // model -│ │ ├──AchieveModel.ets -│ │ ├──DatabaseModel.ets // 数据库model -│ │ ├──Mine.ets -│ │ ├──NavItemModel.ets // 菜单栏model -│ │ ├──RdbColumnModel.ets -│ │ ├──TaskInitList.ets -│ │ └──WeekCalendarModel.ets // 日历model -│ ├──pages -│ │ ├──AdvertisingPage.ets // 广告页 -│ │ ├──MainPage.ets // 应用主页面 -│ │ ├──MinePage.ets // 我的页面 -│ │ ├──SplashPage.ets // 启动页 -│ │ ├──TaskEditPage.ets // 任务编辑页面 -│ │ └──TaskListPage.ets // 任务列表页面 -│ ├──view -│ │ ├──dialog // 弹窗组件 -│ │ │ ├──AchievementDialog.ets // 成就弹窗 -│ │ │ ├──CustomDialogView.ets // 自定义弹窗 -│ │ │ ├──TaskDetailDialog.ets // 打卡弹窗 -│ │ │ ├──TaskDialogView.ets -│ │ │ ├──TaskSettingDialog.ets // 任务编辑相关弹窗 -│ │ │ └──UserPrivacyDialog.ets -│ │ ├──home // 主页面相关组件 -│ │ │ ├──AddBtnComponent.ets // 添加任务按钮组件 -│ │ │ ├──HomeTopComponent.ets // 首页顶部组件 -│ │ │ ├──TaskCardComponent.ets // 任务item组件件 -│ │ │ └──WeekCalendarComponent.ets // 日历组件 -│ │ ├──task // 任务相关组件 -│ │ │ ├──TaskDetailComponent.ets // 任务编辑详情组件 -│ │ │ ├──TaskEditListItem.ets // 任务编辑行内容 -│ │ │ └──TaskListComponent.ets // 任务列表组件 -│ │ ├──AchievementComponent.ets // 成就页面 -│ │ ├──BadgeCardComponent.ets // 勋章卡片组件 -│ │ ├──BadgePanelComponent.ets // 勋章面板组件 -│ │ ├──HealthTextComponent.ets // 自定义text组件 -│ │ ├──HomeComponent.ets // 首页页面 -│ │ ├──ListInfo.ets // 用户信息列表 -│ │ ├──TitleBarComponent.ets // 成就标题组件 -│ │ └──UserBaseInfo.ets // 用户基本信息 -│ └──viewmodel // viewmodel -│ ├──AchievementViewModel.ets // 成就相关模块 -│ ├──CalendarViewModel.ets // 日历相关模块 -│ ├──HomeViewModel.ets // 首页相关模块 -│ └──TaskViewModel.ets // 任务设置相关模块 -└──entry/src/main/resources // 资源文件夹 +├─entry/src/main/ets // 代码区 +│ ├─common +│ │ ├─constants +│ │ │ └─CommonConstants.ets // 公共常量 +│ │ ├─database +│ │ │ ├─rdb // 数据库 +│ │ │ │ ├─RdbHelper.ets +│ │ │ │ ├─RdbHelperImp.ets +│ │ │ │ ├─RdbUtil.ets +│ │ │ │ └─TableHelper.ets +│ │ │ └─tables // 数据库接口 +│ │ │ ├─DayInfoApi.ets +│ │ │ ├─GlobalInfoApi.ets +│ │ │ └─TaskInfoApi.ets +│ │ └─utils +│ │ ├─BroadCast.ets // 通知 +│ │ ├─GlobalContext.ets // 全局上下文 +│ │ ├─HealthDataSrcMgr.ets // 数据管理单例 +│ │ ├─Logger.ets // 日志类 +│ │ └─Utils.ets // 工具类 +│ ├─entryability +│ │ └─EntryAbility.ets // 程序入口类 +│ ├─model // model +│ │ ├─AchieveModel.ets +│ │ ├─DatabaseModel.ets // 数据库model +│ │ ├─Mine.ets +│ │ ├─NavItemModel.ets // 菜单栏model +│ │ ├─RdbColumnModel.ets // 数据库表数据 +│ │ ├─TaskInitList.ets +│ │ └─WeekCalendarModel.ets // 日历model +│ ├─pages +│ │ ├─AdvertisingPage.ets // 广告页 +│ │ ├─MainPage.ets // 应用主页面 +│ │ ├─MinePage.ets // 我的页面 +│ │ ├─SplashPage.ets // 启动页 +│ │ ├─TaskEditPage.ets // 任务编辑页面 +│ │ └─TaskListPage.ets // 任务列表页面 +│ ├─service +│ │ └─ReminderAgent.ets // 后台提醒 +│ ├─view +│ │ ├─dialog // 弹窗组件 +│ │ │ ├─AchievementDialog.ets // 成就弹窗 +│ │ │ ├─CustomDialogView.ets // 自定义弹窗 +│ │ │ ├─TaskDetailDialog.ets // 打卡弹窗 +│ │ │ ├─TaskDialogView.ets // 任务对话框 +│ │ │ ├─TaskSettingDialog.ets // 任务编辑相关弹窗 +│ │ │ └─UserPrivacyDialog.ets +│ │ ├─home // 主页面相关组件 +│ │ │ ├─AddBtnComponent.ets // 添加任务按钮组件 +│ │ │ ├─HomeTopComponent.ets // 首页顶部组件 +│ │ │ ├─TaskCardComponent.ets // 任务item组件件 +│ │ │ └─WeekCalendarComponent.ets // 日历组件 +│ │ ├─task // 任务相关组件 +│ │ │ ├─TaskDetailComponent.ets // 任务编辑详情组件 +│ │ │ ├─TaskEditListItem.ets // 任务编辑行内容 +│ │ │ └─TaskListComponent.ets // 任务列表组件 +│ │ ├─AchievementComponent.ets // 成就页面 +│ │ ├─BadgeCardComponent.ets // 勋章卡片组件 +│ │ ├─BadgePanelComponent.ets // 勋章面板组件 +│ │ ├─HealthTextComponent.ets // 自定义text组件 +│ │ ├─HomeComponent.ets // 首页页面 +│ │ ├─ListInfo.ets // 用户信息列表 +│ │ ├─TitleBarComponent.ets // 成就标题组件 +│ │ └─UserBaseInfo.ets // 用户基本信息 +│ └─viewmodel // viewmodel +│ ├─AchievementInfo.ets // 成就信息 +│ ├─AchievementMapInfo.ets // 成就map信息 +│ ├─AchievementViewModel.ets // 成就相关模块 +│ ├─BroadCastCallBackInfo.ets // 通知回调信息 +│ ├─CalendarViewModel.ets // 日历相关模块 +│ ├─CardInfo.ets // 成就卡片信息 +│ ├─ColumnInfo.ets // 数据库表结构 +│ ├─CommonConstantsInfo.ets // 公共常量信息 +│ ├─DayInfo.ets // 每日信息 +│ ├─GlobalInfo.ets // 全局信息 +│ ├─HomeViewModel.ets // 首页相关模块 +│ ├─PublishReminderInfo.ets // 发布提醒信息 +│ ├─ReminderInfo.ets // 提醒信息 +│ ├─TaskInfo.ets // 任务信息 +│ ├─TaskViewModel.ets // 任务设置相关模块 +│ ├─WeekCalendarInfo.ets // 日历信息 +│ └─WeekCalendarMethodInfo.ets // 日历方法信息 +└─entry/src/main/resources // 资源文件夹 ``` ## 应用架构分析 @@ -153,43 +175,40 @@ 通过修改/entry/src/main/ets/entryability里的loadContent路径可以改变应用的入口文件,我们需要把入口文件改为我们写的SplashPage启动页面。 ```typescript -windowStage.loadContent("pages/SplashPage", (err, data) => { +// EntryAbility.ets +windowStage.loadContent('pages/SplashPage', (err, data) => { if (err.code) {...} - Logger.info('windowStage','Succeeded in loading the content. Data: ' + JSON.stringify(data)) + Logger.info('windowStage','Succeeded in loading the content. Data: ' + JSON.stringify(data)); }); ``` 在SplashPage启动页的文件里通过首选项来实现是否需要弹“权限管理”的弹窗,如果需要弹窗的情况下,用户点击同意权限后通过首选项对用户的操作做持久化保存。相关代码如下: ```typescript -// SplashIndex.ets +// SplashPage.ets import data_preferences from '@ohos.data.preferences'; - onConfirm() { - let preferences = data_preferences.getPreferences(globalThis.abilityContext, H_STORE); + let preferences = data_preferences.getPreferences(this.context, H_STORE); preferences.then((res) => { res.put(IS_PRIVACY, true).then(() => { res.flush(); - Logger.info('TaskInfoTable', 'isPrivacy is put success'); - }).catch((err) => { - Logger.info('TaskInfoTable', 'isPrivacy put failed. Cause:' + err); + Logger.info('SplashPage','isPrivacy is put success'); + }).catch((err: Error) => { + Logger.info('SplashPage','isPrivacy put failed. Cause:' + err); }); }) this.jumpAdPage(); } - exitApp() { - globalThis.abilityContext.terminateSelf(); + this.context.terminateSelf(); } - jumpAdPage() { setTimeout(() => { - router.replace({ url: 'pages/AdvertisingPage' }); - }, commonConst.LAUNCHER_DELAY_TIME); + router.replaceUrl({ url: 'pages/AdvertisingPage' }); + }, Const.LAUNCHER_DELAY_TIME); } - aboutToAppear() { - let preferences = data_preferences.getPreferences(globalThis.abilityContext, H_STORE); + let preferences = data_preferences.getPreferences(this.context, H_STORE); preferences.then((res) => { res.get(IS_PRIVACY, false).then((isPrivate) => { if (isPrivate === true) { @@ -211,20 +230,24 @@ aboutToAppear() { 本应用一共有首页(HomeIndex),成就(AchievementIndex)和我的(MineIndex)三个模块,分别对应Tabs组件的三个子组件TabContent。 ```typescript -Tabs({ barPosition: BarPosition.End, controller: this.tabController }) { - TabContent() { - HomeIndex({ editedTaskInfo: $editedTaskInfo, editedTaskID: $editedTaskID }) - } - .tabBar(this.TabBuilder(TabId.HOME)) - TabContent() { - AchievementIndex() - } - .tabBar(this.TabBuilder(TabId.ACHIEVEMENT)) - TabContent() { - MineIndex() - } - .tabBar(this.TabBuilder(TabId.MINE)) +// MainPage.ets +TabContent() { + HomeIndex({ homeStore: $homeStore, editedTaskInfo: $editedTaskInfo, editedTaskID: $editedTaskID }) + .borderWidth({ bottom: 1 }) + .borderColor($r('app.color.primaryBgColor')) } +.tabBar(this.TabBuilder(TabId.HOME)) +.align(Alignment.Start) +TabContent() { + AchievementIndex() +} +.tabBar(this.TabBuilder(TabId.ACHIEVEMENT)) +TabContent() { + MineIndex() + .borderWidth({ bottom: 1 }) + .borderColor($r('app.color.primaryBgColor')) +} +.tabBar(this.TabBuilder(TabId.MINE)) ``` ### 首页 @@ -240,13 +263,14 @@ Tabs({ barPosition: BarPosition.End, controller: this.tabController }) { Scroll滚动的过程中,在它的onScroll方法里我们通过计算它Y轴的偏移量来改变当前界面的@State修饰的naviAlpha变量值,进而改变顶部标题的背景色,代码实现如下: ```typescript + // HomeComponent.ets // 视图滚动的过程中处理导航栏的透明度 onScrollAction() { - let yOffset = this.scroller.currentOffset().yOffset; - if (yOffset > commonConst.DEFAULT_56) { - this.naviAlpha = 1; + this.yOffset = this.scroller.currentOffset().yOffset; + if (this.yOffset > Const.DEFAULT_56) { + this.naviAlpha = 1; } else { - this.naviAlpha = yOffset / commonConst.DEFAULT_56; + this.naviAlpha = this.yOffset / Const.DEFAULT_56; } } ``` @@ -256,14 +280,15 @@ Tabs({ barPosition: BarPosition.End, controller: this.tabController }) { 日历组件主要用到的是一个横向滑动的Scroll组件。 - ```typescript +```typescript +// WeekCalendarComponent.ets build() { Row() { Column() { Row() {...} Scroll(this.scroller) { Row() { - ForEach(this.homeStore.dateArr, (item: WeekDateModel, index: number) => { + ForEach(this.homeStore.dateArr, (item: WeekDateModel, index?: number) => { Column() { Text(item.weekTitle) .fontColor(sameDate(item.date, this.homeStore.showDate) ? $r('app.color.blueColor') : $r('app.color.titleColor')) @@ -271,49 +296,41 @@ Tabs({ barPosition: BarPosition.End, controller: this.tabController }) { .color(sameDate(item.date, this.homeStore.showDate) ? $r('app.color.blueColor') : $r('app.color.white')) Image(this.getProgressImg(item)) } - .onClick(() => WeekCalendarMethods.calenderItemClickAction.call(this, item, index)) + .onClick(() => WeekCalendarMethods.calenderItemClickAction(item, index, this.homeStore)) }) - } - } - .onScrollEnd(() => WeekCalendarMethods.onScrollEndAction.call(this)) - .onScrollEdge(() => WeekCalendarMethods.onScrollEdgeAction.call(this)) - }... - }... + } + } + ... + .onScrollEdge((event) => this.onScrollEdgeAction(event)) + } + ... } + ... } - ``` +``` 手动滑动页面时,我们通过在onScrollEnd方法里计算Scroll的偏移量来实现分页的效果,同时Scroll有提供scrollPage\(\)方法可供我们点击左右按钮的时候来进行页面切换。 ```typescript + // WeekCalendarComponent.ets import display from '@ohos.display'; ... // scroll滚动停止时通过判断偏移量进行分页处理 - function onScrollEndAction() { - let scrollWidth = DEFAULT_SCROLL_WIDTH; - - // 获取屏幕的宽度 - display.getDefaultDisplay((err, data) => { - if (!err) { - scrollWidth = data.width * DEFAULT_SCROLL_PERCENT; - } else {...} - }) - - // 区分是否是手动滑动,点击左右箭头按钮导致Scroll滑动时不作处理,不然会引起死循环 - if (!this.isPageScroll) { - let page = Math.round(this.scroller.currentOffset().xOffset / scrollWidth); - page = this.isLoadMore ? page + 1 : page; - if (this.scroller.currentOffset().xOffset % scrollWidth != 0 || this.isLoadMore) { - let xOffset = page * scrollWidth; - - // 滑动到指定位置 - this.scroller.scrollTo({ xOffset, yOffset: 0 }); - this.isLoadMore = false; - } - - // 处理当前界面展示的数据 - ... - } + onScrollEndAction() { + if (this.isPageScroll === false) { + let page = Math.round(this.scroller.currentOffset().xOffset / this.scrollWidth); + page = (this.isLoadMore === true) ? page + 1 : page; + if (this.scroller.currentOffset().xOffset % this.scrollWidth != 0 || this.isLoadMore === true) { + let xOffset = page * this.scrollWidth; + this.scroller.scrollTo({ xOffset, yOffset: 0 } as ScrollTo); + this.isLoadMore = false; + } + this.currentPage = this.homeStore.dateArr.length / Const.WEEK_DAY_NUM - page - 1; + Logger.info('HomeIndex', 'onScrollEnd: page ' + page + ', listLength ' + this.homeStore.dateArr.length); + let dayModel: WeekDateModel = this.homeStore.dateArr[Const.WEEK_DAY_NUM * page+this.homeStore.selectedDay]; + Logger.info('HomeIndex', 'currentItem: ' + JSON.stringify(dayModel) + ', selectedDay ' + this.homeStore.selectedDay); + this.homeStore!.setSelectedShowDate(dayModel!.date!.getTime()); + } this.isPageScroll = false; } ``` @@ -321,14 +338,15 @@ Tabs({ barPosition: BarPosition.End, controller: this.tabController }) { 我们在需要在Scroll滑动到左边边缘的时候去请求更多的历史数据以便Scroll能一直滑动,通过Scroll的onScrollEdge方法我们可以判断它是否已滑到边缘位置。 ```typescript - function onScrollEdgeAction(side: Edge) { - if (side == Edge.Top && !this.isPageScroll) { + // WeekCalendarComponent.ets + onScrollEdgeAction(side: Edge) { + if (side === Edge.Top && this.isPageScroll === false) { Logger.info('HomeIndex', 'onScrollEdge: currentPage ' + this.currentPage); - if ((this.currentPage + LAZY_DATA_PAGE) * WEEK_DAY_NUM >= this.homeStore.dateArr.length) { + if ((this.currentPage + 2) * Const.WEEK_DAY_NUM >= this.homeStore.dateArr.length) { Logger.info('HomeIndex', 'onScrollEdge: load more data'); let date: Date = new Date(this.homeStore.showDate); - date.setDate(date.getDate() - WEEK_DAY_NUM); - this.homeStore.getPreWeekData(date); + date.setDate(date.getDate() - Const.WEEK_DAY_NUM); + this.homeStore.getPreWeekData(date, () => {}); this.isLoadMore = true; } } @@ -338,15 +356,16 @@ Tabs({ barPosition: BarPosition.End, controller: this.tabController }) { homeStore主要是请求数据库的数据并对数据进行处理进而渲染到界面上。 ```typescript - public getPreWeekData(date: Date) { - let [initArr, dateArr] = getPreviousWeek(date); + // HomeViewModel.ets + public getPreWeekData(date: Date, callback: Function) { + let weekCalendarInfo: WeekCalendarInfo = getPreviousWeek(date); // 请求数据库数据 - this.dayInfoApi.queryList(dateArr, (res: DayInfo[]) => { + DayInfoApi.queryList(weekCalendarInfo.strArr, (res: DayInfo[]) => { // 数据处理 ... - this.dateArr = initArr.concat(...this.dateArr); + this.dateArr = weekCalendarInfo.arr.concat(...this.dateArr); }) } ``` @@ -354,16 +373,18 @@ Tabs({ barPosition: BarPosition.End, controller: this.tabController }) { 同时我们还需要知道怎么根据当天的日期计算出本周内的所有日期数据。 ```typescript - export function getPreviousWeek(showDate: Date): [Array, Array] { + // WeekCalendarModel.ets + export function getPreviousWeek(showDate: Date): WeekCalendarInfo { + Logger.debug('WeekCalendarModel', 'get week date by date: ' + showDate.toDateString()); + let weekCalendarInfo: WeekCalendarInfo = new WeekCalendarInfo(); let arr: Array = []; - let strArr: Array = []; - + let strArr: Array = []; + let currentDay = showDate.getDay() - 1; // 由于date的getDay()方法返回的是0-6代表周日到周六,我们界面上展示的周一-周日为一周,所以这里要将getDay()数据偏移一天 let currentDay = showDate.getDay() - 1; - if (showDate.getDay() == 0) { + if (showDate.getDay() === 0) { currentDay = 6; } - // 将日期设置为当前周第一天的数据(周一) showDate.setDate(showDate.getDate() - currentDay); for (let index = WEEK_DAY_NUM; index > 0; index--) { @@ -373,7 +394,10 @@ Tabs({ barPosition: BarPosition.End, controller: this.tabController }) { strArr.push(dateStr); arr.push(new WeekDateModel(WEEK_TITLES[tempDate.getDay()], dateStr, tempDate)); } - return [arr, strArr]; + Logger.debug('WeekCalendarModel', JSON.stringify(arr)); + weekCalendarInfo.arr = arr; + weekCalendarInfo.strArr = strArr; + return weekCalendarInfo; } ``` @@ -383,58 +407,80 @@ Tabs({ barPosition: BarPosition.End, controller: this.tabController }) { 由于首页右下角有一个悬浮按钮,所以首页整体我们用了一个Stack组件,将右下角的悬浮按钮和顶部的title放在滚动组件层的上边。 ```typescript + // HomeComponent.ets build() { Stack() { Scroll(this.scroller) { Column() { ... // 上部界面组件 Column() { - ForEach(TaskList, (item: TaskInfo) => { - TaskCard(..., - clickAction: (isClick) => this.taskItemAction(item, isClick)) - }, item => item.date + item.taskID)} - } - } + ForEach(this.homeStore.getTaskListOfDay(), (item: TaskInfo) => { + TaskCard({ + taskInfoStr: JSON.stringify(item), + clickAction: (isClick: boolean) => this.taskItemAction(item, isClick) + }) + ... + }, (item: TaskInfo) => JSON.stringify(item))} + } } - .onScroll(this.onScrollAction.bind(this)) - // 悬浮按钮 - AddBtn() - // 顶部title - Row() { - Text($r('app.string.MainAbility_label')) - } - .position({ x: 0, y: 0 }) - .backgroundColor(`rgba(${WHITE_COLOR_0X},${WHITE_COLOR_0X},${WHITE_COLOR_0X},${this.naviAlpha})`) - CustomDialogView() - } - .allSize() - .backgroundColor($r('app.color.primaryBgColor')) - } + } + .onScroll(() => { + this.onScrollAction() + }) + // 悬浮按钮 + AddBtn({ clickAction: () => { + this.editTaskAction() + } }) + // 顶部title + Row() { + Text($r('app.string.EntryAbility_label')) + .titleTextStyle() + .fontSize($r('app.float.default_24')) + .padding({ left: Const.THOUSANDTH_66 }) + } + .width(Const.THOUSANDTH_1000) + .height(Const.DEFAULT_56) + .position({ x: 0, y: 0 }) + .backgroundColor(`rgba(${WHITE_COLOR_0X},${WHITE_COLOR_0X},${WHITE_COLOR_0X},${this.naviAlpha})`) + CustomDialogView() + } + .allSize() + .backgroundColor($r('app.color.primaryBgColor')) ``` 4. 界面跳转及传参 - + 首页任务列表长按时需要跳转到对应的任务编辑界面,同时点击悬浮按钮时需要跳转到任务列表页面。 页面跳转需要在头部引入router。 ```typescript + // HomeComponent.ets import router from '@ohos.router'; ``` - + 任务item的点击事件代码如下 ```typescript - taskItemAction(item: TaskInfo, isClick: boolean) { + // HomeComponent.ets + taskItemAction(item: TaskInfo, isClick: boolean): void { + if (!this.homeStore.checkCurrentDay()) { + return; + } if (isClick) { // 点击任务打卡 - let callback: CustomDialogCallback = { confirmCallback: this.onConfirm.bind(this), cancelCallback: null }; - this.broadCast.emit(BroadCastType.SHOW_TASK_DETAIL_DIALOG, [item, callback]); + let callback: CustomDialogCallback = { confirmCallback: (taskTemp: TaskInfo) => { + this.onConfirm(taskTemp) + }, cancelCallback: () => { + } }; + this.broadCast.emit(BroadCastType.SHOW_TASK_DETAIL_DIALOG, [item, callback]); } else { // 长按编辑任务 - const editTask: ITaskItem = {...}; - router.push({ url: 'pages/task/TaskEdit', params: { params: JSON.stringify(editTask) } }); + let editTaskStr: string = JSON.stringify(TaskMapById[item.taskID - 1]); + let editTask: ITaskItem = JSON.parse(editTaskStr); + ... + router.pushUrl({ url: 'pages/TaskEditPage', params: { params: JSON.stringify(editTask) } }); } } ``` @@ -470,51 +516,59 @@ Navigation() { // 页面中间的列表 TaskList() } - .width(THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.Center) } -.size({ width: THOUSANDTH_1000, height: THOUSANDTH_1000 }) -.title(ADD_TASK_TITLE) +.size({ width: Const.THOUSANDTH_1000, height: Const.THOUSANDTH_1000 }) +.title(Const.ADD_TASK_TITLE) +.titleMode(NavigationTitleMode.Mini) ``` 列表右侧有一个判断是否开启的文字标识,点击某个列表需要跳转到对应的任务编辑页里。具体的列表实现如下: ```typescript // TaskListComponent.ets -List({ space: commonConst.LIST_ITEM_SPACE }) { - ForEach(this.taskList, (item) => { - ListItem() { - Row() { - Row() { - Image(item?.icon) - Text(item?.taskName) - ... - } - .width(commonConst.THOUSANDTH_500) - // 状态显示 - if (item?.isOpen) { - Text($r('app.string.already_open')) +@Component +export default struct TaskList { + ... + build() { + List({ space: Const.LIST_ITEM_SPACE }) { + ForEach(this.taskList, (item: ITaskItem) => { + ListItem() { + Row() { + Row() { + Image(item?.icon) + ... + Text(item?.taskName).fontSize(Const.DEFAULT_20).fontColor($r('app.color.titleColor')) + }.width(Const.THOUSANDTH_500) + + Blank() + ... + // 状态改变 + if (item?.isOpen) { + Text($r('app.string.already_open')) + ... + } + Image($r('app.media.ic_right_grey')) + ... + } + ... } - Image($rawfile('task/right_grey.png')) - .width(commonConst.DEFAULT_8) - .height(commonConst.DEFAULT_16) - } - ... + ... + .onClick(() => { + router.pushUrl({ + url: 'pages/TaskEditPage', + params: { + params: formatParams(item), + } + }) + }) + ... + }, (item: ITaskItem) => JSON.stringify(item)) } - ... - - // 路由跳转到任务编辑页 - .onClick(() => { - router.push({ - url: 'pages/task/TaskEdit', - params: { - params: formatParams(item), - } - }) - }) - ... - }) + ... + } } ``` @@ -534,18 +588,19 @@ Navigation() { Column() { TaskDetail() } - .width(THOUSANDTH_1000) - .height(THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) + .height(Const.THOUSANDTH_1000) } -.size({ width: THOUSANDTH_1000, height: THOUSANDTH_1000 }) -.title(EDIT_TASK_TITLE) +.size({ width: Const.THOUSANDTH_1000, height: Const.THOUSANDTH_1000 }) +.title(Const.EDIT_TASK_TITLE) +.titleMode(NavigationTitleMode.Mini) ``` 自定义组件由List以及其子组件ListItem构成: ```typescript // TaskDetailComponent.ets -List({ space: commonConst.LIST_ITEM_SPACE }) { +List({ space: Const.LIST_ITEM_SPACE }) { ListItem() { TaskChooseItem() } @@ -567,29 +622,33 @@ List({ space: commonConst.LIST_ITEM_SPACE }) { } ... } -.width(commonConst.THOUSANDTH_940) -.margin({ bottom: commonConst.THOUSANDTH_400 }) +.width(Const.THOUSANDTH_940) ``` 其中做了禁用判断,需要任务打开才可以点击编辑: ```typescript -.enabled(this.settingParams?.isOpen) +// TaskDetailComponent.ets +.enabled( + this.settingParams?.isOpen +) ``` 一些特殊情况的禁用,如每日微笑、每日刷牙的目标设置不可编辑: ```typescript +// TaskDetailComponent.ets .enabled( this.settingParams?.isOpen - && (this.settingParams?.taskID !== taskType.smile) - && (this.settingParams?.taskID !== taskType.brushTeeth) + && this.settingParams?.taskID !== taskType.smile + && this.settingParams?.taskID !== taskType.brushTeeth ) ``` 提醒时间在开启提醒打开之后才可以编辑: ```typescript +// TaskDetailComponent.ets .enabled(this.settingParams?.isOpen && this.settingParams?.isAlarm) ``` @@ -597,34 +656,22 @@ List({ space: commonConst.LIST_ITEM_SPACE }) { ```typescript // TaskDetailComponent.ets -addTask({ - - // 相关参数 - ... -}) -.then(res => { - +addTask(taskInfo, context).then((res: number) => { + GlobalContext.getContext().setObject('taskListChange', true); // 成功的状态,成功后跳转首页 router.back({ - url: 'pages/MainPage', + url: 'pages/MainPage', params: { - editTask: this.isOpen === this.settingParams.isOpen ? {} : - formatParams({ - ...this.settingParams, - isDone: true, - finValue: this.settingParams?.targetValue, - }), + editTask: this.backIndexParams(), } }) - Logger.info('addTaskFinshed', resasstring); -}) -.catch(res => { - + Logger.info('addTaskFinished', JSON.stringify(res)); +}).catch((error: Error) => { // 失败的状态,失败后弹出提示,并打印错误日志 prompt.showToast({ - message: commonConst.SETTING_FINISH_FAILED_MESSAGE + message: Const.SETTING_FINISH_FAILED_MESSAGE }) - Logger.error('addTaskFailed', res as string); + Logger.error('addTaskFailed', JSON.stringify(error)); }) ``` @@ -635,28 +682,28 @@ addTask({ CustomDialogView引入实例并注册事件: ```typescript -// TaskSettingDialog.ets -targetSettingDialog = new CustomDialogController({ +// TaskDialogView.ets +targetSettingDialog: CustomDialogController = new CustomDialogController({ builder: TargetSettingDialog(), autoCancel: true, alignment: DialogAlignment.Bottom, - offset: { dx: ZERO, dy: MINUS_20 } -}) + offset: { dx: Const.ZERO, dy: Const.MINUS_20 } +}); ... // 注册事件 -this.broadCast.on( - BroadCastType.SHOW_TARGETSETTING_DIALOG, - function () { - self.targetSettingDialog.open(); - }) +this.broadCast.on(BroadCastType.SHOW_TARGET_SETTING_DIALOG, () => { + this.targetSettingDialog.open(); +}) ``` 点击对应的编辑项进行触发: ```typescript +// TaskDetailComponent.ets .onClick(() => { - this.broadCast.emit(BroadCastType.SHOW_TARGETSETTING_DIALOG); + this.broadCast.emit( + BroadCastType.SHOW_TARGET_SETTING_DIALOG); }) ``` @@ -678,17 +725,22 @@ this.broadCast.on( ```typescript // TaskSettingDialog.ets -if ([taskType.getup, taskType.sleepEarly].indexOf(this.settingParams?.taskID) - > commonConst.HAS_NO_INDEX) { +if ([taskType.getup, taskType.sleepEarly].indexOf(this.settingParams?.taskID) > Const.HAS_NO_INDEX) { TimePicker({ - selected: commonConst.DEFAULT_SELECTED_TIME, + selected: new Date(`${new Date().toDateString()} 8:00:00`), }) - ... + .height(Const.THOUSANDTH_800) + .useMilitaryTime(true) + .onChange((value: TimePickerResult) => { + this.currentTime = formatTime(value); + }) } else { - TextPicker({ range: this.settingParams?.taskID === taskType.drinkWater - ? this.drinkRange - : this.appleRange }) - ... + TextPicker({ range: this.settingParams?.taskID === taskType.drinkWater ? this.drinkRange : this.appleRange }) + .width(Const.THOUSANDTH_900,) + .height(Const.THOUSANDTH_800,) + .onChange((value) => { + this.currentValue = value?.split(' ')[0]; + }) } ``` @@ -696,30 +748,35 @@ if ([taskType.getup, taskType.sleepEarly].indexOf(this.settingParams?.taskID) ```typescript // TaskSettingDialog.ets - // 校验规则 compareTime(startTime: string, endTime: string) { - if (returnTimeStamp(this.currentTime) < returnTimeStamp(startTime) - || returnTimeStamp(this.currentTime) > returnTimeStamp(endTime)) { - - // 弹出提示 + if (returnTimeStamp(this.currentTime) < returnTimeStamp(startTime) || + returnTimeStamp(this.currentTime) > returnTimeStamp(endTime)) { prompt.showToast({ - message: commonConst.CHOOSE_TIME_OUT_RANGE + message: Const.CHOOSE_TIME_OUT_RANGE }) return false; } return true; } - // 设置修改项 -if (this.settingParams?.taskID === taskType.sleepEarly) { - if (!this.compareTime(commonConst.SLEEP_EARLY_TIME, commonConst.SLEEP_LATE_TIME)) { +setTargetValue() { + if (this.settingParams?.taskID === taskType.getup) { + if (!this.compareTime(Const.GET_UP_EARLY_TIME, Const.GET_UP_LATE_TIME)) { + return; + } + this.settingParams.targetValue = this.currentTime; return; } - this.settingParams.targetValue = this.currentTime; - return; + if (this.settingParams?.taskID === taskType.sleepEarly) { + if (!this.compareTime(Const.SLEEP_EARLY_TIME, Const.SLEEP_LATE_TIME)) { + return; + } + this.settingParams.targetValue = this.currentTime; + return; + } + this.settingParams.targetValue = this.currentValue; } -this.settingParams.targetValue = this.currentValue; ``` 其余弹窗实现基本类似,这里不再赘述。 @@ -732,9 +789,10 @@ this.settingParams.targetValue = this.currentValue; >后台代理提醒接口需要在module.json5中申请ohos.permission.PUBLISH\_AGENT\_REMINDER权限,代码如下: ```typescript +// module.json5 "requestPermissions": [ { - "name": "ohos.permission.PUBLISH_AGENT_REMINDER" + "name": "ohos.permission.PUBLISH_AGENT_REMINDER" } ] ``` @@ -742,73 +800,151 @@ this.settingParams.targetValue = this.currentValue; 后台代理提醒entry\\src\\main\\ets\\service\\ReminderAgent.ts文件中提供了发布提醒任务、查询提醒任务、删除提醒任务三个接口供任务编辑页面调用,跟随任务提醒的开关增加、更改、删除相关后台代理提醒,代码如下: ```typescript -import reminderAgentManager from'@ohos.reminderAgentManager'; -import Notification from '@ohos.notification'; -import { Logger } from '../utils/log/Logger'; - -// publishReminder -function publishReminder(params) { - if(!params) return; - let timer = fetchData(params); - reminderAgentManager.publishReminder(timer).then((reminderId) => { - Logger.info("reminderAgent", `promise, reminderId: ${reminderId}`); - }).catch((err) => { - Logger.error("reminderAgent", `publishReminder err: ${err}`); - }) +// ReminderAgent.ets +import reminderAgent from '@ohos.reminderAgentManager'; +import notification from '@ohos.notificationManager'; +import preferences from '@ohos.data.preferences'; +import Logger from '../common/utils/Logger'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; +import ReminderInfo from '../viewmodel/ReminderInfo'; +import PublishReminderInfo from '../viewmodel/PublishReminderInfo'; + +// 发布提醒 +function publishReminder(params: PublishReminderInfo, context: Context) { + if (!params) { + Logger.error(Const.REMINDER_AGENT_TAG, 'publishReminder params is empty'); + return; + } + let notifyId: string = params.notificationId.toString(); + hasPreferencesValue(context, notifyId, (preferences: preferences.Preferences, hasValue: boolean) => { + if (hasValue) { + preferences.get(notifyId, -1, (error: Error, value: preferences.ValueType) => { + if (typeof value !== 'number') { + return; + } + if (value >= 0) { + reminderAgent.cancelReminder(value).then(() => { + processReminderData(params, preferences, notifyId); + }).catch((err: Error) => { + Logger.error(Const.REMINDER_AGENT_TAG, `cancelReminder err: ${err}`); + }); + } else { + Logger.error(Const.REMINDER_AGENT_TAG, 'preferences get value error ' + JSON.stringify(error)); + } + }); + } else { + processReminderData(params, preferences, notifyId); + } + }); } -// cancelReminder -function cancelReminder(reminderId) { - if(!reminderId) return; - reminderAgentManager.cancelReminder(reminderId).then((data) => { - Logger.info("reminderAgent", `cancelReminder promise: ${data}`); - }).catch((err) => { - Logger.error("reminderAgent", `cancelReminder err: ${err}`); - }) +// 取消提醒 +function cancelReminder(reminderId: number, context: Context) { + if (!reminderId) { + Logger.error(Const.REMINDER_AGENT_TAG, 'cancelReminder reminderId is empty'); + return; + } + let reminder: string = reminderId.toString(); + hasPreferencesValue(context, reminder, (preferences: preferences.Preferences, hasValue: boolean) => { + if (!hasValue) { + Logger.error(Const.REMINDER_AGENT_TAG, 'cancelReminder preferences value is empty'); + return; + } + getPreferencesValue(preferences, reminder); + }); } -// fetchData -function fetchData(params): reminderAgentManager.ReminderRequestAlarm { - return { - reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_ALARM, - hour: params.hour || 0, - minute: params.minute || 0, - daysOfWeek: params.daysOfWeek || [], - wantAgent: { - pkgName: "com.example.exercisehealth", - abilityName: "MainAbility" - }, - title: params.title || '', - content: params.content || '', - notificationId: params.notificationId || -1, - slotType: Notification.SlotType.SOCIAL_COMMUNICATION +// 可通知ID +function hasNotificationId(params: number) { + if (!params) { + Logger.error(Const.REMINDER_AGENT_TAG, 'hasNotificationId params is undefined'); + return; + } + return reminderAgent.getValidReminders().then((reminders) => { + if (!reminders.length) { + return false; + } + let notificationIdList: Array = []; + for (let i = 0; i < reminders.length; i++) { + let notificationId = reminders[i].notificationId; + if (notificationId) { + notificationIdList.push(notificationId); + } } + const flag = notificationIdList.indexOf(params); + return flag === -1 ? false : true; + }); } -// hasNotificationId -async function hasNotificationId(params: number) { - if(!params) return; - await reminderAgentManager.getValidReminders().then((reminders) => { - if (!reminders.length) { - return false; - } - let notificationIdList = []; - for (let i = 0; i < reminders.length; i++) { - notificationIdList.push(reminders[i].notificationId) - } - const flag = notificationIdList.indexOf(params); +function hasPreferencesValue(context: Context, hasKey: string, callback: Function) { + let preferencesPromise = preferences.getPreferences(context, Const.H_STORE); + preferencesPromise.then((preferences: preferences.Preferences) => { + preferences.has(hasKey).then((hasValue: boolean) => { + callback(preferences, hasValue); + }); + }); +} - return flag === -1 ? false : true; - }) +// 进程提醒数据 +function processReminderData(params: PublishReminderInfo, preferences: preferences.Preferences, notifyId: string) { + let timer = fetchData(params); + reminderAgent.publishReminder(timer).then((reminderId: number) => { + putPreferencesValue(preferences, notifyId, reminderId); + }).catch((err: Error) => { + Logger.error(Const.REMINDER_AGENT_TAG, `publishReminder err: ${err}`); + }); } -const reminder = { - publishReminder, - cancelReminder, - hasNotificationId +// 获取数据 +function fetchData(params: PublishReminderInfo): reminderAgent.ReminderRequestAlarm { + return { + reminderType: reminderAgent.ReminderType.REMINDER_TYPE_ALARM, + hour: params.hour || 0, + minute: params.minute || 0, + daysOfWeek: params.daysOfWeek || [], + wantAgent: { + pkgName: Const.PACKAGE_NAME, + abilityName: Const.ENTRY_ABILITY + }, + title: params.title || '', + content: params.content || '', + notificationId: params.notificationId || -1, + slotType: notification.SlotType.SOCIAL_COMMUNICATION + } } -export default reminder +function putPreferencesValue(preferences: preferences.Preferences, putKey: string, putValue: number) { + preferences.put(putKey, putValue).then(() => { + preferences.flush(); + }).catch((error: Error) => { + Logger.error(Const.REMINDER_AGENT_TAG, 'preferences put value error ' + JSON.stringify(error)); + }); +} + +function getPreferencesValue(preferences: preferences.Preferences, getKey: string) { + preferences.get(getKey, -1).then((value: preferences.ValueType) => { + if (typeof value !== 'number') { + return; + } + if (value >= 0) { + reminderAgent.cancelReminder(value).then(() => { + Logger.info(Const.REMINDER_AGENT_TAG, 'cancelReminder promise success'); + }).catch((err: Error) => { + Logger.error(Const.REMINDER_AGENT_TAG, `cancelReminder err: ${err}`); + }); + } + }).catch((error: Error) => { + Logger.error(Const.REMINDER_AGENT_TAG, 'preferences get value error ' + JSON.stringify(error)); + }); +} + +const reminder = { + publishReminder: publishReminder, + cancelReminder: cancelReminder, + hasNotificationId: hasNotificationId +} as ReminderInfo + +export default reminder; ``` ## 实现打卡功能 @@ -822,17 +958,16 @@ export default reminder 使用List组件展示用户当前已经开启的任务,每条任务对应一个TaskCard组件,clickAction包装了点击和长按事件,用户点击任务卡时会触发弹起打卡弹窗,从而进行打卡操作;长按任务卡时会跳转至任务编辑界面,对相应的任务进行编辑处理。代码如下: ```typescript +// HomeComponent.ets // 任务列表 -List({ space: commonConstants.LIST_SPACE }) { - ForEach(this.homeStore.getTaskListOfDay(), (item: TaskInfo) => { - ListItem() { - TaskCard({ - taskInfoStr: JSON.stringify(item), - clickAction: (isClick) => this.taskItemAction(item, isClick) - }) - } - }, item => JSON.stringify(item)) -} +ForEach(this.homeStore.getTaskListOfDay(), (item: TaskInfo) => { + TaskCard({ + taskInfoStr: JSON.stringify(item), + clickAction: (isClick: boolean) => this.taskItemAction(item, isClick) + }) + .margin({ bottom: Const.DEFAULT_12 }) + .height($r('app.float.default_64')) +}, (item: TaskInfo) => JSON.stringify(item)) ... CustomDialogView() // 自定义弹窗中间件 ``` @@ -842,29 +977,59 @@ CustomDialogView() // 自定义弹窗中间件 在组件CustomDialogView的aboutToAppear生命周期中注册SHOW\_TASK\_DETAIL\_DIALOG的事件回调方法 ,当通过emit触发此事件时即触发回调方法执行。代码如下: ```typescript +// CustomDialogView.ets +export class CustomDialogCallback { + confirmCallback: Function = () => {}; + cancelCallback: Function = () => {}; +} + @Component export struct CustomDialogView { + @State isShow: boolean = false; + @Provide achievementLevel: number = 0; @Consume broadCast: BroadCast; @Provide currentTask: TaskInfo = TaskItem; - @Provide dialogCallBack: CustomDialogCallback = { confirmCallback: null, cancelCallback: null }; - // 任务打卡弹窗 - taskDialog = new CustomDialogController({ + @Provide dialogCallBack: CustomDialogCallback = new CustomDialogCallback(); + + // 成就对话框 + achievementDialog: CustomDialogController = new CustomDialogController({ + builder: AchievementDialog(), + autoCancel: true, + customStyle: true + }); + + // 任务时钟对话框 + taskDialog: CustomDialogController = new CustomDialogController({ builder: TaskDetailDialog(), autoCancel: true, customStyle: true - }) + }); + aboutToAppear() { - Logger.debug('CustomDialogView', 'aboutToAppear') - let self = this; - // 任务打卡弹窗 注册 “SHOW_TASK_DETAIL_DIALOG” 事件回调 - this.broadCast.on(BroadCastType.SHOW_TASK_DETAIL_DIALOG, function (currentTask: TaskInfo, dialogCallBack: CustomDialogCallback) { - Logger.debug('CustomDialogView', 'SHOW_TASK_DETAIL_DIALOG') - self.currentTask = currentTask; // 接收当前任务参数 以Provide Consume 方式向子组件透传 - self.dialogCallBack = dialogCallBack; // 接收当前任务确认打卡回调 以Provide Consume 方式向子组件透传 - self.taskDialog.open(); // 弹出打卡弹窗 - }) + Logger.debug('CustomDialogView', 'aboutToAppear'); + // 成就对话框 + this.broadCast.on(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, (achievementLevel: number) => { + Logger.debug('CustomDialogView', 'SHOW_ACHIEVEMENT_DIALOG'); + this.achievementLevel = achievementLevel; + this.achievementDialog.open(); + }); + + // 任务时钟对话框 + this.broadCast.on(BroadCastType.SHOW_TASK_DETAIL_DIALOG, + (currentTask: TaskInfo, dialogCallBack: CustomDialogCallback) => { + Logger.debug('CustomDialogView', 'SHOW_TASK_DETAIL_DIALOG'); + this.currentTask = currentTask || TaskItem; + this.dialogCallBack = dialogCallBack; + this.taskDialog.open(); + }); + } + + aboutToDisappear() { + Logger.debug('CustomDialogView', 'aboutToDisappear'); + } + + build() { } - ... } ``` @@ -873,14 +1038,18 @@ export struct CustomDialogView { 点击任务卡片会emit触发 “SHOW\_TASK\_DETAIL\_DIALOG” 事件,同时把当前任务,以及确认打卡回调方法传递下去。代码如下: ```typescript +// HomeComponent.ets // 任务卡片事件 -taskItemAction(item: TaskInfo, isClick: boolean) { +taskItemAction(item: TaskInfo, isClick: boolean): void { ... if (isClick) { // 点击任务打卡 - let callback: CustomDialogCallback = { confirmCallback: this.onConfirm.bind(this), cancelCallback: null }; + let callback: CustomDialogCallback = { confirmCallback: (taskTemp: TaskInfo) => { + this.onConfirm(taskTemp) + }, cancelCallback: () => { + } }; // 触发弹出打卡弹窗事件 并透传当前任务参数(item) 以及确认打卡回调 - this.broadCast.emit(BroadCastType.SHOW_TASK_DETAIL_DIALOG, [item, callback]); + this.broadCast.emit(BroadCastType.SHOW_TASK_DETAIL_DIALOG, [item, callback]); } else { // 长按编辑任务 ... @@ -888,11 +1057,16 @@ taskItemAction(item: TaskInfo, isClick: boolean) { } // 确认打卡 onConfirm(task) { - this.homeStore.taskClock(task).then((res) => { + this.homeStore.taskClock(task).then((res: AchievementInfo) => { // 打卡成功后 根据连续打卡情况判断是否 弹出成就勋章 以及成就勋章级别 if (res.showAchievement) { // 触发弹出成就勋章SHOW_ACHIEVEMENT_DIALOG 事件, 并透传勋章类型级别 - this.broadCast.emit(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, [res.achievementLevel]); + let achievementLevel = res.achievementLevel; + if (achievementLevel) { + this.broadCast.emit(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, achievementLevel); + } else { + this.broadCast.emit(BroadCastType.SHOW_ACHIEVEMENT_DIALOG); + } } }) } @@ -905,15 +1079,16 @@ onConfirm(task) { 打卡弹窗组件由两个小组件构成,代码如下: ```typescript +// TaskDetailDialog.ets Column() { // 展示任务的基本信息 TaskBaseInfo({ - taskName: TaskMapById[this.currentTask?.taskID].taskName, // 根据当前任务ID获取任务名称 + taskName: TaskMapById[this.currentTask?.taskID - 1].taskName // 根据当前任务ID获取任务名称 }); // 打卡功能组件 (任务打卡、关闭弹窗) TaskClock({ confirm: () => { - this.dialogCallBack.confirmCallback(this.currentTask); // 任务打卡确认回调执行 + this.dialogCallBack.confirmCallback(this.currentTask); this.controller.close(); }, cancel: () => { @@ -928,43 +1103,58 @@ Column() { TaskBaseInfo组件代码如下: ```typescript +// TaskDetailDialog.ets @Component struct TaskBaseInfo { - taskName: string | Resource; + taskName: string | Resource = ''; + build() { - Column({ space: DEFAULT_8 }) { + Column({ space: Const.DEFAULT_8 }) { Text(this.taskName) - ... + .fontSize($r('app.float.default_22')) + .fontWeight(FontWeight.Bold) + .fontFamily($r('app.string.HarmonyHeiTi_Bold')) + .taskTextStyle() + .margin({left: $r('app.float.default_12')}) } - ... + .position({ y: $r('app.float.default_267') }) } } - ``` TaskClock组件代码如下: ```typescript +// TaskDetailDialog.ets @Component struct TaskClock { - confirm: () => void; - cancel: () => void; + confirm: Function = () => {}; + cancel: Function = () => {}; showButton: boolean = false; + build() { - Column({ space: DEFAULT_12 }) { + Column({ space: Const.DEFAULT_12 }) { Button() { - Text($r('app.string.clock_in')) // 打卡 - ... + Text($r('app.string.clock_in')) + .height($r('app.float.default_42')) + .fontSize($r('app.float.default_20')) + .fontWeight(FontWeight.Normal) + .textStyle() } - ... + .width($r('app.float.default_220')) + .borderRadius($r('app.float.default_24')) + .backgroundColor('rgba(255,255,255,0.40)') .onClick(() => { - this.confirm(); + GlobalContext.getContext().setObject('taskListChange', true); + this.confirm(); }) .visibility(!this.showButton ? Visibility.None : Visibility.Visible) - Text($r('app.string.got_it')) // 知道了 - ... + Text($r('app.string.got_it')) + .fontSize($r('app.float.default_14')) + .fontWeight(FontWeight.Regular) + .textStyle() .onClick(() => { - this.cancel(); + this.cancel(); }) } } @@ -974,56 +1164,63 @@ struct TaskClock { ### 打卡接口调用 ```typescript +// HomeViewModel.ets public async taskClock(taskInfo: TaskInfo) { let taskItem = await this.updateTask(taskInfo); - // 更新任务失败 + let dateStr = this.selectedDayInfo?.dateStr; + // 更新任务失败 if (!taskItem) { - return Promise.resolve({ + return { achievementLevel: 0, showAchievement: false - }); + } as AchievementInfo; } // 更新当前时间的任务列表 - this.selectedDayInfo.taskList = this.selectedDayInfo.taskList.map((item) => item.taskID == taskItem?.taskID ? taskItem : item); - let achievementLevel; + this.selectedDayInfo.taskList = this.selectedDayInfo.taskList.map((item) => { + return item.taskID === taskItem?.taskID ? taskItem : item; + }); + let achievementLevel: number = 0; if(taskItem.isDone) { // 更新每日任务完成情况数据 let dayInfo = await this.updateDayInfo(); - ... - if(dayInfo) { - // 当日任务完成数量等于总任务数量时 累计连续打卡一天 - if (dayInfo.finTaskNum === dayInfo?.targetTaskNum) { - // 更新成就勋章数据 判断是否弹出获得勋章弹出及勋章类型 - achievementLevel = await this.updateAchievement(this.selectedDayInfo.dayInfo); - } + ... + // 当日任务完成数量等于总任务数量时 累计连续打卡一天 + // 更新成就勋章数据 判断是否弹出获得勋章弹出及勋章类型 + if (dayInfo && dayInfo?.finTaskNum === dayInfo?.targetTaskNum) { + achievementLevel = await this.updateAchievement(this.selectedDayInfo.dayInfo); } } ... - return Promise.resolve({ + return { achievementLevel: achievementLevel, showAchievement: ACHIEVEMENT_LEVEL_LIST.includes(achievementLevel) - }); + } as AchievementInfo; } ``` ```typescript +// HomeViewModel.ets // 更新当天任务列表 updateTask(task: TaskInfo): Promise { return new Promise((resolve, reject) => { - let {taskID, targetValue, finValue} = task; - let updateTask = Object.assign({}, task); - let step = TaskMapById[taskID].step; // 任务步长 + let taskID = task.taskID; + let targetValue = task.targetValue; + let finValue = task.finValue; + let updateTask = new TaskInfo(task.id, task.date, taskID, targetValue, task.isAlarm, task.startTime, + task.endTime, task.frequency, task.isDone, finValue, task.isOpen); + let step = TaskMapById[taskID - 1].step; // 任务步长 + let hasExceed = updateTask.isDone; if (step === 0) { // 任务步长为0 打卡一次即完成该任务 updateTask.isDone = true; // 打卡一次即完成该任务 updateTask.finValue = targetValue; } else { let value = Number(finValue) + step; // 任务步长非0 打卡一次 步长与上次打卡进度累加 - updateTask.isDone = value >= Number(targetValue); // 判断任务是否完成 + updateTask.isDone = updateTask.isDone || value >= Number(targetValue); // 判断任务是否完成 updateTask.finValue = updateTask.isDone ? targetValue : `${value}`; } - TaskInfoTableApi.updateDataByDate(updateTask, (res) => { // 更新数据库 - if (!res) { - Logger.error('taskClock-updateTask', res); + TaskInfoTableApi.updateDataByDate(updateTask, (res: number) => { // 更新数据库 + if (!res || hasExceed) { + Logger.error('taskClock-updateTask', JSON.stringify(res)); reject(res); } resolve(updateTask); @@ -1038,7 +1235,7 @@ updateTask(task: TaskInfo): Promise { ### 功能概述 -成就页面展示用户可以获取的所有勋章,当用户满足一定的条件时,将点亮本页面对应的勋章,没有得到的成就勋章处于熄灭状态。共有六种勋章,当用户连续完成任务打卡3天、7天、30天、50天、73天、99天时,可以获得对应的 "连续xx天达成" 勋章。 +成就页面展示用户可以获取的所有勋章,当用户满足一定的条件时,将点亮本页面对应的勋章,没有得到的成就勋章处于熄灭状态。共有六种勋章,当用户连续完成任务打卡3天、7天、30天、50天、73天、99天时,可以获得对应的“连续xx天达成”勋章。 ### 页面布局与 ArkTS 代码对应关系 @@ -1054,28 +1251,39 @@ updateTask(task: TaskInfo): Promise { export struct TitleBar { build() { Row() { - Text($r('app.string.achievement')) - ... // 省略属性设置 - }.width(commonConst.FULL_WIDTH) + Text($r('app.string.achievement')) + .fontSize($r('app.float.default_24')) + .fontColor($r('app.color.white')) + .align(Alignment.Start) + .padding({left: Const.ACHIEVE_TITLE_BAR_LEFT,top: Const.ACHIEVE_TITLE_BAR_TOP}) + } + .width(Const.FULL_WIDTH) } } ``` -每个勋章卡片BadgeCard是一个竖向容器Column一个图片子组件Image和一个文字子组件Text。 +每个勋章卡片BadgeCard是由一个竖向容器Column、一个图片子组件Image和一个文字子组件Text组成。 ```typescript -// BadegeCardComponent.ets +// BadgeCardComponent.ets @Component export struct BadgeCard { - @Prop content: string; - @Prop imgSrc: string; - build() { - Column({space: commonConst.DEFAULT_18}) { - Image($rawfile(this.imgSrc)) - ... // 省略属性设置 - Text($r('app.string.task_achievement_level', Number(this.content))) - ... // 省略属性设置 + @Prop content: string = ''; + imgSrc: Resource = $r('app.string.empty'); + + build() { + Column({space: Const.DEFAULT_18}) { + Image(this.imgSrc) + .width(Const.FULL_WIDTH) + .height(Const.ACHIEVE_CARD_IMG_HEIGHT) + .objectFit(ImageFit.Contain) + Text($r('app.string.task_achievement_level', Number(this.content))) + .lineHeight($r('app.float.default_16')) + .fontSize($r('app.float.default_12')) + .fontColor($r('app.color.white')) } + .width(ratio2percent(Const.ACHIEVE_SPLIT_RATIO)) + .padding({top: Const.ACHIEVE_CARD_TOP, bottom: Const.ACHIEVE_CARD_BOTTOM}) } } ``` @@ -1087,15 +1295,19 @@ export struct BadgeCard { @Component export struct BadgePanel { @StorageProp(ACHIEVEMENT_LEVEL_KEY) successiveDays: number = 0; + aboutToAppear() { + Logger.debug('BadgePanel','aboutToAppear'); getAchievementLevel(); - } - build() { - Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) { - ForEach(getBadgeCards(this.successiveDays), (item) => { - BadgeCard({ content: item[0], imgSrc: item[1]}) - }) - }.width(commonConst.FULL_WIDTH) + } + +build() { + Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) { + ForEach(getBadgeCardItems(this.successiveDays), (item: CardInfo) => { + BadgeCard({ content: item.titleContent, imgSrc: item.achievement}) + }) + } + .width(Const.FULL_WIDTH) } } ``` @@ -1107,40 +1319,46 @@ export struct BadgePanel { ```typescript // BadgePanelComponent.ets aboutToAppear() { + Logger.debug('BadgePanel','aboutToAppear'); getAchievementLevel(); -} +} // AchieveModel.ets export function getAchievementLevel() { - let globalInfoTable: GlobalInfoTable = new GlobalInfoTable(); - globalInfoTable.query((res) => { - ... // 省略数据验证 + GlobalInfoApi.query((res: GlobalInfo) => { + let globalInfo: GlobalInfo = res; + let achievementStr = globalInfo.achievements??''; + let achievements = achievementStr.split(','); if (achievements.length > 0) { AppStorage.Set(ACHIEVEMENT_LEVEL_KEY, Number(achievements[achievements.length - 1])); } - } + }) } // BadgePanelComponent.ets @StorageProp(ACHIEVEMENT_LEVEL_KEY) successiveDays: number = 0; -ForEach(getBadgeCards(this.successiveDays), (item) => { - BadgeCard({ content: item[0], imgSrc: item[1]}) +ForEach(getBadgeCardItems(this.successiveDays), (item: CardInfo) => { + BadgeCard({ content: item.titleContent, imgSrc: item.achievement}) }) // AchievementViewModel.ets -export function getBadgeCardsItems(successiveDays: number):[string, string][] { +export function getBadgeCardItems(successiveDays: number): Array { let badgeMileStones = ACHIEVEMENT_LEVEL_LIST; - let cardItems:[string, string][] = []; - for (let i = 0; i < badgeMileStones.length; i++) { - ... // 省略数据拼装细节 - cardItems.push(oneItem); - } + let cardItems: Array = []; + for (let i = 0; i < badgeMileStones.length; i++) { + let onOrOff = successiveDays >= badgeMileStones[i] ? 'on' : 'off'; + let titleContent = String(badgeMileStones[i]); + let cardInfo: CardInfo = new CardInfo(); + cardInfo.titleContent = titleContent; + cardInfo.achievement = getAchievement(`${ onOrOff }_${ badgeMileStones[i] }`); + cardItems.push(cardInfo); + } return cardItems; } ``` -## 搭建关系数据库 +## 搭建关系型数据库 本节将介绍如何调用关系型数据库接口在本地搭建数据库,并读写相应的用户数据。 @@ -1151,12 +1369,12 @@ export function getBadgeCardsItems(successiveDays: number):[string, string][] { 导入关系型数据库模块: ```typescript -import dataRdb from '@ohos.data.relationalStore'; +import data_rdb from '@ohos.data.rdb'; ``` 关系型数据库提供以下两个基本功能: -![](figures/1.png) +![](figures/zh-cn_image_0000001459867377.png) #### 获取RdbStore @@ -1164,17 +1382,15 @@ import dataRdb from '@ohos.data.relationalStore'; ```typescript // RdbHelperImp.ets -getRdb(context: any): Promise { - Logger.info(`initRdb getRdb success`); +getRdb(context: Context): Promise { this.storeConfig = { - // 配置数据库文件名、安全级别 name: this.mDatabaseName, securityLevel: dataRdb.SecurityLevel.S1 }; return new Promise((success, error) => { dataRdb.getRdbStore(context, this.storeConfig).then(dbStore => { - this.rdbStore = dbStore; // 获取RdbStore + this.rdbStore = dbStore; success(this); - }).catch(err => { + }).catch((err: Error) => { Logger.error(`initRdb err : ${JSON.stringify(err)}`); error(err); }) @@ -1189,30 +1405,32 @@ getRdb(context: any): Promise { ```typescript // RdbHelperImp.ets insert(tableName: string, values: dataRdb.ValuesBucket | Array): Promise { - return new Promise((success, error) => { + return new Promise((success, error) => { Logger.info(`insert tableName : ${tableName}, values : ${JSON.stringify(values)}`); - ... - if (Array.isArray(values)) { - // 如果插入一组数据,则批量插入 + if (!values) { + Logger.info(`insert failed, values is undefined`); + error(0); + return; + } + if (values instanceof Array) { Logger.info(`insert values isArray = ${values.length}`); this.rdbStore.beginTransaction(); this.saveArray(tableName, values).then(data => { Logger.info(`insert success, data : ${JSON.stringify(data)}`); success(data); this.rdbStore.commit(); - }).catch(err => { + }).catch((err: Error) => { Logger.error(`insert failed, err : ${err}`); error(err); this.rdbStore.commit(); }) } else { this.rdbStore.insert(tableName, values).then(data => { - // 调用insert()接口插入数据 Logger.info(`insert success id : ${data}`); success(data); - this.rdbStore.commit(); - }).catch(err => { - Logger.error(`insert failed, err : ${err}`); + his.rdbStore.commit(); + }).catch((err: Error) => { + Logger.error(`insert failed, err : ${JSON.stringify(err)}`); error(err); this.rdbStore.commit(); }) @@ -1252,7 +1470,7 @@ query(rdbPredicates: dataRdb.RdbPredicates, columns?: Array): Promise): Promise { @@ -1316,30 +1534,47 @@ insertData(taskInfo: TaskInfo, callback) { ```typescript // TaskInfoApi.ets -function generateBucket(taskInfo: TaskInfo) { - let obj = {}; - TASK_INFO.columns.forEach((item) => { - obj[item] = taskInfo[item]; +function generateBucket(taskInfo: TaskInfo): dataRdb.ValuesBucket { + let valueBucket = {} as dataRdb.ValuesBucket; + Const.TASK_INFO.columns?.forEach((item: string) => { + if (item !== 'id') { + switch (item) { + case 'date': + valueBucket[item] = taskInfo.date; + break; + case 'taskID': + valueBucket[item] = taskInfo.taskID; + break; + case 'targetValue': + valueBucket[item] = taskInfo.targetValue; + break; + case 'isAlarm': + valueBucket[item] = taskInfo.isAlarm; + break; + case 'startTime': + valueBucket[item] = taskInfo.startTime; + break; + case 'endTime': + valueBucket[item] = taskInfo.endTime; + break; + case 'frequency': + valueBucket[item] = taskInfo.frequency; + break; + case 'isDone': + valueBucket[item] = taskInfo.isDone; + break; + case 'finValue': + valueBucket[item] = taskInfo.finValue; + break; + case 'isOpen': + valueBucket[item] = taskInfo.isOpen; + break; + default: + break; + } + } }); - return obj; -} - -// CommonConstants.ets -export const TASK_INFO = { - tableName: 'taskInfo', - columns: [ - 'id', - 'date', - 'taskID', - 'targetValue', - 'isAlarm', - 'startTime', - 'endTime', - 'frequency', - 'isDone', - 'finValue', - 'isOpen' - ] + return valueBucket; } ``` @@ -1347,13 +1582,16 @@ export const TASK_INFO = { ```typescript // TaskInfoApi.ets -updateDataByDate(taskInfo: TaskInfo, callback) { +updateDataByDate(taskInfo: TaskInfo, callback: Function): void { const valueBucket = generateBucket(taskInfo); - let predicates = new dataRdb.RdbPredicates(TASK_INFO.tableName); - + let tableName = Const.TASK_INFO.tableName; + if (!tableName) { + return; + } + let predicates = new dataRdb.RdbPredicates(tableName); // 根据date和taskID匹配要更新的数据行 predicates.equalTo('date', taskInfo.date).and().equalTo('taskID', taskInfo.taskID); - RdbUtils.update(valueBucket, predicates).then(result => { + RdbUtils.update(valueBucket, predicates).then((result: number) => { callback(result); }); Logger.info('TaskInfoTable', `Update data {${taskInfo.date}:${taskInfo.taskID}} finished.`); @@ -1364,35 +1602,46 @@ updateDataByDate(taskInfo: TaskInfo, callback) { ```typescript // TaskInfoApi.ets -query(date: string, isOpen: boolean = true, callback) { - let predicates = new dataRdb.RdbPredicates(TASK_INFO.tableName); +query(date: string, isOpen: boolean = true, callback: Function): void { + let tableName = Const.TASK_INFO.tableName; + if (!tableName) { + return; + } + let predicates = new dataRdb.RdbPredicates(tableName); predicates.equalTo('date', date); - - // 如果isOpen为true,则只查找开启的任务 + // 如果isOpen为true,则只查找开启的任务 if (isOpen) { predicates.equalTo('isOpen', true); } predicates.orderByAsc('taskID'); // 查找结果按taskID排序 - RdbUtils.query(predicates, function(resultSet) { + RdbUtils.query(predicates).then(resultSet => { let count = resultSet.rowCount; - // 查找结果为空则返回空数组,否则返回查找结果数组 if (count === 0 || typeof count === 'string') { - Logger.info('TaskInfoTable', `${date} query no results!`); - callback([]); + Logger.error('TaskInfoTable', `${date} query no results!`); + const result: TaskInfo[] = []; + callback(result); } else { resultSet.goToFirstRow(); - const result = []; + const result: TaskInfo[] = []; for (let i = 0; i < count; i++) { let tmp = new TaskInfo(0, '', 0, '', false, '', '', '', false, ''); + tmp.isOpen = resultSet.getDouble(resultSet.getColumnIndex('isOpen')) ? true : false; tmp.id = resultSet.getDouble(resultSet.getColumnIndex('id')); - ... // 省略赋值代码 + tmp.date = resultSet.getString(resultSet.getColumnIndex('date')); + tmp.taskID = resultSet.getDouble(resultSet.getColumnIndex('taskID')); + tmp.targetValue = resultSet.getString(resultSet.getColumnIndex('targetValue')); + tmp.isAlarm = resultSet.getDouble(resultSet.getColumnIndex('isAlarm')) ? true : false; + tmp.startTime = resultSet.getString(resultSet.getColumnIndex('startTime')); + tmp.endTime = resultSet.getString(resultSet.getColumnIndex('endTime')); + tmp.frequency = resultSet.getString(resultSet.getColumnIndex('frequency')); + tmp.isDone = resultSet.getDouble(resultSet.getColumnIndex('isDone')) ? true : false; + tmp.finValue = resultSet.getString(resultSet.getColumnIndex('finValue')); result[i] = tmp; resultSet.goToNextRow(); } callback(result); } - return; }); } ``` @@ -1415,27 +1664,28 @@ CREATE TABLE IF NOT EXISTS dayInfo( ```typescript // DayInfoApi.ets -queryList(dates: string[], callback) { - let predicates = new dataRdb.RdbPredicates(DAY_INFO.tableName); +queryList(dates: string[], callback: Function): void { + let predicates: dataRdb.RdbPredicates = new dataRdb.RdbPredicates(Const.DAY_INFO.tableName ? Const.DAY_INFO.tableName : ''); predicates.in('date', dates); // 匹配日期数组内的所有日期 - RdbUtils.query(predicates, function(resultSet) { + RdbUtils.query(predicates).then(resultSet => { let count = resultSet.rowCount; if (count === 0) { - Logger.info('DayInfoTable','query no results.'); - callback([]); + Logger.info('DayInfoTable', 'query no results.'); + let result: DayInfo[] = []; + callback(result); } else { resultSet.goToFirstRow(); - let result = []; + let result: DayInfo[] = []; for (let i = 0; i < count; i++) { let tmp = new DayInfo('', 0, 0); tmp.date = resultSet.getString(resultSet.getColumnIndex('date')); - ... // 省略赋值代码 + tmp.targetTaskNum = resultSet.getDouble(resultSet.getColumnIndex('targetTaskNum')); + tmp.finTaskNum = resultSet.getDouble(resultSet.getColumnIndex('finTaskNum')); result[i] = tmp; resultSet.goToNextRow(); } callback(result); } - return; }); } ``` @@ -1461,57 +1711,57 @@ CREATE TABLE IF NOT EXISTS globalInfo( ```typescript // DatabaseModel.ets -query(date: string, callback) { - let result = []; +query(date: string, callback: Function) { + let result: TaskInfo[] = []; let self = this; - GlobalInfoApi.query(function(globalResult) { - // 如果查不到全局信息,就写入全局信息 - if (globalResult.length === 0) { - ... // 插入健康任务信息、每日信息和全局信息 + GlobalInfoApi.query((globalResult: GlobalInfo) => { + if (!globalResult.firstDate) { // 如果找不到全局信息,则写入 + let globalInfo: GlobalInfo = new GlobalInfo(date, date, 0, ''); + GlobalInfoApi.insertData(globalInfo, (isDone: number) => { + if (isDone) { + Logger.info('AppStart', 'Insert globalInfo success: ' + JSON.stringify(globalInfo)); + } + }); + self.insertGlobalTask(); + let dayInfo: DayInfo = new DayInfo(date, 0, 0); + DayInfoApi.insertData(dayInfo, (isDone: number) => { + if (isDone) { + Logger.info('AppStart', 'Insert dayInfo success: ' + JSON.stringify(dayInfo)); + } + }) + self.insertTask(date); callback(result, dayInfo); - } else { - // 如果查到全局信息,那么查询当日任务信息 + } else { // 如果找到全局信息,则查询当天的任务信息 let newGlobalInfo = globalResult; let preDate = globalResult.lastDate; newGlobalInfo.lastDate = date; - ... // 更新全局信息 - - // 查询当日任务信息 - TaskInfoApi.query(date, false, (taskResult) => { - let dayInfo = new DayInfo(date, 0, 0); - // 如果查不到当日任务信息,就查询全局任务信息 - if (taskResult.length === 0) { - ... - TaskInfoApi.query(GLOBAL_KEY, false, (globalTaskResult) => { - ... // 回写没打开应用的时间段的健康任务信息和每日信息 - }) - } else { - // 计算当日健康任务的开启个数和完成数 - let dayInfoList = self.calFinishNum(taskResult, result); - dayInfo.targetTaskNum = dayInfoList[0]; - dayInfo.finTaskNum = dayInfoList[1]; - callback(result, dayInfo); + GlobalInfoApi.updateData(newGlobalInfo, (isDone: number) => { + if (isDone) { + Logger.info('AppStart', 'update globalInfo success: ' + JSON.stringify(newGlobalInfo)); } }); + self.queryPreInfo(date, preDate, result, callback); } }); } ``` -## 通用工具类 +## 编写通用工具类 本节将介绍日志打印、时间换算等通用工具类的编写和使用,工具类可以简化应用代码编写和业务流程处理。 ### 日志类 -日志类Logger旨在提供一个全局的日志打印、日志管理的地方,既可以规范整个应用的日志打印,也方便日后对日志工具类进行修改,而不需要去改动代码中每一个调用日志的地方,目前分info,debug,warn,error四个级别。 +日志类Logger旨在提供一个全局的日志打印、日志管理的地方,既可以规范整个应用的日志打印,也方便日后对日志工具类进行修改,而不需要去改动代码中每一个调用日志的地方,如切换具体的日志实现类(比如不使用Console而是HiLog),将日志记录到本地文件等。 + +Logger对外的日志API全部使用静态方法,方便调用者使用,目前分verbose,debug,info,warn,error五个级别。 使用方法如下: 1. import Logger日志类: ```typescript - import Logger from '../../utils/Logger'; + import { Logger } from '../utils/log/Logger'; ``` 2. 调用对应级别的静态方法: @@ -1520,23 +1770,43 @@ query(date: string, callback) { Logger.debug('MyAbilityStage', 'onCreate'); ``` - Logger目前在打印日志时会拼装本应用的唯一标识,方便筛选日志和调试: +3、Logger类中包括debug、info、warn、error,具体内容如下: - ```typescript - // Logger.ets - class Logger { - private domain: number; - private prefix: string; - - constructor(prefix: string = '', domain: number = 0xFF00) { - this.prefix = prefix; - this.domain = domain; - } - ... - } +```typescript +// Logger.ets +import hilog from '@ohos.hilog'; - export default new Logger(LOGGER_PREFIX, 0xFF02); - ``` +const LOGGER_PREFIX: string = 'Healthy_life'; + +class Logger { + private domain: number; + private prefix: string; + + ... + constructor(prefix: string = '', domain: number = 0xFF00) { + this.prefix = prefix; + this.domain = domain; + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger(LOGGER_PREFIX, 0xFF02); +``` ### 时间工具 @@ -1544,25 +1814,29 @@ query(date: string, callback) { 1. 常用时间相关常量: - ```typescript - const CHINESE_OF_WEEK: string[] = ['一', '二', '三', '四', '五', '六', '日']; - const YEAR: string = '年'; - const MONTH: string = '月'; - const DAY: string = '日'; - const WEEK: string = '星期'; - ``` +```typescript + // Utils.ets + const CHINESE_OF_WEEK: string[] = ['一', '二', '三', '四', '五', '六', '日']; + const YEAR: string = '年'; + const MONTH: string = '月'; + const DAY: string = '日'; + const WEEK: string = '星期'; + DAYS_OF_WEEK: number = 7; + const SUNDAY_FIRST_SHIFT: number = 6; +``` 2. 时间函数示例(由时间常量衍生出星期一到星期日和数字 1-7 的字典映射): - ```typescript - export const oneWeekDictFunc = () => { - const oneWeekDict = {}; - CHINESE_OF_WEEK.forEach((item, index) => { - oneWeekDict[index + 1] = `${ WEEK }${ CHINESE_OF_WEEK[index] }`; - }) - return oneWeekDict; - } - ``` +```typescript +// Utils.ets +export const oneWeekDictFunc = () => { + const oneWeekDict: Array = []; + for (let index = 0;index < CHINESE_OF_WEEK.length; index++) { + oneWeekDict[index] = `${WEEK}${CHINESE_OF_WEEK[index]}`; + } + return oneWeekDict; +} +``` ### 单位转换工具 @@ -1571,8 +1845,9 @@ query(date: string, callback) { 例如成就页面,每一行平均分布三个徽章,可以先定义一个浮点数代表等分比例,再转换为百分比字符串。 ```typescript +// Utils.ets export function ratio2percent(ratio: number): string { - return `${ ratio * 100 }%`; + return `${ratio * 100}%`; } ``` @@ -1587,11 +1862,11 @@ export function ratio2percent(ratio: number): string { 2. 引用工具方法 \( 例如成就页面,每个徽章占据屏幕宽度的三分之一 \) : ```typescript - // 引用工具方法( 例如成就页面,每个徽章占据屏幕宽度的三分之一 ) : - Column({ space: commonConst.DEFAULT_18 }) { + // BadgeCardComponent.ets + Column({space: commonConst.DEFAULT_18}) { ... // 省略徽章卡片的 UI 布局细节 } - .width(ratio2percent(achieveConst.ACHIEVE_SPLIT_RATIO)) + .width(ratio2percent(Const.ACHIEVE_SPLIT_RATIO)) // achieveConst.ACHIEVE_SPLIT_RATIO = 1 / 3 ``` ### 事件分发类 @@ -1603,7 +1878,7 @@ export function ratio2percent(ratio: number): string { 获取事件分发实例: ```typescript -// HomeIndex.ets +// HomeComponent.ets @Provide broadCast: BroadCast = HealthDataSrcMgr.getInstance().getBroadCast(); // HealthDataSrcMgr.ets @@ -1617,84 +1892,126 @@ public getBroadCast(): BroadCast { ```typescript // CustomDialogView.ets aboutToAppear() { - ... - this.broadCast.on(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, function (achievementLevel: number) { - ... // 省略回调细节 - }) - ... + Logger.debug('CustomDialogView', 'aboutToAppear'); + // 成就对话 + this.broadCast.on(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, (achievementLevel: number) => { + Logger.debug('CustomDialogView', 'SHOW_ACHIEVEMENT_DIALOG'); + this.achievementLevel = achievementLevel; + this.achievementDialog.open(); + }); + + // 任务时钟对话框 + this.broadCast.on(BroadCastType.SHOW_TASK_DETAIL_DIALOG, + (currentTask: TaskInfo, dialogCallBack: CustomDialogCallback) => { + Logger.debug('CustomDialogView', 'SHOW_TASK_DETAIL_DIALOG'); + this.currentTask = currentTask || TaskItem; + this.dialogCallBack = dialogCallBack; + this.taskDialog.open(); + }); } // BroadCast.ets -public on(event, callback) { - (this.callBackArray[event] || (this.callBackArray[event] = [])).push(callback); +public on(event: string, callback: Function) { + Logger.info(FILE_TAG, 'register broadcast with type '+ event); + switch (event) { + case BroadCastType.SHOW_ACHIEVEMENT_DIALOG: + this.callBackArray.showAchievementDialog = callback; + break; + case BroadCastType.SHOW_TASK_DETAIL_DIALOG: + this.callBackArray.showTaskDetailDialog = callback; + break; + case BroadCastType.SHOW_TARGET_SETTING_DIALOG: + this.callBackArray.showTargetSettingDialog = callback; + break; + case BroadCastType.SHOW_REMIND_TIME_DIALOG: + this.callBackArray.showRemindTimeDialog = callback; + break; + case BroadCastType.SHOW_FREQUENCY_DIALOG: + this.callBackArray.showFrequencyDialog = callback; + break; + default: + break; + } } ``` 取消事件注册: ```typescript -// HomeIndex.ets -aboutToDisappear() { - this.broadCast.off(null, null); +// TaskDetailComponent.ets +aboutToAppear() { + this.broadCast.off(BroadCastType.SHOW_TARGET_SETTING_DIALOG, () => {}); + this.broadCast.off(BroadCastType.SHOW_REMIND_TIME_DIALOG, () => {}); + this.broadCast.off(BroadCastType.SHOW_FREQUENCY_DIALOG, () => {}); } // BroadCast.ets -public off(event, callback) { - ... // 省略入参检查 - const cbs = this.callBackArray[event]; +public off(event: string, callback: Function) { + if (event === null) { + Logger.info(FILE_TAG, 'cancel all broadcast'); + this.callBackArray = callBackArrayTemp; + } + Logger.info(FILE_TAG, 'cancel broadcast with type '+ event); + const cbs = this.callBackArray; if (!cbs) { return; } - if (!callback) { - this.callBackArray[event] = null; + if (callback === null) { + switch (event) { + case BroadCastType.SHOW_ACHIEVEMENT_DIALOG: + this.callBackArray.showAchievementDialog = () => {}; + break; + case BroadCastType.SHOW_TASK_DETAIL_DIALOG: + this.callBackArray.showTaskDetailDialog = () => {}; + break; + case BroadCastType.SHOW_TARGET_SETTING_DIALOG: + this.callBackArray.showTargetSettingDialog = () => {}; + break; + case BroadCastType.SHOW_REMIND_TIME_DIALOG: + this.callBackArray.showRemindTimeDialog = () => {}; + break; + case BroadCastType.SHOW_FREQUENCY_DIALOG: + this.callBackArray.showFrequencyDialog = () => {}; + break; + default: + break; + } } - cbs.splice(cbs.indexOf(callback), 1); } ``` 发送事件: ```typescript -// HomeIndex.ets -taskItemAction(item: TaskInfo, isClick: boolean) { - ... +// HomeComponent.ets +taskItemAction(item: TaskInfo, isClick: boolean): void { + if (!this.homeStore.checkCurrentDay()) { + return; + } if (isClick) { - // 点击任务打卡 - ... + // 点击时钟 + let callback: CustomDialogCallback = { confirmCallback: (taskTemp: TaskInfo) => { + this.onConfirm(taskTemp) + }, cancelCallback: () => { + } }; this.broadCast.emit(BroadCastType.SHOW_TASK_DETAIL_DIALOG, [item, callback]); - } - else { - ... - } -} - -// BroadCast.ets -public emit(event, args?: any[]) { - ... // 省略入参检查 - let cbs = [...this.callBackArray[event]]; - if (cbs) { - let len = cbs.length; - for (let i = 0; i < len; i++) { - try { - cbs[i].apply(_self, args); - } catch (error) { - new Error(error); - } - } + } else { + // 编辑任务 + let editTaskStr: string = JSON.stringify(TaskMapById[item.taskID - 1]); + let editTask: ITaskItem = JSON.parse(editTaskStr); + editTask.targetValue = item?.targetValue; + editTask.isAlarm = item.isAlarm; + editTask.startTime = item.startTime; + editTask.frequency = item.frequency; + editTask.isOpen = item.isOpen; + router.pushUrl({ url: 'pages/TaskEditPage', params: { params: JSON.stringify(editTask) } }); } } ``` ## 总结 -您已经完成了本次Codelab的学习,并了解到以下知识点: - -1. ArkUI基础组件、容器组件的使用。 -2. 使用页面路由跳转到指定页面并传递所需参数。 -3. 基于基础组件封装自定义组件,如日历、弹窗等。 -4. 数据驱动UI组件刷新。 -5. 使用首选项接口实现应用权限管理。 -6. 使用关系型数据库读写关系型数据。 +通过本次Codelab的学习,您应该已经掌握了页面跳转、自定义弹窗等UI方法,并学会了操作关系型数据库读写数据。 ![](figures/彩带动效.gif) diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/constants/CommonConstants.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/constants/CommonConstants.ets index ac0c0217b6ebef1110202f07eefd209f3f6c2fd6..a8097e8ec8bd5ed594d6a638a75bce19f7d8c55e 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/constants/CommonConstants.ets @@ -12,230 +12,283 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import CommonConstantsInfo from '../../viewmodel/CommonConstantsInfo'; -export const RDB_NAME = { dbname: 'taskInfo.db' }; // db name +export class CommonConstants { + static readonly RDB_NAME = { dbName: 'taskInfo.db' } as CommonConstantsInfo; // db name -/** day info table */ -export const DAY_INFO = { - tableName: 'dayInfo', - columns: ['date', 'targetTaskNum', 'finTaskNum'] -} + /** day info table */ + static readonly DAY_INFO = { + tableName: 'dayInfo', + columns: ['date', 'targetTaskNum', 'finTaskNum'] + } as CommonConstantsInfo -/** global info table */ -export const GLOBAL_INFO = { - tableName: 'globalInfo', - columns: ['id', 'firstDate', 'lastDate', 'checkInDays', 'achievements'] -} + /** global info table */ + static readonly GLOBAL_INFO = { + tableName: 'globalInfo', + columns: ['id', 'firstDate', 'lastDate', 'checkInDays', 'achievements'] + } as CommonConstantsInfo -/** task info table */ -export const TASK_INFO = { - tableName: 'taskInfo', - columns: ['id', 'date', 'taskID', 'targetValue', 'isAlarm', 'startTime', 'endTime', 'frequency', 'isDone', 'finValue', 'isOpen'] -} + /** task info table */ + static readonly TASK_INFO = { + tableName: 'taskInfo', + columns: [ + 'id', + 'date', + 'taskID', + 'targetValue', + 'isAlarm', + 'startTime', + 'endTime', + 'frequency', + 'isDone', + 'finValue', + 'isOpen' + ] + } as CommonConstantsInfo + + /** form info table */ + static readonly FORM_INFO = { + tableName: 'formInfo', + columns: ['id', 'formId', 'formName', 'formDimension'] + } as CommonConstantsInfo + + // TaskNum + static readonly TASK_NUM = 6; + + // THOUSANDTH + static readonly THOUSANDTH_15: string = '1.5%'; // ‘1.5%’ + static readonly THOUSANDTH_12: string = '2.2%'; // ‘2.2%’ + static readonly THOUSANDTH_33: string = '3.3%'; // ‘3.3%’ + static readonly THOUSANDTH_50: string = '5%'; // ‘5%’ + static readonly THOUSANDTH_66: string = '6.6%'; // ‘6.6%’ + static readonly THOUSANDTH_80: string = '8%'; // ‘8%’ + static readonly THOUSANDTH_100: string = '10%'; // ‘10%’ + static readonly THOUSANDTH_120: string = '12%'; // ‘12%’ + static readonly THOUSANDTH_160: string = '16%'; // ‘16%’ + static readonly THOUSANDTH_400: string = '40%'; // ‘40%’ + static readonly THOUSANDTH_420: string = '42%'; // ‘42%’ + static readonly THOUSANDTH_500: string = '50%'; // ‘50%’ + static readonly THOUSANDTH_560: string = '56%'; // ‘56%’ + static readonly THOUSANDTH_800: string = '80%'; // ‘80%’ + static readonly THOUSANDTH_830: string = '83%'; // ‘83%’ + static readonly THOUSANDTH_880: string = '88%'; // ‘88%’ + static readonly THOUSANDTH_900: string = '90%'; // ‘90%’ + static readonly THOUSANDTH_940: string = '94%'; // ‘90%’ + static readonly THOUSANDTH_1000: string = '100%'; // ‘100%’ + + static readonly DEFAULT_2: number = 2; -// TaskNum -export const TASK_NUM = 6; + static readonly DEFAULT_6: number = 6; -// THOUSANDTH -export const THOUSANDTH_15: string = '1.5%'; // ‘1.5%’ -export const THOUSANDTH_12: string = '2.2%'; // ‘2.2%’ -export const THOUSANDTH_33: string = '3.3%'; // ‘3.3%’ -export const THOUSANDTH_50: string = '5%'; // ‘5%’ -export const THOUSANDTH_66: string = '6.6%'; // ‘6.6%’ -export const THOUSANDTH_80: string = '8%'; // ‘8%’ -export const THOUSANDTH_100: string = '10%'; // ‘10%’ -export const THOUSANDTH_120: string = '12%'; // ‘12%’ -export const THOUSANDTH_160: string = '16%'; // ‘16%’ -export const THOUSANDTH_400: string = '40%'; // ‘40%’ -export const THOUSANDTH_420: string = '42%'; // ‘42%’ -export const THOUSANDTH_500: string = '50%'; // ‘50%’ -export const THOUSANDTH_560: string = '56%'; // ‘56%’ -export const THOUSANDTH_800: string = '80%'; // ‘80%’ -export const THOUSANDTH_830: string = '83%'; // ‘83%’ -export const THOUSANDTH_880: string = '88%'; // ‘88%’ -export const THOUSANDTH_900: string = '90%'; // ‘90%’ -export const THOUSANDTH_940: string = '94%'; // ‘90%’ -export const THOUSANDTH_1000: string = '100%'; // ‘100%’ + static readonly DEFAULT_8: number = 8; -export const DEFAULT_2: number = 2; + static readonly DEFAULT_12: number = 12; -export const DEFAULT_6: number = 6; + static readonly DEFAULT_10: number = 10; -export const DEFAULT_8: number = 8; + static readonly DEFAULT_16: number = 16; -export const DEFAULT_12: number = 12; + static readonly DEFAULT_18: number = 18; -export const DEFAULT_10: number = 10; + static readonly DEFAULT_20: number = 20; -export const DEFAULT_16: number = 16; + static readonly DEFAULT_24: number = 24; -export const DEFAULT_18: number = 18; + static readonly DEFAULT_28: number = 28; -export const DEFAULT_20: number = 20; + static readonly DEFAULT_32: number = 32; -export const DEFAULT_24: number = 24; + static readonly DEFAULT_48: number = 48; -export const DEFAULT_28: number = 28; + static readonly DEFAULT_56: number = 56; -export const DEFAULT_32: number = 32; + static readonly DEFAULT_60: number = 60; -export const DEFAULT_48: number = 48; + static readonly DEFAULT_100: number = 100; -export const DEFAULT_56: number = 56; + static readonly DEFAULT_180: number = 180; -export const DEFAULT_60: number = 60; + // fontWeight + static readonly FONT_WEIGHT_400: number = 400; -export const DEFAULT_100: number = 100; + static readonly FONT_WEIGHT_500: number = 500; -export const DEFAULT_180: number = 180; + static readonly FONT_WEIGHT_700: number = 700; -// fontWeight -export const FONT_WEIGHT_400: number = 400; + static readonly FONT_WEIGHT_900: number = 900; -export const FONT_WEIGHT_500: number = 500; -export const FONT_WEIGHT_700: number = 700; + // opacity + static readonly OPACITY_4: number = 0.4; -export const FONT_WEIGHT_900: number = 900; + static readonly OPACITY_6: number = 0.6; + // radius + static readonly BORDER_RADIUS_PERCENT_50: string = '50%'; -// opacity -export const OPACITY_4: number = 0.4; + // duration + static readonly AD_DURATION: number = 5; // 5s + static readonly LAUNCHER_DELAY_TIME: number = 2000; // 2000ms + static readonly DURATION_1000: number = 1000; // 1000ms + static readonly DURATION_800: number = 800; // 700ms + static readonly DURATION_100: number = 100; // 100ms -export const OPACITY_6: number = 0.6; -// radius -export const BORDER_RADIUS_PERCENT_50: string = '50%'; + // list space + static readonly LIST_ITEM_SPACE: number = 2; -// duration -export const AD_DURATION: number = 5; // 5s -export const LAUNCHER_DELAY_TIME: number = 2000; // 2000ms -export const DURATION_1000: number = 1000; // 1000ms -export const DURATION_800: number = 800; // 700ms -export const DURATION_100: number = 100; // 100ms + static readonly SPACE_4: number = 4; + // navigation title + static readonly ADD_TASK_TITLE: string = '添加任务'; -// list space -export const LIST_ITEM_SPACE: number = 2; + static readonly EDIT_TASK_TITLE: string = '编辑任务'; -export const SPACE_4: number = 4; + // prompt message + static readonly SETTING_FINISHED_MESSAGE = '设置完成!!!'; -// navigation title -export const ADD_TASK_TITLE: string = '添加任务'; + static readonly SETTING_FINISH_FAILED_MESSAGE = '网络连接错误'; -export const EDIT_TASK_TITLE: string = '编辑任务'; + static readonly CHOOSE_TIME_OUT_RANGE: string = '选择时间超出范围'; -// prompt message -export const SETTING_FINISHED_MESSAGE = '设置完成!!!'; + static readonly NICK_NAME = 'JoIin'; -export const SETTING_FINISH_FAILED_MESSAGE = '网络连接错误'; + static readonly SIGNATURE = '这是一条简短地个人签'; -export const CHOOSE_TIME_OUT_RANGE: string = '选择时间超出范围'; + static readonly HOME_BTN_Z = 2; -export const NICK_NAME = 'JoIin'; + // time range + static readonly DEFAULT_TIME: string = '08:00'; -export const SIGNATURE = '这是一条简短地个人签'; + static readonly GET_UP_TIME_RANGE: string = '(06:00 - 09:00)'; -export const HOME_BTN_Z = 2; + static readonly SLEEP_TIME_RANGE: string = '(20:00 - 23:00)'; -// date format -export const TODAY: string = new Date().toDateString(); + static readonly GET_UP_EARLY_TIME: string = '06:00'; -// time range -export const DEFAULT_TIME: string = '08:00'; + static readonly GET_UP_LATE_TIME: string = '09:00'; -export const GET_UP_TIME_RANGE: string = '(06:00 - 09:00)'; + static readonly SLEEP_EARLY_TIME: string = '20:00'; -export const SLEEP_TIME_RANGE: string = '(20:00 - 23:00)'; + static readonly SLEEP_LATE_TIME: string = '23:00'; -export const GET_UP_EARLY_TIME: string = '06:00'; + // frequency Dialog + static readonly EVERYDAY: string = '每天'; -export const GET_UP_LATE_TIME: string = '09:00'; + static readonly NO_LENGTH: number = 0; -export const SLEEP_EARLY_TIME: string = '20:00'; + static readonly INIT_WEEK_IDS: string = '1, 2, 3, 4, 5, 6, 7'; -export const SLEEP_LATE_TIME: string = '23:00'; + // unit + static readonly PER_DAY: string = '/ 天'; -export const DEFAULT_SELECTED_TIME: Date = new Date(`${TODAY} 8:00:00`); + // global data key + static readonly GLOBAL_KEY: string = 'global'; -// frequency Dialog -export const EVERYDAY: string = '每天'; + // RemindContent + static readonly GET_UP_TASK_NAME: string = '早起'; -export const NO_LENGTH: number = 0; + static readonly DRINK_TASK_NAME: string = '喝水'; -export const INIT_WEEK_IDS: string = '1, 2, 3, 4, 5, 6, 7'; + static readonly EAT_APPLE_TASK_NAME: string = '吃苹果'; -// unit -export const PER_DAY: string = '/ 天'; + static readonly SMILE_TASK_NAME: string = '每日微笑'; -// global data key -export const GLOBAL_KEY: string = 'global'; + static readonly BRUSH_TEETH_TASK_NAME: string = '每日刷牙'; -// RemindContent -export const GET_UP_TASK_NAME: string = '早起'; + static readonly SLEEP_TASK_NAME: string = '早睡'; -export const DRINK_TASK_NAME: string = '喝水'; + static readonly GET_UP_CONTENT: string = '该早起啦'; -export const EAT_APPLE_TASK_NAME: string = '吃苹果'; + static readonly DRINK_CONTENT: string = '该喝水啦'; -export const SMILE_TASK_NAME: string = '每日微笑'; + static readonly EAT_APPLE_CONTENT: string = '该吃苹果啦'; -export const BRUSH_TEETH_TASK_NAME: string = '每日刷牙'; + static readonly SMILE_CONTENT: string = '请保持微笑'; -export const SLEEP_TASK_NAME: string = '早睡'; + static readonly BRUSH_TEETH_CONTENT: string = '每日刷牙'; -export const GET_UP_CONTENT: string = '该早起啦'; + static readonly SLEEP_CONTENT: string = '早睡'; -export const DRINK_CONTENT: string = '该喝水啦'; + static readonly H_STORE: string = 'healthAppStore'; -export const EAT_APPLE_CONTENT: string = '该吃苹果啦'; + static readonly REMINDER_AGENT_TAG: string = 'reminderAgent'; -export const SMILE_CONTENT: string = '请保持微笑'; + static readonly PACKAGE_NAME: string = 'com.example.healthy_life'; -export const BRUSH_TEETH_CONTENT: string = '每日刷牙'; + static readonly ENTRY_ABILITY: string = 'EntryAbility'; -export const SLEEP_CONTENT: string = '早睡'; + // offset + static readonly ZERO: number = 0; -// offset -export const ZERO: number = 0; + static readonly MINUS_20: number = -20; -export const MINUS_20: number = -20; + static readonly HAS_NO_INDEX: number = -1; -export const HAS_NO_INDEX: number = -1; + static readonly OFFSET_24: number = -24; -export const OFFSET_24: number = -24; + // targetSetting Range + static readonly DRINK_STEP: number = 25; -// targetSetting Range -export const DRINK_STEP: number = 25; + static readonly DRINK_MAX_RANGE: number = 500; -export const DRINK_MAX_RANGE: number = 500; + static readonly TIMES_50: number = 50; -export const TIMES_100: number = 100; + static readonly TIMES_100: number = 100; -export const EAT_APPLE_RANGE: number = 100; + static readonly EAT_APPLE_RANGE: number = 100; -// letter spacing -export const LETTER_1: number = 0.1; + // letter spacing + static readonly LETTER_1: number = 0.1; -export const LETTER_34: number = 3.4; + static readonly LETTER_34: number = 3.4; -// achievement -export const ACHIEVE_CARD_IMG_HEIGHT: number = 88; + // achievement + static readonly ACHIEVE_CARD_IMG_HEIGHT: number = 88; -export const ACHIEVE_CARD_TOP: number = 38; + static readonly ACHIEVE_CARD_TOP: number = 38; -export const ACHIEVE_CARD_BOTTOM: number = 10; + static readonly ACHIEVE_CARD_BOTTOM: number = 10; -export const ACHIEVE_SPLIT_RATIO: number = 1 / 3; + static readonly ACHIEVE_SPLIT_RATIO: number = 1 / 3; -export const ACHIEVE_TITLE_BAR_LEFT: number = 20; + static readonly ACHIEVE_TITLE_BAR_LEFT: number = 20; -export const ACHIEVE_TITLE_BAR_TOP: number = 15; + static readonly ACHIEVE_TITLE_BAR_TOP: number = 15; -export const FULL_WIDTH: string = '100%'; + static readonly FULL_WIDTH: string = '100%'; -export const FULL_HEIGHT: string = '100%'; + static readonly FULL_HEIGHT: string = '100%'; -export const WEEK_DAY_NUM: number = 7; // number days of one week -export const WEEK_DAY_TIME: number = WEEK_DAY_NUM * 24 * 60 * 60 * 1000; \ No newline at end of file + static readonly WEEK_DAY_NUM: number = 7; // number days of one week + + static readonly WEEK_DAY_TIME: number = 7 * 24 * 60 * 60 * 1000; + + // Card Constants + static readonly TAG = "UpdateFormUtils"; + static readonly FORM_PARAM_IDENTITY_KEY = "ohos.extra.param.key.form_identity"; + static readonly FORM_PARAM_DIMENSION_KEY = "ohos.extra.param.key.form_dimension"; + static readonly FORM_PARAM_NAME_KEY = "ohos.extra.param.key.form_name"; + static readonly DEFAULT_DIMENSION_2X2 = 2; + static readonly DEFAULT_DIMENSION_2X4 = 3; + static readonly WIDGET_NAME_AGENCY = "agency"; + static readonly WIDGET_NAME_PROGRESS = "progress"; +} + +export enum TaskType { + Getup = 'getup', + Drink= 'drink', + Apple = 'apple', + Smile = 'smile', + Clean = 'clean', + Sleep = 'sleep' +} + +export enum Unit { + Liter = 'L', + Pcs = '个', + Times = '次', + Empty = '' +} diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbHelper.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbHelper.ets index 05823750f9b1e225fecfb3804141449ce5bee0c9..2728fd0b31d5c09e62947726f969a08057d4c1f3 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbHelper.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbHelper.ets @@ -1,30 +1,120 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import dataRdb from '@ohos.data.relationalStore'; -import ColumnInfo from '../../bean/ColumnInfo'; +import ColumnInfo from '../../../viewmodel/ColumnInfo'; export interface RdbHelper { + /** + * Get name of the database. + * + * @returns the database name + */ + getDbName(): string; - getDbName(): string - - getRdb(context?: any): Promise - - executeSql(sql: string): Promise + /** + * Obtains a RDB store. + * + * @param context - indicates the context of application or capability. + * @returns the RDB store. + */ + getRdb(context: Context): Promise; - createTable(tableName: string, columns: Array): Promise + /** + * Execute sql in the database. + * + * @param sql - indicates the SQL statement to execute. + * @returns + */ + executeSql(sql: string): Promise; - deleteTable(tableName: string): Promise + /** + * Create table in the database. + * + * @param tableName - indicates the target table. + * @param columns - the columns to alert. + * @returns + */ + createTable(tableName: string, columns: Array): Promise; - addTableColumn(tableName: string, column: ColumnInfo): Promise + /** + * Delete table in the database based on table name. + * + * @param tableName - indicates the target table. + * @returns + */ + deleteTable(tableName: string): Promise; - insert(tableName: string, values: dataRdb.ValuesBucket | Array): Promise + /** + * Alert table in the database based on table name. + * + * @param tableName - indicates the target table. + * @param column - the columns to alert. + * @returns + */ + addTableColumn(tableName: string, column: ColumnInfo): Promise; - update(values: dataRdb.ValuesBucket, rdbPredicates: dataRdb.RdbPredicates): Promise + /** + * Inserts a row of data or a batch of data into the target table. + * + * @param tableName - indicates the target table. + * @param values - indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @returns the number of affected rows. + */ + insert(tableName: string, values: dataRdb.ValuesBucket | Array): Promise; - query(rdbPredicates: dataRdb.RdbPredicates, columns?: Array): Promise + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param values - indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @param rdbPredicates - the specified update condition by the instance object of {@link RdbPredicates}. + * @returns the number of affected rows. + */ + update(values: dataRdb.ValuesBucket, rdbPredicates: dataRdb.RdbPredicates): Promise; - queryAll(tableName: string): Promise + /** + * Queries data in the database based on specified conditions. + * + * @param rdbPredicates - the specified query condition by the instance object of {@link RdbPredicates}. + * @param columns - the columns to query. If the value is empty array, the query applies to all columns. + * @returns the {@link ResultSet} object if the operation is successful. + */ + query(rdbPredicates: dataRdb.RdbPredicates, columns?: Array): Promise; - queryBySql(sql: string, bindArgs?: Array): Promise + /** + * Queries data in the database based on table name. + * + * @param tableName - indicates the target table. + * @returns the {@link ResultSet} object if the operation is successful. + */ + queryAll(tableName: string): Promise; - delete(rdbPredicates: dataRdb.RdbPredicates): Promise + /** + * Queries data in the database based on SQL statement. + * + * @param sql - indicates the SQL statement to execute. + * @param bindArgs - indicates the values of the parameters in the SQL statement. The values are strings. + * @returns the {@link ResultSet} object if the operation is successful. + */ + queryBySql(sql: string, bindArgs?: Array): Promise; + /** + * Delete Data in the database based on specified conditions. + * + * @param rdbPredicates - the specified delete condition by the instance object of {@link RdbPredicates}. + * @returns the number of affected rows. + */ + delete(rdbPredicates: dataRdb.RdbPredicates): Promise; } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbHelperImp.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbHelperImp.ets index d2b27bf430a36e51e313611bf02f4d8f34675653..4230d2ec1f21bec8b2f2aaf77de77f433fb4495b 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbHelperImp.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbHelperImp.ets @@ -1,13 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import dataRdb from '@ohos.data.relationalStore'; import tableHelper from './TableHelper'; import { RdbHelper } from './RdbHelper'; -import ColumnInfo from '../../bean/ColumnInfo'; +import ColumnInfo from '../../../viewmodel/ColumnInfo'; import Logger from '../../utils/Logger'; export class RdbHelperImp implements RdbHelper { private mDatabaseName: string; - private rdbStore: dataRdb.RdbStore = null; - private storeConfig: dataRdb.StoreConfig; + private rdbStore: dataRdb.RdbStore = {} as dataRdb.RdbStore; + private storeConfig: dataRdb.StoreConfig = { name: '', securityLevel: dataRdb.SecurityLevel.S1 } as dataRdb.StoreConfig; constructor(databaseName: string) { this.mDatabaseName = databaseName; @@ -17,8 +32,7 @@ export class RdbHelperImp implements RdbHelper { return this.mDatabaseName; } - getRdb(context: any): Promise { - Logger.info(`initRdb getRdb success`); + getRdb(context: Context): Promise { this.storeConfig = { name: this.mDatabaseName, securityLevel: dataRdb.SecurityLevel.S1 }; @@ -26,7 +40,7 @@ export class RdbHelperImp implements RdbHelper { dataRdb.getRdbStore(context, this.storeConfig).then(dbStore => { this.rdbStore = dbStore; success(this); - }).catch(err => { + }).catch((err: Error) => { Logger.error(`initRdb err : ${JSON.stringify(err)}`); error(err); }) @@ -57,21 +71,21 @@ export class RdbHelperImp implements RdbHelper { } insert(tableName: string, values: dataRdb.ValuesBucket | Array): Promise { - return new Promise((success, error) => { + return new Promise((success, error) => { Logger.info(`insert tableName : ${tableName}, values : ${JSON.stringify(values)}`); if (!values) { Logger.info(`insert failed, values is undefined`); error(0); return; } - if (Array.isArray(values)) { + if (values instanceof Array) { Logger.info(`insert values isArray = ${values.length}`); this.rdbStore.beginTransaction(); this.saveArray(tableName, values).then(data => { Logger.info(`insert success, data : ${JSON.stringify(data)}`); success(data); this.rdbStore.commit(); - }).catch(err => { + }).catch((err: Error) => { Logger.error(`insert failed, err : ${err}`); error(err); this.rdbStore.commit(); @@ -81,8 +95,8 @@ export class RdbHelperImp implements RdbHelper { Logger.info(`insert success id : ${data}`); success(data); this.rdbStore.commit(); - }).catch(err => { - Logger.error(`insert failed, err : ${err}`); + }).catch((err: Error) => { + Logger.error(`insert failed, err : ${JSON.stringify(err)}`); error(err); this.rdbStore.commit(); }) @@ -92,12 +106,12 @@ export class RdbHelperImp implements RdbHelper { private saveArray(tableName: string, values: Array): Promise { return new Promise((success, error) => { - if (!values || values.length == 0) { + if (!values || values.length === 0) { error(0); return; } let index = 0 - let callback = (data, err) => { + let callback = (data: number, err: Error) => { if (err) { Logger.info(`saveArray failed, err : ${err}`); error(err); @@ -115,12 +129,12 @@ export class RdbHelperImp implements RdbHelper { }) } - private saveData(tableName: string, values: Array, index: number, callback) { + private saveData(tableName: string, values: Array, index: number, callback: Function): void { Logger.info(`saveData tableName : ${tableName}, index : ${JSON.stringify(index)}`); - this.rdbStore.insert(tableName, values[index]).then(data => { + this.rdbStore.insert(tableName, values[index]).then((data: number) => { Logger.info(`saveData success id : ${data}`); callback(data); - }).catch(err => { + }).catch((err: Error) => { Logger.error(`saveData failed, err : ${err}`); callback(err); }) @@ -132,7 +146,7 @@ export class RdbHelperImp implements RdbHelper { query(rdbPredicates: dataRdb.RdbPredicates, columns?: Array): Promise { Logger.info(`query rdbPredicates : ${JSON.stringify(rdbPredicates)}`); - return this.rdbStore.query(rdbPredicates, columns) + return this.rdbStore.query(rdbPredicates, columns); } queryAll(tableName: string): Promise { @@ -140,7 +154,7 @@ export class RdbHelperImp implements RdbHelper { return this.rdbStore.querySql(`select * from ${tableName}`); } - queryBySql(sql: string, bindArgs?: Array): Promise { + queryBySql(sql: string, bindArgs?: Array): Promise { Logger.info(`queryBySql sql : ${sql}`); return this.rdbStore.querySql(sql, bindArgs); } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbUtils.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbUtils.ets index 70401e9224d5874d07fb8c1eb553e83f90c09ed4..0d9ce310d683d13093fe8c47ef30d1b17f210603 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbUtils.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/RdbUtils.ets @@ -1,17 +1,32 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import dataRdb from '@ohos.data.relationalStore'; -import common from '@ohos.app.ability.common'; -import ColumnInfo from '../../bean/ColumnInfo'; +import ColumnInfo from '../../../viewmodel/ColumnInfo'; import { RdbHelper } from './RdbHelper'; import { RdbHelperImp } from './RdbHelperImp'; import Logger from '../../utils/Logger'; +import Queue from '@ohos.util.Queue'; -let dbContext: common.UIAbilityContext; +let dbContext: Context; let mDatabaseName: string = ''; export class RdbUtils { private rdbHelpers = new Map(); - initDb(context: common.UIAbilityContext, databaseName: string) { + initDb(context: Context, databaseName: string) { dbContext = context; mDatabaseName = databaseName; } @@ -19,7 +34,7 @@ export class RdbUtils { createDb(): Promise { return new Promise((success, error) => { let dbName = mDatabaseName; - if (!dbContext || !dbName || dbName.length == 0) { + if (!dbContext || !dbName || dbName.length === 0) { error("init err"); return; } @@ -30,7 +45,7 @@ export class RdbUtils { rdbHelper.getRdb(dbContext).then(data => { this.rdbHelpers.set(dbName, data); success(data); - }).catch(err => { + }).catch((err: Error) => { error(err); }) } else { @@ -39,7 +54,7 @@ export class RdbUtils { }) } - deleteDb(context: any, dbName: string): Promise { + deleteDb(context: Context, dbName: string): Promise { this.rdbHelpers.delete(dbName); return dataRdb.deleteRdbStore(context, dbName); } @@ -47,7 +62,16 @@ export class RdbUtils { createTable(tableName: string, columns: Array): Promise { return this.createDb().then(dbHelper => { return dbHelper.createTable(tableName, columns); - }) + }); + } + + isCreateTable(tableName: string, columns: Array): Promise { + return this.createTable(tableName, columns).then(() => { + return true; + }).catch((error: Error) => { + Logger.error('RdbUtils', 'create table error ' + JSON.stringify(error)); + return false; + }); } deleteTable(tableName: string): Promise { @@ -92,7 +116,7 @@ export class RdbUtils { }) } - queryBySql(sql: string, bindArgs?: Array): Promise { + queryBySql(sql: string, bindArgs?: Array): Promise { return this.createDb().then(dbHelper => { return dbHelper.queryBySql(sql, bindArgs); }) diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/TableHelper.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/TableHelper.ets index 9dd57e9215c76caeec64f26105f5e4c9af51e85a..0404259a2f671be5714ac90b736cfcc9b5143ea8 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/TableHelper.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/rdb/TableHelper.ets @@ -1,25 +1,38 @@ -import ColumnInfo from '../../bean/ColumnInfo'; +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import ColumnInfo from '../../../viewmodel/ColumnInfo'; import Logger from '../../utils/Logger'; class TableHelper { createTableSql(tableName: string, columns: Array): string { - Logger.info(`TableHelper createTableSql : ${JSON.stringify(columns)}`); - let sql = `create table if not exists ${tableName}(` + let sql = `create table if not exists ${tableName}(`; for (let column of columns) { - sql = sql.concat(`${column.name} ${column.type}`) - sql = sql.concat(`${column.length && column.length > 0 ? `(${column.length})` : ''}`) - sql = sql.concat(`${column.primary ? ' primary key' : ''}`) - sql = sql.concat(`${column.autoincrement ? ' autoincrement' : ''}`) - sql = sql.concat(`${column.nullable ? '' : ' not null'}`) - sql = sql.concat(', ') + sql = sql.concat(`${column.name} ${column.type}`); + sql = sql.concat(`${column.length && column.length > 0 ? `(${column.length})` : ''}`); + sql = sql.concat(`${column.primary ? ' primary key' : ''}`); + sql = sql.concat(`${column.autoincrement ? ' autoincrement' : ''}`); + sql = sql.concat(`${column.nullable ? '' : ' not null'}`); + sql = sql.concat(', '); } sql = `${sql.substring(0, sql.length - 2)})`; - Logger.info(`TableHelper createTableSql : ` + sql); return sql; } addTableColumnSql(tableName: string, column: ColumnInfo): string { - Logger.info(`TableHelper updateTableSql : ${JSON.stringify(column)}`) + Logger.info(`TableHelper updateTableSql : ${JSON.stringify(column)}`); let sql = `alter table ${tableName} add `; sql = sql.concat(`${column.name} ${column.type}`); sql = sql.concat(`${column.length && column.length > 0 ? `(${column.length})` : ''}`); @@ -35,4 +48,4 @@ class TableHelper { const tableHelper = new TableHelper(); -export default tableHelper \ No newline at end of file +export default tableHelper; \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/DayInfoApi.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/DayInfoApi.ets index 8760b5a2f70f6682aa3fcc61c7df9dcdbecb0746..73b5141836f596665fa055a8a9612c50ff7e9626 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/DayInfoApi.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/DayInfoApi.ets @@ -14,20 +14,20 @@ */ import dataRdb from '@ohos.data.relationalStore'; -import DayInfo from '../../bean/DayInfo'; -import { DAY_INFO } from '../../constants/CommonConstants' +import DayInfo from '../../../viewmodel/DayInfo'; +import { CommonConstants as Const } from '../../constants/CommonConstants' import RdbUtils from '../Rdb/RdbUtils'; import Logger from '../../utils/Logger'; class DayInfoApi { /** - * insert dayInfo + * Insert dayInfo. * * @param dayInfo * @param callback */ - insertData(dayInfo: DayInfo, callback: Function) { + insertData(dayInfo: DayInfo, callback: Function): void { const valueBucket = generateBucket(dayInfo); RdbUtils.insert('dayInfo', valueBucket).then(result => { callback(result); @@ -36,35 +36,36 @@ class DayInfoApi { } /** - * update dayInfo + * Update dayInfo. * * @param dayInfo * @param callback */ - updateData(dayInfo: DayInfo, callback: Function) { + updateData(dayInfo: DayInfo, callback: Function): void { const valueBucket = generateBucket(dayInfo); - let predicates = new dataRdb.RdbPredicates(DAY_INFO.tableName); + let predicates: dataRdb.RdbPredicates = new dataRdb.RdbPredicates(Const.DAY_INFO.tableName ? Const.DAY_INFO.tableName : ''); predicates.equalTo('date', dayInfo.date); - RdbUtils.update(valueBucket, predicates).then(result => { + RdbUtils.update(valueBucket, predicates).then((result: number) => { callback(result); }); Logger.info('DayInfoTable', 'Update dayInfo finished.'); } /** - * query dayInfo + * Query dayInfo. * * @param date * @param callback */ - query(date: string, callback: Function) { - let predicates = new dataRdb.RdbPredicates(DAY_INFO.tableName); + query(date: string, callback: Function): void { + let predicates: dataRdb.RdbPredicates = new dataRdb.RdbPredicates(Const.DAY_INFO.tableName ? Const.DAY_INFO.tableName : ''); predicates.equalTo('date', date); RdbUtils.query(predicates).then(resultSet => { let count = resultSet.rowCount; if (count === 0) { Logger.info('DayInfoTable', 'query no results.'); - callback([]); + let result = new DayInfo('', 0, 0); + callback(result); } else { let result = new DayInfo('', 0, 0); resultSet.goToFirstRow(); @@ -78,22 +79,23 @@ class DayInfoApi { } /** - * query dayInfo list + * Query dayInfo list. * * @param date * @param callback */ - queryList(dates: string[], callback: Function) { - let predicates = new dataRdb.RdbPredicates(DAY_INFO.tableName); + queryList(dates: string[], callback: Function): void { + let predicates: dataRdb.RdbPredicates = new dataRdb.RdbPredicates(Const.DAY_INFO.tableName ? Const.DAY_INFO.tableName : ''); predicates.in('date', dates); RdbUtils.query(predicates).then(resultSet => { let count = resultSet.rowCount; if (count === 0) { Logger.info('DayInfoTable', 'query no results.'); - callback([]); + let result: DayInfo[] = []; + callback(result); } else { resultSet.goToFirstRow(); - let result = []; + let result: DayInfo[] = []; for (let i = 0; i < count; i++) { let tmp = new DayInfo('', 0, 0); tmp.date = resultSet.getString(resultSet.getColumnIndex('date')); @@ -104,15 +106,26 @@ class DayInfoApi { } callback(result); } - return; }); } } -function generateBucket(dayInfo: DayInfo) { - let valueBucket = {}; - DAY_INFO.columns.forEach((item) => { - valueBucket[item] = dayInfo[item]; +function generateBucket(dayInfo: DayInfo): dataRdb.ValuesBucket { + let valueBucket = {} as dataRdb.ValuesBucket; + Const.DAY_INFO.columns?.forEach((item: string) => { + switch (item) { + case 'date': + valueBucket.date = dayInfo.date; + break; + case 'targetTaskNum': + valueBucket.targetTaskNum = dayInfo.targetTaskNum; + break; + case 'finTaskNum': + valueBucket.finTaskNum = dayInfo.finTaskNum; + break; + default: + break; + } }); return valueBucket; } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/GlobalInfoApi.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/GlobalInfoApi.ets index 2fe76ad9ee1e753d8aa04e34740bb5385541492a..e8712051ce94d1eb10482e9d0138ea33a0c70c5a 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/GlobalInfoApi.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/GlobalInfoApi.ets @@ -14,20 +14,20 @@ */ import dataRdb from '@ohos.data.relationalStore'; -import GlobalInfo from '../../bean/GlobalInfo'; -import { GLOBAL_INFO } from '../../constants/CommonConstants' +import GlobalInfo from '../../../viewmodel/GlobalInfo'; +import { CommonConstants as Const } from '../../constants/CommonConstants' import RdbUtils from '../Rdb/RdbUtils'; import Logger from '../../utils/Logger'; class GlobalInfoApi { /** - * insert globalInfo + * Insert globalInfo. * * @param globalInfo * @param callback */ - insertData(globalInfo: GlobalInfo, callback) { + insertData(globalInfo: GlobalInfo, callback: Function): void { const valueBucket = generateBucket(globalInfo); RdbUtils.insert('GlobalInfo', valueBucket).then(result => { callback(result); @@ -36,34 +36,35 @@ class GlobalInfoApi { } /** - * update globalInfo + * Update globalInfo. * * @param globalInfo * @param callback */ - updateData(globalInfo: GlobalInfo, callback) { + updateData(globalInfo: GlobalInfo, callback: Function): void { const valueBucket = generateBucket(globalInfo); - let predicates = new dataRdb.RdbPredicates(GLOBAL_INFO.tableName); + let predicates = new dataRdb.RdbPredicates(Const.GLOBAL_INFO.tableName ? Const.GLOBAL_INFO.tableName : ''); predicates.equalTo('id', 0); - RdbUtils.update(valueBucket, predicates).then(result => { + RdbUtils.update(valueBucket, predicates).then((result: number) => { callback(result); }); Logger.info('GlobalInfoTable', 'Update globalInfo finished.'); } /** - * query globalInfo + * Query globalInfo. * * @param callback */ - query(callback) { - let predicates = new dataRdb.RdbPredicates(GLOBAL_INFO.tableName); + query(callback: Function): void { + let predicates = new dataRdb.RdbPredicates(Const.GLOBAL_INFO.tableName ? Const.GLOBAL_INFO.tableName : ''); predicates.equalTo('id', 0); RdbUtils.query(predicates).then(resultSet => { let count = resultSet.rowCount; if (count === 0) { Logger.info('GlobalInfoTable', 'query no results!'); - callback([]); + let result = new GlobalInfo('', '', 0, ''); + callback(result); } else { let result = new GlobalInfo('', '', 0, ''); resultSet.goToFirstRow(); @@ -73,18 +74,32 @@ class GlobalInfoApi { result.achievements = resultSet.getString(resultSet.getColumnIndex('achievements')); callback(result); } - return; }); } } -function generateBucket(globalInfo: GlobalInfo) { - let valueBucket = {}; - GLOBAL_INFO.columns.forEach((item) => { +function generateBucket(globalInfo: GlobalInfo): dataRdb.ValuesBucket { + let valueBucket = {} as dataRdb.ValuesBucket; + Const.GLOBAL_INFO.columns?.forEach((item: string) => { if (item === 'id') { valueBucket[item] = 0; } else { - valueBucket[item] = globalInfo[item]; + switch (item) { + case 'firstDate': + valueBucket[item] = globalInfo.firstDate; + break; + case 'lastDate': + valueBucket[item] = globalInfo.lastDate; + break; + case 'checkInDays': + valueBucket[item] = globalInfo.checkInDays; + break; + case 'achievements': + valueBucket[item] = globalInfo.achievements; + break; + default: + break; + } } }); return valueBucket; diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/TaskInfoApi.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/TaskInfoApi.ets index 3e998c5d70cfc7f2008390829e79c8394497486c..63904a7cc6cad23a4dbbed127baac3c0301da846 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/TaskInfoApi.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/database/tables/TaskInfoApi.ets @@ -14,8 +14,8 @@ */ import dataRdb from '@ohos.data.relationalStore'; -import TaskInfo from '../../bean/TaskInfo'; -import { TASK_INFO } from '../../constants/CommonConstants' +import TaskInfo from '../../../viewmodel/TaskInfo'; +import { CommonConstants as Const } from '../../constants/CommonConstants'; import RdbUtils from '../Rdb/RdbUtils'; import Logger from '../../utils/Logger'; @@ -26,7 +26,7 @@ class TaskInfoApi { * @param taskInfo * @param callback */ - insertData(taskInfo: TaskInfo, callback) { + insertData(taskInfo: TaskInfo, callback: Function): void { const valueBucket = generateBucket(taskInfo); RdbUtils.insert('taskInfo', valueBucket).then(result => { callback(result); @@ -40,13 +40,17 @@ class TaskInfoApi { * @param taskInfo * @param callback */ - deleteDataByID(taskInfo: TaskInfo, callback) { - let predicates = new dataRdb.RdbPredicates(TASK_INFO.tableName); + deleteDataByID(taskInfo: TaskInfo, callback: Function): void { + let tableName = Const.TASK_INFO.tableName; + if (!tableName) { + return; + } + let predicates = new dataRdb.RdbPredicates(tableName); predicates.equalTo('date', taskInfo.date).and().equalTo('taskID', taskInfo.taskID); RdbUtils.del(predicates).then(result => { callback(result); }); - Logger.info('TaskInfoTable', `Delete taskInfo {${taskInfo.date}:${taskInfo.taskID}} finished.`) + Logger.info('TaskInfoTable', `Delete taskInfo {${taskInfo.date}:${taskInfo.taskID}} finished.`); } /** @@ -55,12 +59,16 @@ class TaskInfoApi { * @param taskInfo * @param callback */ - updateDataByDate(taskInfo: TaskInfo, callback) { + updateDataByDate(taskInfo: TaskInfo, callback: Function): void { const valueBucket = generateBucket(taskInfo); - let predicates = new dataRdb.RdbPredicates(TASK_INFO.tableName); + let tableName = Const.TASK_INFO.tableName; + if (!tableName) { + return; + } + let predicates = new dataRdb.RdbPredicates(tableName); predicates.equalTo('date', taskInfo.date).and().equalTo('taskID', taskInfo.taskID); - RdbUtils.update(valueBucket, predicates).then(result => { - callback(result) + RdbUtils.update(valueBucket, predicates).then((result: number) => { + callback(result); }); Logger.info('TaskInfoTable', `Update data {${taskInfo.date}:${taskInfo.taskID}} finished.`); } @@ -71,8 +79,12 @@ class TaskInfoApi { * @param date * @param callback */ - query(date: string, isOpen: boolean = true, callback) { - let predicates = new dataRdb.RdbPredicates(TASK_INFO.tableName); + query(date: string, isOpen: boolean = true, callback: Function): void { + let tableName = Const.TASK_INFO.tableName; + if (!tableName) { + return; + } + let predicates = new dataRdb.RdbPredicates(tableName); predicates.equalTo('date', date); if (isOpen) { predicates.equalTo('isOpen', true); @@ -80,13 +92,13 @@ class TaskInfoApi { predicates.orderByAsc('taskID'); RdbUtils.query(predicates).then(resultSet => { let count = resultSet.rowCount; - // 添加数据库返回错误的逻辑判断 if (count === 0 || typeof count === 'string') { Logger.error('TaskInfoTable', `${date} query no results!`); - callback([]); + const result: TaskInfo[] = []; + callback(result); } else { resultSet.goToFirstRow(); - const result = []; + const result: TaskInfo[] = []; for (let i = 0; i < count; i++) { let tmp = new TaskInfo(0, '', 0, '', false, '', '', '', false, ''); tmp.isOpen = resultSet.getDouble(resultSet.getColumnIndex('isOpen')) ? true : false; @@ -105,16 +117,48 @@ class TaskInfoApi { } callback(result); } - return; }); } } -function generateBucket(taskInfo: TaskInfo) { - let valueBucket = {}; - TASK_INFO.columns.forEach((item) => { +function generateBucket(taskInfo: TaskInfo): dataRdb.ValuesBucket { + let valueBucket = {} as dataRdb.ValuesBucket; + Const.TASK_INFO.columns?.forEach((item: string) => { if (item !== 'id') { - valueBucket[item] = taskInfo[item]; + switch (item) { + case 'date': + valueBucket[item] = taskInfo.date; + break; + case 'taskID': + valueBucket[item] = taskInfo.taskID; + break; + case 'targetValue': + valueBucket[item] = taskInfo.targetValue; + break; + case 'isAlarm': + valueBucket[item] = taskInfo.isAlarm; + break; + case 'startTime': + valueBucket[item] = taskInfo.startTime; + break; + case 'endTime': + valueBucket[item] = taskInfo.endTime; + break; + case 'frequency': + valueBucket[item] = taskInfo.frequency; + break; + case 'isDone': + valueBucket[item] = taskInfo.isDone; + break; + case 'finValue': + valueBucket[item] = taskInfo.finValue; + break; + case 'isOpen': + valueBucket[item] = taskInfo.isOpen; + break; + default: + break; + } } }); return valueBucket; diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/BroadCast.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/BroadCast.ets index 9240041766ed9b35ea7daee1c24e93608699e6c6..08168bd9115cc38f39241dba453045b1c64a9b10 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/BroadCast.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/BroadCast.ets @@ -12,51 +12,112 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { CustomDialogCallback } from '../../view/dialog/CustomDialogView'; +import BroadCastCallBackInfo from '../../viewmodel/BroadCastCallBackInfo'; +import TaskInfo from '../../viewmodel/TaskInfo'; import Logger from './Logger'; const FILE_TAG = 'BroadCast'; +const callBackArrayTemp = new BroadCastCallBackInfo(); + export class BroadCast { - private callBackArray = {}; + private callBackArray: BroadCastCallBackInfo = callBackArrayTemp; - public on(event, callback) { + public on(event: string, callback: Function) { Logger.info(FILE_TAG, 'register broadcast with type '+ event); - (this.callBackArray[event] || (this.callBackArray[event] = [])).push(callback); + switch (event) { + case BroadCastType.SHOW_ACHIEVEMENT_DIALOG: + this.callBackArray.showAchievementDialog = callback; + break; + case BroadCastType.SHOW_TASK_DETAIL_DIALOG: + this.callBackArray.showTaskDetailDialog = callback; + break; + case BroadCastType.SHOW_TARGET_SETTING_DIALOG: + this.callBackArray.showTargetSettingDialog = callback; + break; + case BroadCastType.SHOW_REMIND_TIME_DIALOG: + this.callBackArray.showRemindTimeDialog = callback; + break; + case BroadCastType.SHOW_FREQUENCY_DIALOG: + this.callBackArray.showFrequencyDialog = callback; + break; + default: + break; + } } - public off(event, callback) { - if (event == null) { + public off(event: string, callback: Function) { + if (event === null) { Logger.info(FILE_TAG, 'cancel all broadcast'); - this.callBackArray = {}; + this.callBackArray = callBackArrayTemp; } Logger.info(FILE_TAG, 'cancel broadcast with type '+ event); - const cbs = this.callBackArray[event]; + const cbs = this.callBackArray; if (!cbs) { return; } - if (callback == null) { - this.callBackArray[event] = null; + if (callback === null) { + switch (event) { + case BroadCastType.SHOW_ACHIEVEMENT_DIALOG: + this.callBackArray.showAchievementDialog = () => {}; + break; + case BroadCastType.SHOW_TASK_DETAIL_DIALOG: + this.callBackArray.showTaskDetailDialog = () => {}; + break; + case BroadCastType.SHOW_TARGET_SETTING_DIALOG: + this.callBackArray.showTargetSettingDialog = () => {}; + break; + case BroadCastType.SHOW_REMIND_TIME_DIALOG: + this.callBackArray.showRemindTimeDialog = () => {}; + break; + case BroadCastType.SHOW_FREQUENCY_DIALOG: + this.callBackArray.showFrequencyDialog = () => {}; + break; + default: + break; + } } - - cbs.splice(cbs.indexOf(callback), 1); } - public emit(event, args?: any[]) { - let _self = this; - if (!this.callBackArray[event]) { + public emit(event: string, args?: (number | number[] | (TaskInfo | CustomDialogCallback)[])) { + if (!this.callBackArray) { Logger.info(FILE_TAG, 'emit broadcast failed for no callback'); return; } Logger.info(FILE_TAG, 'emit broadcast with type '+ event); - let cbs = [...this.callBackArray[event]]; + let cbs: Array = []; + switch (event) { + case BroadCastType.SHOW_ACHIEVEMENT_DIALOG: + cbs = [this.callBackArray.showAchievementDialog]; + break; + case BroadCastType.SHOW_TASK_DETAIL_DIALOG: + cbs = [this.callBackArray.showTaskDetailDialog]; + break; + case BroadCastType.SHOW_TARGET_SETTING_DIALOG: + cbs = [this.callBackArray.showTargetSettingDialog]; + break; + case BroadCastType.SHOW_REMIND_TIME_DIALOG: + cbs = [this.callBackArray.showRemindTimeDialog]; + break; + case BroadCastType.SHOW_FREQUENCY_DIALOG: + cbs = [this.callBackArray.showFrequencyDialog]; + break; + default: + break; + } if (cbs) { let len = cbs.length; for (let i = 0; i < len; i++) { try { - cbs[i].apply(_self, args); - } catch (e) { - new Error(e); + if (args instanceof Array) { + cbs[i](args[0], args[1]); + } else { + cbs[i](args); + } + } catch (error) { + new Error(error); } } } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/GlobalContext.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..677db0cb7cce13a483f076991499a50d7fcdae94 --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/GlobalContext.ets @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { } + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/HealthDataSrcMgr.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/HealthDataSrcMgr.ets index 47bdf1e1ac9ab0cc382451b1f56280e8efcff758..6519bc327e5e32652617857e14c984210b6b93bb 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/HealthDataSrcMgr.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/HealthDataSrcMgr.ets @@ -27,10 +27,11 @@ export class HealthDataSrcMgr { } public static getInstance(): HealthDataSrcMgr { - if (AppStorage.Get(APP_KEY_GROUP_DATA_SOURCE_MANAGER) == null) { - AppStorage.SetOrCreate(APP_KEY_GROUP_DATA_SOURCE_MANAGER, new HealthDataSrcMgr()); + if (!AppStorage.Get(APP_KEY_GROUP_DATA_SOURCE_MANAGER)) { + AppStorage.SetOrCreate(APP_KEY_GROUP_DATA_SOURCE_MANAGER, new HealthDataSrcMgr()); } - return AppStorage.Get(APP_KEY_GROUP_DATA_SOURCE_MANAGER); + let healthDataSrcMgr = AppStorage.Get(APP_KEY_GROUP_DATA_SOURCE_MANAGER); + return healthDataSrcMgr ? healthDataSrcMgr : new HealthDataSrcMgr(); } public getBroadCast(): BroadCast { diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/Logger.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/Logger.ets index b508de57f459ac61159c1b9c937badd34cc2aa7d..9ee77c71f0f220a0fd79b68fa2bf6fa4d36eedb7 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/Logger.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/Logger.ets @@ -36,19 +36,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/Utils.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/Utils.ets index 4c185a9f636b19921976a0c82241e3b912fa4606..fc388072801759696fa8fbda04dd48ca12f7fca1 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/Utils.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/common/utils/Utils.ets @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { FrequencyContentType } from '../../model/TaskInitList'; const CHINESE_OF_WEEK: string[] = ['一', '二', '三', '四', '五', '六', '日']; const YEAR: string = '年'; @@ -22,10 +23,10 @@ const DAYS_OF_WEEK: number = 7; const SUNDAY_FIRST_SHIFT: number = 6; export const weekTitleFunc = () => { - const weekTitleArr = []; - CHINESE_OF_WEEK.forEach((item, index) => { + const weekTitleArr: Array = []; + for (let index = 0;index < CHINESE_OF_WEEK.length; index++) { weekTitleArr.push(CHINESE_OF_WEEK[(index + SUNDAY_FIRST_SHIFT) % DAYS_OF_WEEK]); // Sunday is the first day - }); + } return weekTitleArr; } @@ -73,22 +74,22 @@ export function ratio2percent(ratio: number): string { } export const frequencyRange = () => { - const frequencyRangeArr = [] + const frequencyRangeArr: FrequencyContentType[] = []; CHINESE_OF_WEEK.forEach((item, index) => { frequencyRangeArr.push({ id: (index + 1), label: `${WEEK}${item}`, isChecked: false - }) + } as FrequencyContentType) }); return frequencyRangeArr; } export const oneWeekDictFunc = () => { - const oneWeekDict = {}; - CHINESE_OF_WEEK.forEach((item, index) => { - oneWeekDict[index + 1] = `${WEEK}${CHINESE_OF_WEEK[index]}`; - }); + const oneWeekDict: Array = []; + for (let index = 0;index < CHINESE_OF_WEEK.length; index++) { + oneWeekDict[index] = `${WEEK}${CHINESE_OF_WEEK[index]}`; + } return oneWeekDict; } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/entryability/EntryAbility.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/entryability/EntryAbility.ets index 5a5058be3b83799ad97d02cae26ce6ffb7cc1a83..1abb282739805cfe6141e68faea6567fa1352e68 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/entryability/EntryAbility.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/entryability/EntryAbility.ets @@ -14,74 +14,78 @@ */ import UIAbility from '@ohos.app.ability.UIAbility'; -import { RDB_NAME, DAY_INFO, GLOBAL_INFO, TASK_INFO } from '../common/constants/CommonConstants'; -import { columnDayInfos, columnGlobalInfos, columnTaskInfoInfos } from '../model/RdbColumnModel'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; +import { + columnDayInfoList, + columnGlobalInfoList, + columnTaskInfoInfoList, + columnFormInfoList +} from '../model/RdbColumnModel'; import RdbUtils from '../common/database/rdb/RdbUtils'; +import Logger from '../common/utils/Logger'; +import Want from '@ohos.app.ability.Want'; +import window from '@ohos.window'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; +import { GlobalContext } from '../common/utils/GlobalContext'; +export default class EntryAbility extends UIAbility { + private static TAG: string = 'EntryAbility'; -export default class MainAbility extends UIAbility { - private static TAG: string = 'MainAbility'; + async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { + GlobalContext.getContext().setObject('want', want); + GlobalContext.getContext().setObject('launchParam', launchParam); - async onCreate(want, launchParam) { - console.debug(MainAbility.TAG, 'onCreate'); - globalThis.abilityWant = want; - - RdbUtils.initDb(this.context, RDB_NAME.dbname); + RdbUtils.initDb(this.context, Const.RDB_NAME.dbName ? Const.RDB_NAME.dbName : ''); await RdbUtils.createDb(); - RdbUtils.createTable(DAY_INFO.tableName, columnDayInfos).then(() => { - console.log(`RdbHelper createTable dayInfo success`); - }).catch(err => { - console.log(`RdbHelper dayInfo err : ${JSON.stringify(err)}`); + RdbUtils.createTable(Const.DAY_INFO.tableName ? Const.DAY_INFO.tableName : '', columnDayInfoList).then(() => { + Logger.info(`RdbHelper createTable dayInfo success`); + }).catch((err: Error) => { + Logger.error(`RdbHelper dayInfo err : ${JSON.stringify(err)}`); }); - RdbUtils.createTable(GLOBAL_INFO.tableName, columnGlobalInfos).then(() => { - console.log(`RdbHelper createTable globalInfo success`); - }).catch(err => { - console.log(`RdbHelper globalInfo err : ${JSON.stringify(err)}`); + RdbUtils.createTable(Const.GLOBAL_INFO.tableName ? Const.GLOBAL_INFO.tableName : '', columnGlobalInfoList).then(() => { + Logger.info(`RdbHelper createTable globalInfo success`); + }).catch((err: Error) => { + Logger.error(`RdbHelper globalInfo err : ${JSON.stringify(err)}`); }); - RdbUtils.createTable(TASK_INFO.tableName, columnTaskInfoInfos).then(() => { - console.log(`RdbHelper createTable taskInfo success`); - }).catch(err => { - console.log(`RdbHelper taskInfo err : ${JSON.stringify(err)}`); + RdbUtils.createTable(Const.TASK_INFO.tableName ? Const.TASK_INFO.tableName : '', columnTaskInfoInfoList).then(() => { + Logger.info(`RdbHelper createTable taskInfo success`); + }).catch((err: Error) => { + Logger.error(`RdbHelper taskInfo err : ${JSON.stringify(err)}`); }); + RdbUtils.createTable(Const.FORM_INFO.tableName ? Const.FORM_INFO.tableName : '', columnFormInfoList) + .catch((err: Error) => { + Logger.error(`RdbHelper formInfo err : ${JSON.stringify(err)}`); + }); } - onDestroy() { - console.debug(MainAbility.TAG, 'onDestroy'); - } - - onWindowStageCreate(windowStage) { + onWindowStageCreate(windowStage: window.WindowStage) { // Main window is created, set main page for this ability - console.debug(MainAbility.TAG, 'onWindowStageCreate'); - windowStage.loadContent("pages/SplashPage", (err, data) => { + GlobalContext.getContext().setObject('isForeground', true); + windowStage.loadContent('pages/SplashPage', (err, data) => { if (err.code) { - console.error('windowStage', 'Failed to load the content. Cause:' + JSON.stringify(err)); + Logger.error('windowStage', 'Failed to load the content. Cause:' + JSON.stringify(err)); return; } - console.info('windowStage', 'Succeeded in loading the content. Data: ' + JSON.stringify(data)); + Logger.info('windowStage', 'Succeeded in loading the content. Data: ' + JSON.stringify(data)); }); } - onWindowStageDestroy() { - // Main window is destroyed, release UI related resources - console.debug(MainAbility.TAG, 'onWindowStageDestroy'); - } - onForeground() { // Ability has brought to foreground - globalThis.isForeground = true; - console.debug(MainAbility.TAG, 'onForeground'); + GlobalContext.getContext().setObject('isForeground', true); + GlobalContext.getContext().setObject('taskListChange', false); } onBackground() { // Ability has back to background - console.debug(MainAbility.TAG, 'onBackground'); + // FormUtils.backgroundUpdateCard(GlobalContext.getContext().getObject('taskListChange') as boolean); } - onNewWant(want, launchParam) { + onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) { // Ability has new want - console.debug(MainAbility.TAG, `onNewWant ${JSON.stringify(want)}`); - globalThis.abilityWant = want; + GlobalContext.getContext().setObject('abilityWant', want); + GlobalContext.getContext().setObject('launchParam', launchParam); } }; diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/model/AchieveModel.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/model/AchieveModel.ets index b6e850675962fd4bd903a34d1b8929f4e25a4194..5eab21c74a303dc581961b4c7ae3fe11ac839940 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/model/AchieveModel.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/model/AchieveModel.ets @@ -14,13 +14,13 @@ */ import { ACHIEVEMENT_LEVEL_LIST } from './TaskInitList'; -import GlobalInfo from '../common/bean/GlobalInfo'; +import GlobalInfo from '../viewmodel/GlobalInfo'; import GlobalInfoApi from '../common/database/tables/GlobalInfoApi'; export const ACHIEVEMENT_LEVEL_KEY = 'AchievementLevelKey'; export function getAchievementLevel() { - GlobalInfoApi.query((res) => { + GlobalInfoApi.query((res: GlobalInfo) => { let globalInfo: GlobalInfo = res; let achievementStr = globalInfo.achievements??''; diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/model/DatabaseModel.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/model/DatabaseModel.ets index 0fee4bb0995dc78fe21bb0c3b159ee1513ff651f..f8ee5f7d50bf3942aa73b8015e624a41c925d992 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/model/DatabaseModel.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/model/DatabaseModel.ets @@ -13,37 +13,36 @@ * limitations under the License. */ -import { GLOBAL_KEY, TASK_NUM } from '../common/constants/CommonConstants'; -import DayInfo from '../common/bean/DayInfo'; -import GlobalInfo from '../common/bean/GlobalInfo'; -import TaskInfo from '../common/bean/TaskInfo'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; +import DayInfo from '../viewmodel/DayInfo'; +import GlobalInfo from '../viewmodel/GlobalInfo'; +import TaskInfo from '../viewmodel/TaskInfo'; import DayInfoApi from '../common/database/tables/DayInfoApi'; import GlobalInfoApi from '../common/database/tables/GlobalInfoApi'; import TaskInfoApi from '../common/database/tables/TaskInfoApi'; import Logger from '../common/utils/Logger'; export class DatabaseModel { - /** * Init when open the app * * @param date * @param callback */ - query(date: string, callback) { - let result = []; + query(date: string, callback: Function) { + let result: TaskInfo[] = []; let self = this; - GlobalInfoApi.query(function (globalResult) { - if (globalResult.length === 0) { // if global information is not found, it is written - let globalInfo = new GlobalInfo(date, date, 0, ''); - GlobalInfoApi.insertData(globalInfo, (isDone) => { + GlobalInfoApi.query((globalResult: GlobalInfo) => { + if (!globalResult.firstDate) { // if global information is not found, it is written + let globalInfo: GlobalInfo = new GlobalInfo(date, date, 0, ''); + GlobalInfoApi.insertData(globalInfo, (isDone: number) => { if (isDone) { Logger.info('AppStart', 'Insert globalInfo success: ' + JSON.stringify(globalInfo)); } }); self.insertGlobalTask(); - let dayInfo = new DayInfo(date, 0, 0); - DayInfoApi.insertData(dayInfo, (isDone) => { + let dayInfo: DayInfo = new DayInfo(date, 0, 0); + DayInfoApi.insertData(dayInfo, (isDone: number) => { if (isDone) { Logger.info('AppStart', 'Insert dayInfo success: ' + JSON.stringify(dayInfo)); } @@ -54,20 +53,20 @@ export class DatabaseModel { let newGlobalInfo = globalResult; let preDate = globalResult.lastDate; newGlobalInfo.lastDate = date; - GlobalInfoApi.updateData(newGlobalInfo, (isDone) => { + GlobalInfoApi.updateData(newGlobalInfo, (isDone: number) => { if (isDone) { Logger.info('AppStart', 'update globalInfo success: ' + JSON.stringify(newGlobalInfo)); } }); - self.queryPreInfo(self, date, preDate, result, callback); + self.queryPreInfo(date, preDate, result, callback); } }); } insertGlobalTask() { - for (let i = 0; i < TASK_NUM; i++) { - let tmp = new TaskInfo(0, GLOBAL_KEY, i + 1, '', false, '08: 00', '00: 00', '1,2,3,4,5,6,7', false, ''); - TaskInfoApi.insertData(tmp, (isDone) => { + for (let i = 0; i < Const.TASK_NUM; i++) { + let tmp = new TaskInfo(0, Const.GLOBAL_KEY, i + 1, '', false, '08: 00', '00: 00', '1,2,3,4,5,6,7', false, ''); + TaskInfoApi.insertData(tmp, (isDone: number) => { if (isDone) { Logger.info('AppStart', 'Insert taskGlobalInfo success: ' + JSON.stringify(tmp)); } @@ -75,10 +74,10 @@ export class DatabaseModel { } } - insertTask(date) { - for (let i = 0; i < TASK_NUM; i++) { + insertTask(date: string) { + for (let i = 0; i < Const.TASK_NUM; i++) { let tmp = new TaskInfo(0, date, i + 1, '', false, '08: 00', '00: 00', '1,2,3,4,5,6,7', false, ''); - TaskInfoApi.insertData(tmp, (isDone) => { + TaskInfoApi.insertData(tmp, (isDone: number) => { if (isDone) { Logger.info('AppStart', 'Insert taskInfo success: ' + JSON.stringify(tmp)); } @@ -86,9 +85,9 @@ export class DatabaseModel { } } - queryPreInfo(self, date, preDate, result, callback) { - TaskInfoApi.query(date, false, async (taskResult) => { // query the task information for the day - let dayInfo = new DayInfo(date, 0, 0); + queryPreInfo(date: string, preDate: string, result: TaskInfo[], callback: Function) { + TaskInfoApi.query(date, false, async (taskResult: TaskInfo[]) => { // query the task information for the day + let dayInfo: DayInfo = new DayInfo(date, 0, 0); if (taskResult.length === 0) { // if task information for the day is not found, the global task information is queried let curDate = new Date(preDate); curDate.setDate(curDate.getDate() + 1); @@ -96,50 +95,50 @@ export class DatabaseModel { let finDate = new Date(date); finDate.setDate(finDate.getDate() + 1); Logger.info('AppStart', 'insert data end: ' + finDate.toDateString()) - TaskInfoApi.query(GLOBAL_KEY, false, async (globalTaskResult) => { + TaskInfoApi.query(Const.GLOBAL_KEY, false, async (globalTaskResult: TaskInfo[]) => { result = globalTaskResult; - dayInfo.targetTaskNum = self.calTaskNum(result); - self.insertPreInfo(curDate, finDate, result, dayInfo); - let finResult = [] + dayInfo.targetTaskNum = this.calTaskNum(result); + this.insertPreInfo(curDate, finDate, result, dayInfo); + let finResult: TaskInfo[] = []; for (let i = 0; i < 6; i++) { - if (result[i].isOpen == true) { + if (result[i].isOpen === true) { finResult.push(result[i]); } } callback(finResult, dayInfo); }) } else { - let dayInfoList = self.calFinishNum(taskResult, result); - dayInfo.targetTaskNum = dayInfoList[0]; - dayInfo.finTaskNum = dayInfoList[1]; + let dayInfoList: DayInfo = this.calFinishNum(taskResult, result); + dayInfo.targetTaskNum = dayInfoList.targetTaskNum; + dayInfo.finTaskNum = dayInfoList.finTaskNum; callback(result, dayInfo); } }); } - calTaskNum(result) { + calTaskNum(result: TaskInfo[]) { let taskNum = 0; - for (let i = 0; i < TASK_NUM; i++) { - if (result[i].isOpen) { + for (let i = 0; i < Const.TASK_NUM; i++) { + if (result[i]?.isOpen) { taskNum += 1; } } return taskNum; } - insertPreInfo(curDate, finDate, result, dayInfo) { + insertPreInfo(curDate: Date, finDate: Date, result: TaskInfo[], dayInfo: DayInfo) { while (curDate.toDateString() !== finDate.toDateString()) { dayInfo.date = curDate.toDateString(); - DayInfoApi.insertData(dayInfo, (isDone) => { + DayInfoApi.insertData(dayInfo, (isDone: number) => { if (isDone) { Logger.info('AppStart', 'insert dayInfo success: ' + JSON.stringify(dayInfo)); } }) - for (let i = 0; i < TASK_NUM; i++) { + for (let i = 0; i < Const.TASK_NUM; i++) { let tmp = new TaskInfo(0, '', 0, '', false, '', '', '', false, ''); tmp = result[i]; tmp.date = curDate.toDateString(); - TaskInfoApi.insertData(tmp, (isDone) => { + TaskInfoApi.insertData(tmp, (isDone: number) => { if (isDone) { Logger.info('AppStart', 'insert taskInfo success: ' + JSON.stringify(tmp)); } @@ -147,13 +146,12 @@ export class DatabaseModel { } curDate.setDate(curDate.getDate() + 1); } - } - calFinishNum(taskResult, result) { + calFinishNum(taskResult: TaskInfo[], result: TaskInfo[]) { let taskNum = 0; let finishNum = 0; - for (let i = 0; i < TASK_NUM; i++) { + for (let i = 0; i < Const.TASK_NUM; i++) { if (taskResult[i].isOpen) { result.push(taskResult[i]); taskNum += 1; @@ -162,7 +160,7 @@ export class DatabaseModel { } } } - return [taskNum, finishNum]; + return new DayInfo('', taskNum, finishNum); } } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/model/Mine.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/model/Mine.ets index e5fe3e6dd74f0eb27f6b677fd816823a30ab023d..e05ced75f4d676032fce0496164a51d3fc92c611 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/model/Mine.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/model/Mine.ets @@ -22,7 +22,7 @@ export interface InfoItem { export const MineInfoList: InfoItem[] = [ { id: '1', - title: $r("app.string.mine_personal_data") + title: $r('app.string.mine_personal_data') }, { id: '2', diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/model/RdbColumnModel.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/model/RdbColumnModel.ets index 88520fb79d78fa97702c07df2c30139f7e814987..fa56842d47ff1556149f93a04bff7f1a871ff70b 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/model/RdbColumnModel.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/model/RdbColumnModel.ets @@ -13,98 +13,40 @@ * limitations under the License. */ -import ColumnInfo from '../common/bean/ColumnInfo'; +import ColumnInfo from '../viewmodel/ColumnInfo'; -export const columnGlobalInfos: Array = [ - { - name: 'id', - type: 'integer', - primary: true, - nullable: true - }, - { - name: 'firstDate', - type: 'text' - }, - { - name: 'lastDate', - type: 'text' - }, - { - name: 'checkInDays', - type: 'integer', - nullable: true - }, - { - name: 'achievements', - type: 'text' - }]; +export const columnGlobalInfoList: Array = [ + new ColumnInfo('id', 'integer', -1, true, true, false), + new ColumnInfo('firstDate', 'text', -1, false, false, false), + new ColumnInfo('lastDate', 'text', -1, false, false, false), + new ColumnInfo('checkInDays', 'integer', -1, true, false, false), + new ColumnInfo('achievements', 'text', -1, false, false, false) +]; + +export const columnDayInfoList: Array = [ + new ColumnInfo('date', 'text', -1, false, true, false), + new ColumnInfo('targetTaskNum', 'integer', -1, true, false, false), + new ColumnInfo('finTaskNum', 'integer', -1, true, false, false) +]; -export const columnDayInfos: Array = [ - { - name: 'date', - type: 'text', - primary: true - }, - { - name: 'targetTaskNum', - type: 'integer', - nullable: true - }, - { - name: 'finTaskNum', - type: 'integer', - nullable: true - }]; +export const columnTaskInfoInfoList: Array = [ + new ColumnInfo('id', 'integer', -1, false, true, true), + new ColumnInfo('date', 'TEXT', -1, false, false, false), + new ColumnInfo('taskID', 'integer', -1, false, false, false), + new ColumnInfo('targetValue', 'text', -1, false, false, false), + new ColumnInfo('isAlarm', 'boolean', -1, false, false, false), + new ColumnInfo('startTime', 'text', -1, false, false, false), + new ColumnInfo('endTime', 'text', -1, false, false, false), + new ColumnInfo('frequency', 'text', -1, false, false, false), + new ColumnInfo('isDone', 'boolean', -1, true, false, false), + new ColumnInfo('finValue', 'text', -1, false, false, false), + new ColumnInfo('isOpen', 'boolean', -1, true, false, false) +]; -export const columnTaskInfoInfos: Array = [ - { - name: 'id', - type: 'integer', - primary: true, - autoincrement: true - }, - { - name: 'date', - type: 'TEXT' - }, - { - name: 'taskID', - type: 'integer' - }, - { - name: 'targetValue', - type: 'text' - }, - { - name: 'isAlarm', - type: 'boolean' - }, - { - name: 'startTime', - type: 'text' - }, - { - name: 'endTime', - type: 'text' - }, - { - name: 'frequency', - type: 'text' - }, - { - name: 'isDone', - type: 'boolean', - nullable: true - }, - { - name: 'finValue', - type: 'text' - }, - { - name: 'isOpen', - type: 'boolean', - nullable: true - } +export const columnFormInfoList: Array = [ + new ColumnInfo('id', 'integer', -1, true, true, false), + new ColumnInfo('formId', 'text', -1, false, false, false), + new ColumnInfo('formName', 'text', -1, false, false, false), + new ColumnInfo('formDimension', 'integer', -1, false, false, false) ]; diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/model/TaskInitList.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/model/TaskInitList.ets index 54553ea3c5af29fe5286f3144f8d2f6c3a9a5566..6ba81470e4a8d59c8eb0ade7960d2a16d83fb406 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/model/TaskInitList.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/model/TaskInitList.ets @@ -12,22 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import AchievementMapInfo from '../viewmodel/AchievementMapInfo'; -import TaskInfo from '../common/bean/TaskInfo'; -import { - GET_UP_TASK_NAME, - DRINK_TASK_NAME, - EAT_APPLE_TASK_NAME, - SMILE_TASK_NAME, - BRUSH_TEETH_TASK_NAME, - SLEEP_TASK_NAME, - GET_UP_CONTENT, - DRINK_CONTENT, - EAT_APPLE_CONTENT, - SMILE_CONTENT, - BRUSH_TEETH_CONTENT, - SLEEP_CONTENT -} from '../common/constants/CommonConstants'; +import TaskInfo from '../viewmodel/TaskInfo'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; export interface ITaskItem { taskID: number; @@ -45,8 +33,9 @@ export interface ITaskItem { step: number; } -export interface TaskInitListType { - [key: number]: ITaskItem; +export interface RemindContentItem { + title: string; + content: string; } export interface FrequencyContentType { @@ -56,104 +45,19 @@ export interface FrequencyContentType { } export const TaskList: TaskInfo[] = [ - { - id: 0, - taskID: 1, - isOpen: true, - date: '', - targetValue: '7:00', - isAlarm: true, - startTime: '', - endTime: ';', - frequency: '', - isDone: false, - finValue: '' - }, - { - id: 1, - taskID: 2, - isOpen: true, - date: '', - targetValue: '1.5', - isAlarm: true, - startTime: '', - endTime: ';', - frequency: '', - isDone: false, - finValue: '' - }, - { - id: 2, - taskID: 3, - isOpen: true, - date: '', - targetValue: '3', - startTime: '08: 00', - endTime: '', - isAlarm: true, - frequency: '', - isDone: false, - finValue: '' - }, - { - id: 3, - taskID: 4, - isOpen: true, - date: '', - targetValue: '1', - isAlarm: true, - startTime: '', - endTime: ';', - frequency: '', - isDone: false, - finValue: '' - }, - { - id: 4, - taskID: 5, - isOpen: true, - date: '', - targetValue: '21:30', - isAlarm: true, - startTime: '', - endTime: ';', - frequency: '', - isDone: false, - finValue: '' - }, - { - id: 5, - taskID: 6, - isOpen: true, - date: '', - targetValue: '22:00', - isAlarm: true, - startTime: '', - endTime: ';', - frequency: '', - isDone: false, - finValue: '' - } + new TaskInfo(0, '', 1, '7:00', true, '', ';', '', false, '', true), + new TaskInfo(1, '', 2, '1.5', true, '', ';', '', false, '', true), + new TaskInfo(2, '', 3, '3', true, '08: 00', '', '', false, '', true), + new TaskInfo(3, '', 4, '1', true, '', ';', '', false, '', true), + new TaskInfo(4, '', 5, '21:30', true, '', ';', '', false, '', true), + new TaskInfo(5, '', 6, '22:00', true, '', ';', '', false, '', true) ] -export const AchievementMap = { - '3_off': $r('app.media.ic_badge_3_off'), - '3_on': $r('app.media.ic_badge_3_on'), - '7_off': $r('app.media.ic_badge_7_off'), - '7_on': $r('app.media.ic_badge_7_on'), - '30_off': $r('app.media.ic_badge_30_off'), - '30_on': $r('app.media.ic_badge_30_on'), - '50_off': $r('app.media.ic_badge_50_off'), - '50_on': $r('app.media.ic_badge_50_on'), - '73_off': $r('app.media.ic_badge_73_off'), - '73_on': $r('app.media.ic_badge_73_on'), - '99_off': $r('app.media.ic_badge_99_off'), - '99_on': $r('app.media.ic_badge_99_on') -} - +let achievementMap = new AchievementMapInfo(); +export const AchievementMap = achievementMap; -export const TaskMapById: TaskInitListType = { - 1: { +export const TaskMapById: Array = [ + { taskID: 1, taskName: $r('app.string.task_morning'), icon: $r("app.media.ic_task_morning"), @@ -168,7 +72,7 @@ export const TaskMapById: TaskInitListType = { endTime: '00: 00', frequency: '1, 2, 3, 4, 5, 6, 7' }, - 2: { + { taskID: 2, taskName: $r('app.string.task_water'), icon: $r("app.media.ic_task_water"), @@ -183,7 +87,7 @@ export const TaskMapById: TaskInitListType = { endTime: '00: 00', frequency: '1, 2, 3, 4, 5, 6, 7' }, - 3: { + { taskID: 3, taskName: $r('app.string.task_apple'), icon: $r("app.media.ic_task_apple"), @@ -198,7 +102,7 @@ export const TaskMapById: TaskInitListType = { endTime: '00: 00', frequency: '1, 2, 3, 4, 5, 6, 7' }, - 4: { + { taskID: 4, taskName: $r('app.string.task_smile'), icon: $r("app.media.ic_task_smile"), @@ -213,7 +117,7 @@ export const TaskMapById: TaskInitListType = { endTime: '00: 00', frequency: '1, 2, 3, 4, 5, 6, 7' }, - 5: { + { taskID: 5, taskName: $r('app.string.task_brush'), icon: $r("app.media.ic_task_brush"), @@ -228,7 +132,7 @@ export const TaskMapById: TaskInitListType = { endTime: '00: 00', frequency: '1, 2, 3, 4, 5, 6, 7' }, - 6: { + { taskID: 6, taskName: $r('app.string.task_night'), icon: $r("app.media.ic_task_night"), @@ -243,47 +147,35 @@ export const TaskMapById: TaskInitListType = { endTime: '00: 00', frequency: '1, 2, 3, 4, 5, 6, 7' } -} +] -export const TaskItem: TaskInfo = { - id: 1, - taskID: 0, - isOpen: false, - date: '', - targetValue: '7:00', - isAlarm: true, - startTime: 'string', - endTime: 'string;', - frequency: '', - isDone: true, - finValue: '6:58' -}; +export const TaskItem = new TaskInfo(1, '', 0, '7:00', true, 'string', 'string;', '', true, '6:58', false); -export const RemindContentMap = { - 1: { - title: GET_UP_TASK_NAME, - content: GET_UP_CONTENT - }, - 2: { - title: DRINK_TASK_NAME, - content: DRINK_CONTENT +export const RemindContentMap: Array = [ + { + title: Const.GET_UP_TASK_NAME, + content: Const.GET_UP_CONTENT }, - 3: { - title: EAT_APPLE_TASK_NAME, - content: EAT_APPLE_CONTENT + { + title: Const.DRINK_TASK_NAME, + content: Const.DRINK_CONTENT }, - 4: { - title: SMILE_TASK_NAME, - content: SMILE_CONTENT + { + title: Const.EAT_APPLE_TASK_NAME, + content: Const.EAT_APPLE_CONTENT }, - 5: { - title: BRUSH_TEETH_TASK_NAME, - content: BRUSH_TEETH_CONTENT + { + title: Const.SMILE_TASK_NAME, + content: Const.SMILE_CONTENT }, - 6: { - title: SLEEP_TASK_NAME, - content: SLEEP_CONTENT + { + title: Const.BRUSH_TEETH_TASK_NAME, + content: Const.BRUSH_TEETH_CONTENT }, -}; + { + title: Const.SLEEP_TASK_NAME, + content: Const.SLEEP_CONTENT + } +]; export const ACHIEVEMENT_LEVEL_LIST = [3, 7, 30, 50, 73, 99]; \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/model/WeekCalendarModel.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/model/WeekCalendarModel.ets index 536ed3ceab9a44c2ad9228467950101c3fc34077..61c835414ee8ff033643787b97efcea6496276d2 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/model/WeekCalendarModel.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/model/WeekCalendarModel.ets @@ -13,10 +13,11 @@ * limitations under the License. */ -import TaskInfo from '../common/bean/TaskInfo'; -import DayInfo from '../common/bean/DayInfo'; +import TaskInfo from '../viewmodel/TaskInfo'; +import DayInfo from '../viewmodel/DayInfo'; import { WEEK_TITLES, dateToStr } from '../common/utils/Utils' import Logger from '../common/utils/Logger' +import WeekCalendarInfo from '../viewmodel/WeekCalendarInfo'; // day number of on week export const WEEK_DAY_NUM: number = 7; @@ -25,7 +26,7 @@ export class WeekDateModel { weekTitle: string; dateStr: string; date: Date; - dayInfo: DayInfo; + dayInfo: DayInfo = new DayInfo('', 0, 0); taskList: TaskInfo[] = []; constructor(weekTitle: string, dateStr: string, date: Date) { @@ -40,8 +41,10 @@ export class WeekDateModel { * * @param date today str */ -export function initializeOnStartUp(date: Date): [Array, Array] { - let [arr, strArr] = [[], []]; // getPreviousWeek(date); +export function initializeOnStartUp(date: Date): WeekCalendarInfo { + let weekCalendarInfo: WeekCalendarInfo = new WeekCalendarInfo(); + let arr: Array = []; + let strArr: Array = []; let currentDay = date.getDay() - 1; if (date.getDay() === 0) { currentDay = 6; @@ -57,7 +60,9 @@ export function initializeOnStartUp(date: Date): [Array, Array, Array, Array] { - Logger.debug('WeekCalendarModel', 'get week date by date: ' + showDate.toDateString()) +export function getPreviousWeek(showDate: Date): WeekCalendarInfo { + Logger.debug('WeekCalendarModel', 'get week date by date: ' + showDate.toDateString()); + let weekCalendarInfo: WeekCalendarInfo = new WeekCalendarInfo(); let arr: Array = []; let strArr: Array = []; let currentDay = showDate.getDay() - 1; @@ -77,9 +83,11 @@ export function getPreviousWeek(showDate: Date): [Array, Array).editTask as ITaskItem : {} as ITaskItem; @State editedTaskID: string = '0'; @State homeStore: HomeStore = new HomeStore(new Date()); private tabController: TabsController = new TabsController(); + aboutToAppear() { + notificationManager.requestEnableNotification().then(() => { + Logger.info('onPageShow', `requestEnableNotification success`); + }).catch((err: Error) => { + Logger.error('onPageShow', `requestEnableNotification failed, message is ${err.message}`); + }); + } + onPageShow() { Logger.info('onPageShow', JSON.stringify(router.getParams())); - this.editedTaskInfo = JSON.parse(router.getParams() ? router.getParams()['editTask'] : '{}'); - this.editedTaskID = `${this.editedTaskInfo.taskID}_${this.editedTaskInfo.isOpen}` + new Date().getTime(); - if (globalThis.isForeground) { - globalThis.isForeground = false; - if (this.homeStore.currentDate.getDate()!== (new Date()).getDate()) { + let params = (router.getParams() ? router.getParams() : {}) as Record; + let result = params.editTask ? params.editTask as string : '{}'; + this.editedTaskInfo = JSON.parse(result); + this.editedTaskID = JSON.stringify(this.editedTaskInfo); + if ((GlobalContext.getContext().getObject('isForeground') as boolean)) { + GlobalContext.getContext().setObject('isForeground', false); + if (this.homeStore.currentDate.getDate() !== (new Date()).getDate()) { + GlobalContext.getContext().setObject('taskListChange', true); this.homeStore = new HomeStore(new Date()); - this.homeStore.initData(); } + this.checkCurrentTime(); } } + checkCurrentTime() { + GlobalInfoApi.query((result: GlobalInfo) => { + let predate = new Date(result.lastDate); + let date = new Date(); + if (result && date.getTime() < predate.getTime()) { + AlertDialog.show( + { + title: $r('app.string.alert'), + message: $r('app.string.alert_message'), + autoCancel: false, + alignment: DialogAlignment.Bottom, + offset: { dx: 0, dy: -20 }, + gridCount: 3, + confirm: { + value: $r('app.string.alert_button'), + action: () => { + (getContext(this) as common.UIAbilityContext).terminateSelf(); + console.info('Button-clicking callback'); + } + }, + cancel: () => { + console.info('Closed callbacks'); + } + }); + } else { + this.homeStore.initData(); + } + }); + } + @Builder TabBuilder(index: number) { Column() { - Image(index == this.currentPage ? NavList[index].icon_selected : NavList[index].icon) + Image(index === this.currentPage ? NavList[index].icon_selected : NavList[index].icon) .width($r('app.float.default_24')) .height($r('app.float.default_24')) .objectFit(ImageFit.Contain); Text(NavList[index].text) .fontSize($r('app.float.default_10')) - .fontWeight(commonConst.FONT_WEIGHT_500) + .fontWeight(Const.FONT_WEIGHT_500) .fontColor(this.currentPage === index ? $r('app.color.blueColor') : $r('app.color.tabTitleColor')) .margin({ top: $r('app.float.default_4') }) }.justifyContent(FlexAlign.Center).allSize() @@ -67,7 +113,7 @@ struct MainPage { build() { Tabs({ barPosition: BarPosition.End, controller: this.tabController }) { TabContent() { - HomeIndex({homeStore: $homeStore, editedTaskInfo: $editedTaskInfo, editedTaskID: $editedTaskID }) + HomeIndex({ homeStore: $homeStore, editedTaskInfo: $editedTaskInfo, editedTaskID: $editedTaskID }) .borderWidth({ bottom: 1 }) .borderColor($r('app.color.primaryBgColor')) } @@ -88,7 +134,7 @@ struct MainPage { } .scrollable(false) .allSize() - .barWidth(commonConst.THOUSANDTH_940) + .barWidth(Const.THOUSANDTH_940) .barMode(BarMode.Fixed) .vertical(false) .onChange((index) => { diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/pages/MinePage.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/pages/MinePage.ets index 1bcc8a0600a0dca48d8e00c7b0939a97cee79ae5..2e5052878affc45a594ff490d50bfae89a8f708d 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/pages/MinePage.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/pages/MinePage.ets @@ -15,12 +15,12 @@ import { ListInfo } from '../view/ListInfo'; import { UserBaseInfo } from '../view/UserBaseInfo'; -import { NICK_NAME, SIGNATURE, FULL_HEIGHT } from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; @Component export struct MineIndex { - @State nickname: string = NICK_NAME; - @State signature: string = SIGNATURE; + @State nickname: string = Const.NICK_NAME; + @State signature: string = Const.SIGNATURE; build() { Column() { @@ -31,7 +31,7 @@ export struct MineIndex { ListInfo(); } - .height(FULL_HEIGHT) + .height(Const.FULL_HEIGHT) .backgroundColor($r('app.color.mineBgColor')) } } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/pages/SplashPage.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/pages/SplashPage.ets index d0b6a7c2e823f8b1af262888e1cf721abd01e897..f3f4d75806de1b643f15897f255362caf1dcdcbd 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/pages/SplashPage.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/pages/SplashPage.ets @@ -18,7 +18,7 @@ import common from '@ohos.app.ability.common'; import router from '@ohos.router'; import data_preferences from '@ohos.data.preferences'; import Logger from '../common/utils/Logger'; -import * as commonConst from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; import UserPrivacyDialog from '../view/dialog/UserPrivacyDialog'; // app preferences name @@ -32,13 +32,13 @@ struct SplashIndex { dialogController: CustomDialogController = new CustomDialogController({ builder: UserPrivacyDialog( { - cancel: this.exitApp.bind(this), - confirm: this.onConfirm.bind(this) + cancel: () => { this.exitApp() }, + confirm: () => { this.onConfirm() } }), - cancel: this.exitApp.bind(this), + cancel: () => { this.exitApp() }, autoCancel: false, alignment: DialogAlignment.Bottom, - offset: { dx: 0, dy: commonConst.OFFSET_24 } + offset: { dx: 0, dy: Const.OFFSET_24 } }); onConfirm() { @@ -47,7 +47,7 @@ struct SplashIndex { res.put(IS_PRIVACY, true).then(() => { res.flush(); Logger.info('SplashPage','isPrivacy is put success'); - }).catch((err) => { + }).catch((err: Error) => { Logger.info('SplashPage','isPrivacy put failed. Cause:' + err); }); }) @@ -61,7 +61,7 @@ struct SplashIndex { jumpAdPage() { setTimeout(() => { router.replaceUrl({ url: 'pages/AdvertisingPage' }); - }, commonConst.LAUNCHER_DELAY_TIME); + }, Const.LAUNCHER_DELAY_TIME); } aboutToAppear() { @@ -87,21 +87,21 @@ struct SplashIndex { .width($r('app.float.default_120')) .aspectRatio(1) .margin({ top: $r('app.float.default_120') }); - Text($r('app.string.MainAbility_label')) + Text($r('app.string.EntryAbility_label')) .fontFamily($r('app.string.HarmonyHeiTi_Bold')) .fontSize($r('app.float.default_24')) .fontColor($r('app.color.titleColor')) - .fontWeight(commonConst.FONT_WEIGHT_700) - .letterSpacing(commonConst.LETTER_1) + .fontWeight(Const.FONT_WEIGHT_700) + .letterSpacing(Const.LETTER_1) .margin({ top: $r('app.float.default_20'), bottom: $r('app.float.default_8') }) - Text($r('app.string.MainAbility_desc')) + Text($r('app.string.EntryAbility_desc')) .fontFamily($r('app.string.HarmonyHeiTi')) .fontColor($r('app.color.titleColor')) - .fontWeight(commonConst.FONT_WEIGHT_400) - .letterSpacing(commonConst.LETTER_34) - .opacity(commonConst.OPACITY_6) + .fontWeight(Const.FONT_WEIGHT_400) + .letterSpacing(Const.LETTER_34) + .opacity(Const.OPACITY_6) .fontSize($r('app.float.default_16')) } .width('100%') diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/pages/TaskEditPage.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/pages/TaskEditPage.ets index 4c6d39940677edcebf062ba543cbcd1d9cd53195..e928d7a4e2170173b6693f858a307ed2c3eca407 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/pages/TaskEditPage.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/pages/TaskEditPage.ets @@ -14,7 +14,7 @@ */ import TaskDetail from '../view/task/TaskDetailComponent'; -import { THOUSANDTH_1000, EDIT_TASK_TITLE } from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; @Entry @Component @@ -25,14 +25,14 @@ struct TaskEdit { Column() { TaskDetail() } - .width(THOUSANDTH_1000) - .height(THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) + .height(Const.THOUSANDTH_1000) } - .size({ width: THOUSANDTH_1000, height: THOUSANDTH_1000 }) - .title(EDIT_TASK_TITLE) + .size({ width: Const.THOUSANDTH_1000, height: Const.THOUSANDTH_1000 }) + .title(Const.EDIT_TASK_TITLE) .titleMode(NavigationTitleMode.Mini) } - .height(THOUSANDTH_1000) + .height(Const.THOUSANDTH_1000) .backgroundColor($r('app.color.primaryBgColor')) } } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/pages/TaskListPage.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/pages/TaskListPage.ets index 9606d7c2b88a6cb55a4a12669f3e4e10074eb30c..cd04eaa95ca11771fd9506d5a3eb88e2912c8d78 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/pages/TaskListPage.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/pages/TaskListPage.ets @@ -15,8 +15,9 @@ import { ITaskItem } from '../model/TaskInitList'; import TaskList from '../view/task/TaskListComponent'; -import { THOUSANDTH_1000, ADD_TASK_TITLE } from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; import { getAllTask, taskIndexDataInit, taskOriginData } from '../viewmodel/TaskViewModel'; +import TaskInfo from '../viewmodel/TaskInfo'; @Entry @Component @@ -25,9 +26,9 @@ struct TaskIndex { @Provide taskList: ITaskItem[] = taskOriginData; onPageShow() { - getAllTask().then(res => { - let deepCopyData = JSON.stringify(this.taskList); - deepCopyData = JSON.parse(deepCopyData); + getAllTask().then((res: TaskInfo[]) => { + let deepCopyDataStr = JSON.stringify(this.taskList); + let deepCopyData: ITaskItem[] = JSON.parse(deepCopyDataStr); this.taskList = taskIndexDataInit(deepCopyData, res); }) } @@ -38,14 +39,14 @@ struct TaskIndex { Column() { TaskList() } - .width(THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.Center) } - .size({ width: THOUSANDTH_1000, height: THOUSANDTH_1000 }) - .title(ADD_TASK_TITLE) + .size({ width: Const.THOUSANDTH_1000, height: Const.THOUSANDTH_1000 }) + .title(Const.ADD_TASK_TITLE) .titleMode(NavigationTitleMode.Mini) } .backgroundColor($r('app.color.primaryBgColor')) - .height(THOUSANDTH_1000) + .height(Const.THOUSANDTH_1000) } } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/service/ReminderAgent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/service/ReminderAgent.ets new file mode 100644 index 0000000000000000000000000000000000000000..6f23992c37e3157a606f50d72f8e3de1f4ed3ea3 --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/service/ReminderAgent.ets @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import reminderAgent from '@ohos.reminderAgentManager'; +import notification from '@ohos.notificationManager'; +import preferences from '@ohos.data.preferences'; +import Logger from '../common/utils/Logger'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; +import ReminderInfo from '../viewmodel/ReminderInfo'; +import PublishReminderInfo from '../viewmodel/PublishReminderInfo'; + +// publishReminder +function publishReminder(params: PublishReminderInfo, context: Context) { + if (!params) { + Logger.error(Const.REMINDER_AGENT_TAG, 'publishReminder params is empty'); + return; + } + let notifyId: string = params.notificationId.toString(); + hasPreferencesValue(context, notifyId, (preferences: preferences.Preferences, hasValue: boolean) => { + if (hasValue) { + preferences.get(notifyId, -1, (error: Error, value: preferences.ValueType) => { + if (typeof value !== 'number') { + return; + } + if (value >= 0) { + reminderAgent.cancelReminder(value).then(() => { + processReminderData(params, preferences, notifyId); + }).catch((err: Error) => { + Logger.error(Const.REMINDER_AGENT_TAG, `cancelReminder err: ${err}`); + }); + } else { + Logger.error(Const.REMINDER_AGENT_TAG, 'preferences get value error ' + JSON.stringify(error)); + } + }); + } else { + processReminderData(params, preferences, notifyId); + } + }); +} + +// cancelReminder +function cancelReminder(reminderId: number, context: Context) { + if (!reminderId) { + Logger.error(Const.REMINDER_AGENT_TAG, 'cancelReminder reminderId is empty'); + return; + } + let reminder: string = reminderId.toString(); + hasPreferencesValue(context, reminder, (preferences: preferences.Preferences, hasValue: boolean) => { + if (!hasValue) { + Logger.error(Const.REMINDER_AGENT_TAG, 'cancelReminder preferences value is empty'); + return; + } + getPreferencesValue(preferences, reminder); + }); +} + +// hasNotificationId +function hasNotificationId(params: number) { + if (!params) { + Logger.error(Const.REMINDER_AGENT_TAG, 'hasNotificationId params is undefined'); + return; + } + return reminderAgent.getValidReminders().then((reminders) => { + if (!reminders.length) { + return false; + } + let notificationIdList: Array = []; + for (let i = 0; i < reminders.length; i++) { + let notificationId = reminders[i].notificationId; + if (notificationId) { + notificationIdList.push(notificationId); + } + } + const flag = notificationIdList.indexOf(params); + + return flag === -1 ? false : true; + }); +} + +function hasPreferencesValue(context: Context, hasKey: string, callback: Function) { + let preferencesPromise = preferences.getPreferences(context, Const.H_STORE); + preferencesPromise.then((preferences: preferences.Preferences) => { + preferences.has(hasKey).then((hasValue: boolean) => { + callback(preferences, hasValue); + }); + }); +} + +// processReminderData +function processReminderData(params: PublishReminderInfo, preferences: preferences.Preferences, notifyId: string) { + let timer = fetchData(params); + reminderAgent.publishReminder(timer).then((reminderId: number) => { + putPreferencesValue(preferences, notifyId, reminderId); + }).catch((err: Error) => { + Logger.error(Const.REMINDER_AGENT_TAG, `publishReminder err: ${err}`); + }); +} + +// fetchData +function fetchData(params: PublishReminderInfo): reminderAgent.ReminderRequestAlarm { + return { + reminderType: reminderAgent.ReminderType.REMINDER_TYPE_ALARM, + hour: params.hour || 0, + minute: params.minute || 0, + daysOfWeek: params.daysOfWeek || [], + wantAgent: { + pkgName: Const.PACKAGE_NAME, + abilityName: Const.ENTRY_ABILITY + }, + title: params.title || '', + content: params.content || '', + notificationId: params.notificationId || -1, + slotType: notification.SlotType.SOCIAL_COMMUNICATION + } +} + +function putPreferencesValue(preferences: preferences.Preferences, putKey: string, putValue: number) { + preferences.put(putKey, putValue).then(() => { + preferences.flush(); + }).catch((error: Error) => { + Logger.error(Const.REMINDER_AGENT_TAG, 'preferences put value error ' + JSON.stringify(error)); + }); +} + +function getPreferencesValue(preferences: preferences.Preferences, getKey: string) { + preferences.get(getKey, -1).then((value: preferences.ValueType) => { + if (typeof value !== 'number') { + return; + } + if (value >= 0) { + reminderAgent.cancelReminder(value).then(() => { + Logger.info(Const.REMINDER_AGENT_TAG, 'cancelReminder promise success'); + }).catch((err: Error) => { + Logger.error(Const.REMINDER_AGENT_TAG, `cancelReminder err: ${err}`); + }); + } + }).catch((error: Error) => { + Logger.error(Const.REMINDER_AGENT_TAG, 'preferences get value error ' + JSON.stringify(error)); + }); +} + +const reminder = { + publishReminder: publishReminder, + cancelReminder: cancelReminder, + hasNotificationId: hasNotificationId +} as ReminderInfo + +export default reminder; \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/AchievementComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/AchievementComponent.ets index 01231c1da468b5c47e8154fd2814baf491af0391..0f350517dffceb9a7c60d52b9346263bd9da2977 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/AchievementComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/AchievementComponent.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import * as commonConst from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; import { BadgePanel } from './BadgePanelComponent'; import { TitleBar } from './TitleBarComponent'; import Logger from '../common/utils/Logger'; @@ -29,13 +29,13 @@ export struct AchievementIndex { } build() { - Column({space: commonConst.DEFAULT_20}) { + Column({space: Const.DEFAULT_20}) { TitleBar() BadgePanel() } - .padding(commonConst.DEFAULT_10) - .height(commonConst.FULL_HEIGHT) - .width(commonConst.FULL_WIDTH) + .padding(Const.DEFAULT_10) + .height(Const.FULL_HEIGHT) + .width(Const.FULL_WIDTH) .backgroundColor($r('app.color.black')) } } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/BadgeCardComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/BadgeCardComponent.ets index c0ce7a2cb0e3022eaf23aad2055db4c2026aa9d5..cedf46926faaf28fc133874055de44b7b2fde9e1 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/BadgeCardComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/BadgeCardComponent.ets @@ -14,25 +14,25 @@ */ import { ratio2percent } from '../common/utils/Utils' -import * as commonConst from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; @Component export struct BadgeCard { - @Prop content: string; - imgSrc: Resource; + @Prop content: string = ''; + imgSrc: Resource = $r('app.string.empty'); build() { - Column({space: commonConst.DEFAULT_18}) { + Column({space: Const.DEFAULT_18}) { Image(this.imgSrc) - .width(commonConst.FULL_WIDTH) - .height(commonConst.ACHIEVE_CARD_IMG_HEIGHT) + .width(Const.FULL_WIDTH) + .height(Const.ACHIEVE_CARD_IMG_HEIGHT) .objectFit(ImageFit.Contain) Text($r('app.string.task_achievement_level', Number(this.content))) .lineHeight($r('app.float.default_16')) .fontSize($r('app.float.default_12')) .fontColor($r('app.color.white')) } - .width(ratio2percent(commonConst.ACHIEVE_SPLIT_RATIO)) - .padding({top: commonConst.ACHIEVE_CARD_TOP, bottom: commonConst.ACHIEVE_CARD_BOTTOM}) + .width(ratio2percent(Const.ACHIEVE_SPLIT_RATIO)) + .padding({top: Const.ACHIEVE_CARD_TOP, bottom: Const.ACHIEVE_CARD_BOTTOM}) } } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/BadgePanelComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/BadgePanelComponent.ets index 398498daa843816b10ae0c9792409c1ae27a84f4..a73f328766768b6b484f0159a4851a92c26cc016 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/BadgePanelComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/BadgePanelComponent.ets @@ -18,23 +18,24 @@ import { getAchievementLevel} from '../model/AchieveModel' import { getBadgeCardItems } from '../viewmodel/AchievementViewModel' import Logger from '../common/utils/Logger' import { ACHIEVEMENT_LEVEL_KEY } from '../model/AchieveModel' -import * as commonConst from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; +import CardInfo from '../viewmodel/CardInfo' @Component export struct BadgePanel { @StorageProp(ACHIEVEMENT_LEVEL_KEY) successiveDays: number = 0; aboutToAppear() { - Logger.debug('BadgePanel','aboutToAppear') - getAchievementLevel() + Logger.debug('BadgePanel','aboutToAppear'); + getAchievementLevel(); } build() { Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) { - ForEach(getBadgeCardItems(this.successiveDays), (item) => { - BadgeCard({ content: item[0], imgSrc: item[1]}) + ForEach(getBadgeCardItems(this.successiveDays), (item: CardInfo) => { + BadgeCard({ content: item.titleContent, imgSrc: item.achievement}) }) } - .width(commonConst.FULL_WIDTH) + .width(Const.FULL_WIDTH) } } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/HealthTextComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/HealthTextComponent.ets index eb47a07015e300589330753e3f489422d3e25d58..6621f1056fdd18f63df68d3707d249777df9bbf2 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/HealthTextComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/HealthTextComponent.ets @@ -13,14 +13,14 @@ * limitations under the License. */ -import * as commonConst from '../common/constants/CommonConstants' +import { CommonConstants as Const } from '../common/constants/CommonConstants' @Component export default struct HealthText { - @Prop title: string; - titleResource: Resource; + @Prop title: string = ''; + titleResource: Resource = $r('app.string.empty'); fontSize: number | string | Resource = $r('app.float.default_16'); - fontWeight: number | FontWeight | string = commonConst.FONT_WEIGHT_500; + fontWeight: number | FontWeight | string = Const.FONT_WEIGHT_500; fontColor: ResourceColor = $r('app.color.titleColor'); fontFamily: string | Resource = $r('app.string.HarmonyHeiTi_Medium'); diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/HomeComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/HomeComponent.ets index 2d8c1d0567eeca6f397ff921d0388dd3ab3bb3f5..9b24de59152671fd2b6ccd527e74ae857d5a5d9c 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/HomeComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/HomeComponent.ets @@ -13,38 +13,39 @@ * limitations under the License. */ -import common from '@ohos.app.ability.common'; import router from '@ohos.router'; import HealthText from './HealthTextComponent'; import AddBtn from '../view/home/AddBtnComponent'; import { TaskCard } from '../view/home//TaskCardComponent'; import HomeTopView from '../view/home/HomeTopComponent'; import { CustomDialogView, CustomDialogCallback } from '../view/dialog/CustomDialogView'; -import TaskInfo from '../common/bean/TaskInfo'; -import GlobalInfoApi from '../common/database/tables/GlobalInfoApi'; +import TaskInfo from '../viewmodel/TaskInfo'; import { HomeStore } from '../viewmodel/HomeViewModel'; import { ITaskItem, TaskMapById } from '../model/TaskInitList'; import { HealthDataSrcMgr } from '../common/utils/HealthDataSrcMgr'; import { BroadCast, BroadCastType } from '../common/utils/BroadCast'; -import * as commonConst from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; +import AchievementInfo from '../viewmodel/AchievementInfo'; const WHITE_COLOR_0X = 255; -@Styles function allSize() { - .width(commonConst.THOUSANDTH_1000) - .height(commonConst.THOUSANDTH_1000) +@Styles +function allSize() { + .width(Const.THOUSANDTH_1000) + .height(Const.THOUSANDTH_1000) } -@Extend(Text) function titleTextStyle() { +@Extend(Text) +function titleTextStyle() { .fontSize($r('app.float.default_16')) - .fontWeight(commonConst.FONT_WEIGHT_500) - .width(commonConst.THOUSANDTH_1000) + .fontWeight(Const.FONT_WEIGHT_500) + .width(Const.THOUSANDTH_1000) .fontFamily($r('app.string.HarmonyHeiTi_Medium')) .fontColor($r(`app.element.color.titleColor`)) .padding({ - top: commonConst.THOUSANDTH_15, - bottom: commonConst.THOUSANDTH_15, - left: commonConst.THOUSANDTH_33 + top: Const.THOUSANDTH_15, + bottom: Const.THOUSANDTH_15, + left: Const.THOUSANDTH_33 }) } @@ -56,79 +57,57 @@ export default struct HomeIndex { @Link editedTaskInfo: ITaskItem; @Link @Watch('taskChange') editedTaskID: string; private scroller: Scroller = new Scroller(); - - async aboutToAppear() { - GlobalInfoApi.query((result) => { - let predate = new Date(result.lastDate); - let date = new Date(); - if (result.length !== 0 && date.getTime() < predate.getTime()) { - AlertDialog.show( - { - title: $r('app.string.alert'), - message: $r('app.string.alert_message'), - autoCancel: false, - alignment: DialogAlignment.Bottom, - offset: { dx: 0, dy: -20 }, - gridCount: 3, - confirm: { - value: $r('app.string.alert_button'), - action: () => { - (getContext(this) as common.UIAbilityContext).terminateSelf() - console.info('Button-clicking callback') - } - }, - cancel: () => { - console.info('Closed callbacks') - } - }) - } else { - this.homeStore.initData(); - } - }); - } + private yOffset: number = 0; taskChange() { this.homeStore.updateTaskInfoList(this.editedTaskInfo); } - taskItemAction(item: TaskInfo, isClick: boolean) { + taskItemAction(item: TaskInfo, isClick: boolean): void { if (!this.homeStore.checkCurrentDay()) { return; } if (isClick) { // click to clock - let callback: CustomDialogCallback = { confirmCallback: this.onConfirm.bind(this), cancelCallback: null }; + let callback: CustomDialogCallback = { confirmCallback: (taskTemp: TaskInfo) => { + this.onConfirm(taskTemp) + }, cancelCallback: () => { + } }; this.broadCast.emit(BroadCastType.SHOW_TASK_DETAIL_DIALOG, [item, callback]); } else { // edit task - const editTask: ITaskItem = { - ...TaskMapById[item.taskID], - targetValue: item?.targetValue, - isAlarm: item.isAlarm, - startTime: item.startTime, - frequency: item.frequency, - isOpen: item.isOpen, - }; + let editTaskStr: string = JSON.stringify(TaskMapById[item.taskID - 1]); + let editTask: ITaskItem = JSON.parse(editTaskStr); + editTask.targetValue = item?.targetValue; + editTask.isAlarm = item.isAlarm; + editTask.startTime = item.startTime; + editTask.frequency = item.frequency; + editTask.isOpen = item.isOpen; router.pushUrl({ url: 'pages/TaskEditPage', params: { params: JSON.stringify(editTask) } }); } } //confirm clockL - onConfirm(task) { - this.homeStore.taskClock(task).then((res) => { + onConfirm(task: TaskInfo) { + this.homeStore.taskClock(task).then((res: AchievementInfo) => { if (res.showAchievement) { - this.broadCast.emit(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, [res.achievementLevel]); + let achievementLevel = res.achievementLevel; + if (achievementLevel) { + this.broadCast.emit(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, achievementLevel); + } else { + this.broadCast.emit(BroadCastType.SHOW_ACHIEVEMENT_DIALOG); + } } }) } // change navigator alpha when scrolling the Scroll component onScrollAction() { - let yOffset = this.scroller.currentOffset().yOffset; - if (yOffset > commonConst.DEFAULT_56) { + this.yOffset = this.scroller.currentOffset().yOffset; + if (this.yOffset > Const.DEFAULT_56) { this.naviAlpha = 1; } else { - this.naviAlpha = yOffset / commonConst.DEFAULT_56; + this.naviAlpha = this.yOffset / Const.DEFAULT_56; } } @@ -145,48 +124,55 @@ export default struct HomeIndex { HomeTopView({ homeStore: $homeStore }) Text($r('app.string.task_list')).titleTextStyle() if (this.homeStore.getTaskListOfDay().length > 0) { - Column({ space: commonConst.DEFAULT_8 }) { + Column({ space: Const.DEFAULT_8 }) { ForEach(this.homeStore.getTaskListOfDay(), (item: TaskInfo) => { TaskCard({ taskInfoStr: JSON.stringify(item), - clickAction: (isClick) => this.taskItemAction(item, isClick) + clickAction: (isClick: boolean) => this.taskItemAction(item, isClick) }) - .margin({ bottom: commonConst.DEFAULT_12 }) + .margin({ bottom: Const.DEFAULT_12 }) .height($r('app.float.default_64')) - }, item => JSON.stringify(item)) + }, (item: TaskInfo) => JSON.stringify(item)) } + .onAppear(() => { + this.scroller.scrollTo({ xOffset: 0, yOffset: this.yOffset }); + }) .padding({ - top: commonConst.THOUSANDTH_15, - left: commonConst.THOUSANDTH_33, - right: commonConst.THOUSANDTH_33 + top: Const.THOUSANDTH_15, + left: Const.THOUSANDTH_33, + right: Const.THOUSANDTH_33 }) - .width(commonConst.THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) } else { - Column({ space: commonConst.DEFAULT_8 }) { + Column({ space: Const.DEFAULT_8 }) { Image($r('app.media.ic_no_data')) .width($r('app.float.default_132')) .height($r('app.float.default_100')); HealthText({ title: '', titleResource: $r('app.string.no_task'), fontSize: $r('app.float.default_14') }) - .opacity(commonConst.OPACITY_4) + .opacity(Const.OPACITY_4) } - .margin({ top: commonConst.DEFAULT_48 }) + .margin({ top: Const.DEFAULT_48 }) } } } .scrollBar(BarState.Off) .allSize() - .onScroll(this.onScrollAction.bind(this)) + .onScroll(() => { + this.onScrollAction() + }) .align(Alignment.TopStart) - AddBtn({ clickAction: this.editTaskAction.bind(this) }) + AddBtn({ clickAction: () => { + this.editTaskAction() + } }) Row() { - Text($r('app.string.MainAbility_label')) + Text($r('app.string.EntryAbility_label')) .titleTextStyle() .fontSize($r('app.float.default_24')) - .padding({ left: commonConst.THOUSANDTH_66 }) + .padding({ left: Const.THOUSANDTH_66 }) } - .width(commonConst.THOUSANDTH_1000) - .height(commonConst.DEFAULT_56) + .width(Const.THOUSANDTH_1000) + .height(Const.DEFAULT_56) .position({ x: 0, y: 0 }) .backgroundColor(`rgba(${WHITE_COLOR_0X},${WHITE_COLOR_0X},${WHITE_COLOR_0X},${this.naviAlpha})`) diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/ListInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/ListInfo.ets index eadb26e4a7b5b6a00c4ea60f4553c62007c85e98..83471e5232e8599b0f8cddf7861755dccb2f071d 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/ListInfo.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/ListInfo.ets @@ -42,7 +42,7 @@ export struct ListInfo { color: $r('app.color.borderColor') }) - }, item => item.id); + }, (item: InfoItem) => JSON.stringify(item)); } .border({ radius: { diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/TitleBarComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/TitleBarComponent.ets index 51f8637bf7e0e03fe7aae97b17a314adc6a5d4ea..b6badf8ad3596bca89e1f302f0389a261e98c735 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/TitleBarComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/TitleBarComponent.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as commonConst from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; @Component export struct TitleBar { @@ -22,8 +22,8 @@ export struct TitleBar { .fontSize($r('app.float.default_24')) .fontColor($r('app.color.white')) .align(Alignment.Start) - .padding({left: commonConst.ACHIEVE_TITLE_BAR_LEFT,top: commonConst.ACHIEVE_TITLE_BAR_TOP}) + .padding({left: Const.ACHIEVE_TITLE_BAR_LEFT,top: Const.ACHIEVE_TITLE_BAR_TOP}) } - .width(commonConst.FULL_WIDTH) + .width(Const.FULL_WIDTH) } } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/UserBaseInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/UserBaseInfo.ets index 4cdc6952436204983bb42b3bea034ea7e77fadc5..72dfed84c33f93225e7d0f182412628489798628 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/UserBaseInfo.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/UserBaseInfo.ets @@ -15,13 +15,13 @@ @Component export struct UserBaseInfo { - @Prop nickname: string; - @Prop signature: string; + @Prop nickname: string = ''; + @Prop signature: string = ''; build() { Column() { // userIcon - Image($r("app.media.ic_user")) + Image($r('app.media.ic_user')) .objectFit(ImageFit.Contain) .height($r('app.float.default_66')) .width($r('app.float.default_66')) diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/AchievementDialog.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/AchievementDialog.ets index 2bc5c63dd5ba0611fea6574ce030aedff2229472..cadb5d614e66421413bc7353223da9702761ef82 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/AchievementDialog.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/AchievementDialog.ets @@ -13,36 +13,62 @@ * limitations under the License. */ -import * as commonConst from '../../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; import { AchievementMap } from '../../model/TaskInitList'; const ANGLE_LARGE = 360; @CustomDialog export struct AchievementDialog { - controller: CustomDialogController; + controller: CustomDialogController = new CustomDialogController({ builder: 0 }); @Consume achievementLevel: number; @State private opacityValue: number = 0; @State private angle: number = 0; @State private scaleValue: number = 0; + @State achievementMapValue: Resource = $r('app.string.empty'); + + aboutToAppear() { + switch (this.achievementLevel) { + case 3: + this.achievementMapValue = AchievementMap.on_3; + break; + case 7: + this.achievementMapValue = AchievementMap.on_7; + break; + case 30: + this.achievementMapValue = AchievementMap.on_30; + break; + case 50: + this.achievementMapValue = AchievementMap.on_50; + break; + case 73: + this.achievementMapValue = AchievementMap.on_73; + break; + case 99: + this.achievementMapValue = AchievementMap.on_99; + break; + default: + break; + } + } build() { Column() { - Image(AchievementMap[`${this.achievementLevel}_on`]) - .width(commonConst.THOUSANDTH_560) - .height(commonConst.THOUSANDTH_400) + Image(this.achievementMapValue) + .width(Const.THOUSANDTH_560) + .height(Const.THOUSANDTH_400) .objectFit(ImageFit.Contain) Text($r('app.string.task_achievement_level', this.achievementLevel)) .fontSize($r('app.float.default_24')) - .fontWeight(commonConst.FONT_WEIGHT_500) + .fontWeight(Const.FONT_WEIGHT_500) .fontColor($r('app.color.white')) .fontFamily($r('app.string.HarmonyHeiTi')) .margin({ top: $r('app.float.default_12') }) } - .height(commonConst.THOUSANDTH_800) - .width(commonConst.THOUSANDTH_1000) + .height(Const.THOUSANDTH_800) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.Center) .gesture(TapGesture().onAction(() => { this.controller.close(); @@ -52,9 +78,9 @@ export struct AchievementDialog { .opacity(this.opacityValue) .onAppear(() => { animateTo({ - duration: commonConst.DURATION_800, + duration: Const.DURATION_800, curve: Curve.EaseOut, - delay: commonConst.DURATION_100, + delay: Const.DURATION_100, iterations: 1 }, () => { this.opacityValue = 1; diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/CustomDialogView.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/CustomDialogView.ets index df2a48d324dc0de4067485f0a66b6cfeaac4dccd..81116ae09186872f4896587a91f061b6f3e41483 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/CustomDialogView.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/CustomDialogView.ets @@ -17,12 +17,12 @@ import { AchievementDialog } from './AchievementDialog'; import { TaskDetailDialog } from './TaskDetailDialog'; import { BroadCast, BroadCastType } from '../../common/utils/BroadCast'; import { TaskItem } from '../../model/TaskInitList'; -import TaskInfo from '../../common/bean/TaskInfo'; +import TaskInfo from '../../viewmodel/TaskInfo'; import Logger from '../../common/utils/Logger'; -export interface CustomDialogCallback { - confirmCallback: Function; - cancelCallback: Function; +export class CustomDialogCallback { + confirmCallback: Function = () => {}; + cancelCallback: Function = () => {}; } @Component @@ -31,17 +31,17 @@ export struct CustomDialogView { @Provide achievementLevel: number = 0; @Consume broadCast: BroadCast; @Provide currentTask: TaskInfo = TaskItem; - @Provide dialogCallBack: CustomDialogCallback = { confirmCallback: null, cancelCallback: null }; + @Provide dialogCallBack: CustomDialogCallback = new CustomDialogCallback(); // achievement dialog - achievementDialog = new CustomDialogController({ + achievementDialog: CustomDialogController = new CustomDialogController({ builder: AchievementDialog(), autoCancel: true, customStyle: true }); // task clock dialog - taskDialog = new CustomDialogController({ + taskDialog: CustomDialogController = new CustomDialogController({ builder: TaskDetailDialog(), autoCancel: true, customStyle: true @@ -54,7 +54,7 @@ export struct CustomDialogView { Logger.debug('CustomDialogView', 'SHOW_ACHIEVEMENT_DIALOG'); this.achievementLevel = achievementLevel; this.achievementDialog.open(); - }) + }); // task clock dialog this.broadCast.on(BroadCastType.SHOW_TASK_DETAIL_DIALOG, @@ -63,7 +63,7 @@ export struct CustomDialogView { this.currentTask = currentTask || TaskItem; this.dialogCallBack = dialogCallBack; this.taskDialog.open(); - }) + }); } aboutToDisappear() { diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskDetailDialog.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskDetailDialog.ets index 36c80b61394e4589e29c15dcb6c1af1a26bbd853..ac55eb8650c6c05f43930cabc55940dd1f6a83fa 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskDetailDialog.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskDetailDialog.ets @@ -14,9 +14,10 @@ */ import { CustomDialogCallback } from './CustomDialogView'; -import TaskInfo from '../../common/bean/TaskInfo'; +import TaskInfo from '../../viewmodel/TaskInfo'; import { TaskMapById } from '../../model/TaskInitList'; -import { DEFAULT_8, DEFAULT_12 } from '../../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; +import { GlobalContext } from '../../common/utils/GlobalContext'; @Extend(Text) function textStyle () { .fontColor($r('app.color.white')) @@ -30,7 +31,7 @@ import { DEFAULT_8, DEFAULT_12 } from '../../common/constants/CommonConstants'; @CustomDialog export struct TaskDetailDialog { - controller: CustomDialogController; + controller: CustomDialogController = new CustomDialogController({ builder: '' }); @Consume currentTask: TaskInfo; @State showButton: boolean = true; @Consume dialogCallBack: CustomDialogCallback; @@ -38,7 +39,7 @@ export struct TaskDetailDialog { build() { Column() { TaskBaseInfo({ - taskName: TaskMapById[this.currentTask?.taskID].taskName + taskName: TaskMapById[this.currentTask?.taskID - 1].taskName }); TaskClock({ @@ -54,7 +55,7 @@ export struct TaskDetailDialog { } .height($r('app.float.default_451')) .width($r('app.float.default_316')) - .backgroundImage(TaskMapById[this.currentTask?.taskID].dialogBg, ImageRepeat.NoRepeat) + .backgroundImage(TaskMapById[this.currentTask?.taskID - 1].dialogBg, ImageRepeat.NoRepeat) .backgroundImageSize({ width: '100%', height: '100%' @@ -69,10 +70,10 @@ export struct TaskDetailDialog { @Component struct TaskBaseInfo { - taskName: string | Resource; + taskName: string | Resource = ''; build() { - Column({ space: DEFAULT_8 }) { + Column({ space: Const.DEFAULT_8 }) { Text(this.taskName) .fontSize($r('app.float.default_22')) .fontWeight(FontWeight.Bold) @@ -86,12 +87,12 @@ struct TaskBaseInfo { @Component struct TaskClock { - confirm: () => void; - cancel: () => void; + confirm: Function = () => {}; + cancel: Function = () => {}; showButton: boolean = false; build() { - Column({ space: DEFAULT_12 }) { + Column({ space: Const.DEFAULT_12 }) { Button() { Text($r('app.string.clock_in')) .height($r('app.float.default_42')) @@ -103,6 +104,7 @@ struct TaskClock { .borderRadius($r('app.float.default_24')) .backgroundColor('rgba(255,255,255,0.40)') .onClick(() => { + GlobalContext.getContext().setObject('taskListChange', true); this.confirm(); }) .visibility(!this.showButton ? Visibility.None : Visibility.Visible) diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskDialogView.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskDialogView.ets index deae9a4cbd343e9c2fdb214d0d11423dcceac64f..f248b3712929c4992ee5a2c9ccfe3e99056fb085 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskDialogView.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskDialogView.ets @@ -16,7 +16,7 @@ import { TargetSettingDialog, RemindTimeDialog, FrequencyDialog } from './TaskSettingDialog'; import { BroadCast, BroadCastType } from '../../common/utils/BroadCast'; import Logger from '../../common/utils/Logger'; -import { ZERO, MINUS_20 } from '../../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; export interface CustomDialogCallback { confirmCallback: Function; @@ -29,25 +29,25 @@ export struct TaskDialogView { @Consume broadCast: BroadCast; // target setting dialog - targetSettingDialog = new CustomDialogController({ + targetSettingDialog: CustomDialogController = new CustomDialogController({ builder: TargetSettingDialog(), autoCancel: true, alignment: DialogAlignment.Bottom, - offset: { dx: ZERO, dy: MINUS_20 } + offset: { dx: Const.ZERO, dy: Const.MINUS_20 } }); // remind time dialog RemindTimeDialogController: CustomDialogController = new CustomDialogController({ builder: RemindTimeDialog(), autoCancel: true, alignment: DialogAlignment.Bottom, - offset: { dx: ZERO, dy: MINUS_20 } + offset: { dx: Const.ZERO, dy: Const.MINUS_20 } }); // frequency dialog FrequencyDialogController: CustomDialogController = new CustomDialogController({ builder: FrequencyDialog(), autoCancel: true, alignment: DialogAlignment.Bottom, - offset: { dx: ZERO, dy: MINUS_20 } + offset: { dx: Const.ZERO, dy: Const.MINUS_20 } }); aboutToAppear() { diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskSettingDialog.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskSettingDialog.ets index 6ba3d6ae6bb7c0f2c18b882ee1080730ee9c1a9c..2ac4ab8beb57ce40fa2ad5fc1ca8ea0aee424f5e 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskSettingDialog.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/TaskSettingDialog.ets @@ -17,25 +17,24 @@ import prompt from '@system.prompt'; import { ITaskItem } from '../../model/TaskInitList'; import { frequencyRange } from '../../common/utils/Utils'; import { returnTimeStamp, createAppleRange, createDrinkRange, formatTime } from '../../viewmodel/TaskViewModel'; -import { taskType } from '../../common/bean/TaskInfo'; -import * as commonConst from '../..//common/constants/CommonConstants'; +import { taskType } from '../../viewmodel/TaskInfo'; +import { CommonConstants as Const } from '../..//common/constants/CommonConstants'; import { FrequencyContentType } from '../../model/TaskInitList'; @CustomDialog export struct TargetSettingDialog { @Consume settingParams: ITaskItem; - controller: CustomDialogController; + controller: CustomDialogController = new CustomDialogController({ builder: '' }); drinkRange: string[] = createDrinkRange(); appleRange: string[] = createAppleRange(); currentValue: string = this.settingParams.targetValue; - currentTime: string = commonConst.DEFAULT_TIME; - private tip: string = ''; + currentTime: string = Const.DEFAULT_TIME; compareTime(startTime: string, endTime: string) { if (returnTimeStamp(this.currentTime) < returnTimeStamp(startTime) || - returnTimeStamp(this.currentTime) > returnTimeStamp(endTime)) { + returnTimeStamp(this.currentTime) > returnTimeStamp(endTime)) { prompt.showToast({ - message: commonConst.CHOOSE_TIME_OUT_RANGE + message: Const.CHOOSE_TIME_OUT_RANGE }) return false; } @@ -44,14 +43,14 @@ export struct TargetSettingDialog { setTargetValue() { if (this.settingParams?.taskID === taskType.getup) { - if (!this.compareTime(commonConst.GET_UP_EARLY_TIME, commonConst.GET_UP_LATE_TIME)) { + if (!this.compareTime(Const.GET_UP_EARLY_TIME, Const.GET_UP_LATE_TIME)) { return; } this.settingParams.targetValue = this.currentTime; return; } if (this.settingParams?.taskID === taskType.sleepEarly) { - if (!this.compareTime(commonConst.SLEEP_EARLY_TIME, commonConst.SLEEP_LATE_TIME)) { + if (!this.compareTime(Const.SLEEP_EARLY_TIME, Const.SLEEP_LATE_TIME)) { return; } this.settingParams.targetValue = this.currentTime; @@ -63,106 +62,106 @@ export struct TargetSettingDialog { build() { Column() { Row() { - Text($r('app.string.target_setting')).fontSize(commonConst.DEFAULT_20).margin({ right: commonConst.DEFAULT_12 }) + Text($r('app.string.target_setting')).fontSize(Const.DEFAULT_20).margin({ right: Const.DEFAULT_12 }) Text(this.settingParams?.taskID === taskType.getup ? - commonConst.GET_UP_TIME_RANGE : - this.settingParams?.taskID === taskType.sleepEarly ? - commonConst.SLEEP_TIME_RANGE : '') - .fontSize(commonConst.DEFAULT_16) + Const.GET_UP_TIME_RANGE : + this.settingParams?.taskID === taskType.sleepEarly ? + Const.SLEEP_TIME_RANGE : '') + .fontSize(Const.DEFAULT_16) } - .width(commonConst.THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.Start) - if ([taskType.getup, taskType.sleepEarly].indexOf(this.settingParams?.taskID) > commonConst.HAS_NO_INDEX) { + if ([taskType.getup, taskType.sleepEarly].indexOf(this.settingParams?.taskID) > Const.HAS_NO_INDEX) { TimePicker({ - selected: commonConst.DEFAULT_SELECTED_TIME, + selected: new Date(`${new Date().toDateString()} 8:00:00`), }) - .height(commonConst.THOUSANDTH_800) + .height(Const.THOUSANDTH_800) .useMilitaryTime(true) .onChange((value: TimePickerResult) => { this.currentTime = formatTime(value); }) } else { TextPicker({ range: this.settingParams?.taskID === taskType.drinkWater ? this.drinkRange : this.appleRange }) - .width(commonConst.THOUSANDTH_900,) - .height(commonConst.THOUSANDTH_800,) + .width(Const.THOUSANDTH_900,) + .height(Const.THOUSANDTH_800,) .onChange((value) => { this.currentValue = value?.split(' ')[0]; }) } Row() { - Text($r('app.string.cancel')).fontSize(commonConst.DEFAULT_20).fontColor($r('app.color.blueColor')) + Text($r('app.string.cancel')).fontSize(Const.DEFAULT_20).fontColor($r('app.color.blueColor')) .onClick(() => { - this.currentTime = commonConst.DEFAULT_TIME; + this.currentTime = Const.DEFAULT_TIME; this.currentValue = ''; this.controller.close(); }) - Text($r('app.string.confirm')).fontSize(commonConst.DEFAULT_20).fontColor($r('app.color.blueColor')) + Text($r('app.string.confirm')).fontSize(Const.DEFAULT_20).fontColor($r('app.color.blueColor')) .onClick(() => { this.setTargetValue(); this.controller.close(); }) } .justifyContent(FlexAlign.SpaceAround) - .width(commonConst.THOUSANDTH_1000) - .height(commonConst.DEFAULT_28) - .margin({ bottom: commonConst.DEFAULT_20 }) + .width(Const.THOUSANDTH_1000) + .height(Const.DEFAULT_28) + .margin({ bottom: Const.DEFAULT_20 }) } .justifyContent(FlexAlign.Center) - .height(commonConst.THOUSANDTH_560) - .padding(commonConst.DEFAULT_12) + .height(Const.THOUSANDTH_560) + .padding(Const.DEFAULT_12) } } @CustomDialog export struct RemindTimeDialog { @Consume settingParams: ITaskItem; - controller: CustomDialogController; - currentTime: string = commonConst.DEFAULT_TIME; + controller: CustomDialogController = new CustomDialogController({ builder: '' }); + currentTime: string = Const.DEFAULT_TIME; build() { Column() { Column() { Text($r('app.string.remind_time')) - .fontSize(commonConst.DEFAULT_20) - .margin({ top: commonConst.DEFAULT_10 }) - .width(commonConst.THOUSANDTH_1000) + .fontSize(Const.DEFAULT_20) + .margin({ top: Const.DEFAULT_10 }) + .width(Const.THOUSANDTH_1000) .textAlign(TextAlign.Start) } - .width(commonConst.THOUSANDTH_900) + .width(Const.THOUSANDTH_900) TimePicker({ - selected: commonConst.DEFAULT_SELECTED_TIME, + selected: new Date(`${new Date().toDateString()} 8:00:00`), }) - .height(commonConst.THOUSANDTH_800) + .height(Const.THOUSANDTH_800) .useMilitaryTime(true) .onChange((value: TimePickerResult) => { this.currentTime = formatTime(value); }) Row() { - Text($r('app.string.cancel')).fontSize(commonConst.DEFAULT_20).fontColor($r('app.color.blueColor')) + Text($r('app.string.cancel')).fontSize(Const.DEFAULT_20).fontColor($r('app.color.blueColor')) .onClick(() => { - this.currentTime = commonConst.DEFAULT_TIME; + this.currentTime = Const.DEFAULT_TIME; this.controller.close(); }) - Text($r('app.string.confirm')).fontSize(commonConst.DEFAULT_20).fontColor($r('app.color.blueColor')) + Text($r('app.string.confirm')).fontSize(Const.DEFAULT_20).fontColor($r('app.color.blueColor')) .onClick(() => { this.settingParams.startTime = this.currentTime; this.controller.close(); }) } .justifyContent(FlexAlign.SpaceAround) - .width(commonConst.THOUSANDTH_1000) - .height(commonConst.DEFAULT_28) - .margin({ bottom: commonConst.DEFAULT_20 }) + .width(Const.THOUSANDTH_1000) + .height(Const.DEFAULT_28) + .margin({ bottom: Const.DEFAULT_20 }) } .justifyContent(FlexAlign.Center) - .height(commonConst.THOUSANDTH_560) - .padding(commonConst.DEFAULT_12) + .height(Const.THOUSANDTH_560) + .padding(Const.DEFAULT_12) } } @@ -170,15 +169,15 @@ export struct RemindTimeDialog { export struct FrequencyDialog { @Consume settingParams: ITaskItem; @Consume frequency: string; - private controller: CustomDialogController; - private currentFrequency: string = commonConst.EVERYDAY; + private controller: CustomDialogController = new CustomDialogController({ builder: '' }); + private currentFrequency: string = Const.EVERYDAY; private frequencyChooseRange: FrequencyContentType[] = frequencyRange(); setFrequency() { const checkedArr = this.frequencyChooseRange.filter((item) => item?.isChecked) - if (checkedArr.length === this.frequencyChooseRange.length || checkedArr.length === commonConst.NO_LENGTH) { - this.currentFrequency = commonConst.EVERYDAY; - this.settingParams.frequency = commonConst.INIT_WEEK_IDS; + if (checkedArr.length === this.frequencyChooseRange.length || checkedArr.length === Const.NO_LENGTH) { + this.currentFrequency = Const.EVERYDAY; + this.settingParams.frequency = Const.INIT_WEEK_IDS; return; } this.currentFrequency = checkedArr.reduce((sum, current) => { @@ -193,44 +192,44 @@ export struct FrequencyDialog { Column() { Column() { Text($r('app.string.set_your_frequency')) - .fontSize(commonConst.DEFAULT_20) - .margin({ top: commonConst.DEFAULT_10 }) - .width(commonConst.THOUSANDTH_1000) + .fontSize(Const.DEFAULT_20) + .margin({ top: Const.DEFAULT_10 }) + .width(Const.THOUSANDTH_1000) .textAlign(TextAlign.Start) } - .width(commonConst.THOUSANDTH_900) + .width(Const.THOUSANDTH_900) List() { - ForEach(this.frequencyChooseRange, (item) => { + ForEach(this.frequencyChooseRange, (item: FrequencyContentType) => { ListItem() { Row() { - Text(item?.label).fontSize(commonConst.DEFAULT_20) + Text(item?.label).fontSize(Const.DEFAULT_20) Toggle({ type: ToggleType.Checkbox }) .onChange((isOn) => { item.isChecked = isOn; }) } - .width(commonConst.THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.SpaceBetween) - .height(commonConst.DEFAULT_60) + .height(Const.DEFAULT_60) } - }) + }, (item: FrequencyContentType) => JSON.stringify(item)) } .divider({ - strokeWidth: commonConst.DEFAULT_2, + strokeWidth: Const.DEFAULT_2, color: $r('app.color.btnBgColor') }) .flexGrow(1) - .padding(commonConst.DEFAULT_12) - .width(commonConst.THOUSANDTH_1000) + .padding(Const.DEFAULT_12) + .width(Const.THOUSANDTH_1000) Row() { - Text($r('app.string.cancel')).fontSize(commonConst.DEFAULT_20).fontColor($r('app.color.blueColor')) + Text($r('app.string.cancel')).fontSize(Const.DEFAULT_20).fontColor($r('app.color.blueColor')) .onClick(() => { this.controller.close(); }) - Text($r('app.string.confirm')).fontSize(commonConst.DEFAULT_20).fontColor($r('app.color.blueColor')) + Text($r('app.string.confirm')).fontSize(Const.DEFAULT_20).fontColor($r('app.color.blueColor')) .onClick(() => { this.setFrequency(); this.frequency = this.currentFrequency; @@ -238,12 +237,12 @@ export struct FrequencyDialog { }) } .justifyContent(FlexAlign.SpaceAround) - .width(commonConst.THOUSANDTH_900) - .height(commonConst.DEFAULT_28) - .margin({ bottom: commonConst.DEFAULT_16 }) + .width(Const.THOUSANDTH_900) + .height(Const.DEFAULT_28) + .margin({ bottom: Const.DEFAULT_16 }) } .justifyContent(FlexAlign.Center) - .height(commonConst.THOUSANDTH_900) - .padding(commonConst.DEFAULT_12) + .height(Const.THOUSANDTH_900) + .padding(Const.DEFAULT_12) } } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/UserPrivacyDialog.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/UserPrivacyDialog.ets index 6f27e02c7b49c3858d3481d2300e74f53604aea6..f5d915b9bb02a1b0fe3cfa6457f51934476de7eb 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/UserPrivacyDialog.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/dialog/UserPrivacyDialog.ets @@ -13,23 +13,23 @@ * limitations under the License. */ -import { FONT_WEIGHT_400, OPACITY_6, OPACITY_4,FULL_WIDTH } from '../../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; @Extend(Text) function descStyle () { .fontSize($r('app.float.default_14')) - .fontWeight(FONT_WEIGHT_400) + .fontWeight(Const.FONT_WEIGHT_400) .fontFamily($r('app.string.HarmonyHeiTi')) .fontColor($r(`app.element.color.titleColor`)) - .width(FULL_WIDTH) + .width(Const.FULL_WIDTH) .lineHeight($r('app.float.default_20')) .margin({ top: $r('app.float.default_8') }) } @CustomDialog export default struct UserPrivacyDialog { - controller: CustomDialogController; - cancel: () => void; - confirm: () => void; + controller: CustomDialogController = new CustomDialogController({ builder: '' });; + cancel: Function = () => {}; + confirm: Function = () => {}; build() { Column() { @@ -37,7 +37,7 @@ export default struct UserPrivacyDialog { .descStyle() Text($r('app.string.privacy_desc')) .descStyle() - .opacity(OPACITY_6) + .opacity(Const.OPACITY_6) Row() { Button($r('app.string.cancel')) .backgroundColor(Color.White) @@ -49,7 +49,7 @@ export default struct UserPrivacyDialog { Divider() .vertical(true) .height($r('app.float.default_22')) - .opacity(OPACITY_4) + .opacity(Const.OPACITY_4) Button($r('app.string.sure')) .backgroundColor(Color.White) .fontColor($r('app.color.blueColor')) @@ -58,7 +58,7 @@ export default struct UserPrivacyDialog { this.confirm(); }) } - .width(FULL_WIDTH) + .width(Const.FULL_WIDTH) .margin({ top: $r('app.float.default_22') }) .justifyContent(FlexAlign.SpaceEvenly) } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/AddBtnComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/AddBtnComponent.ets index 62bd1a465a51d4fc112a33d12d8c6fdff0c6adab..83be980035703aca48f4062becdcc23b75371f08 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/AddBtnComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/AddBtnComponent.ets @@ -13,26 +13,26 @@ * limitations under the License. */ -import * as commonConst from '../../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; @Styles function allSize () { - .width(commonConst.THOUSANDTH_1000) - .height(commonConst.THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) + .height(Const.THOUSANDTH_1000) } @Component export default struct AddBtn { - clickAction: Function; + clickAction: Function = () => {}; build() { Button({ type: ButtonType.Circle, stateEffect: false }) { Image($r('app.media.ic_home_add')) .allSize() - .borderRadius(commonConst.BORDER_RADIUS_PERCENT_50) + .borderRadius(Const.BORDER_RADIUS_PERCENT_50) } .onClick(() => this.clickAction()) - .zIndex(commonConst.HOME_BTN_Z) - .position({ x: commonConst.THOUSANDTH_830, y: commonConst.THOUSANDTH_880 }) + .zIndex(Const.HOME_BTN_Z) + .position({ x: Const.THOUSANDTH_830, y: Const.THOUSANDTH_880 }) .width($r('app.float.default_48')) .height($r('app.float.default_48')) } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/HomeTopComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/HomeTopComponent.ets index ebc35a73ff9e860e625a414b569daf79686a9c14..c203b8f522a03034606dd2adfb683fa4612112b9 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/HomeTopComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/HomeTopComponent.ets @@ -15,13 +15,13 @@ import { HomeStore } from '../../viewmodel/HomeViewModel'; import { WeekCalendar } from './WeekCalendarComponent'; -import * as commonConst from '../../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; import HealthText from '../../view/HealthTextComponent'; @Extend(Text) function titleTextStyle () { .fontSize($r('app.float.default_16')) - .fontWeight(commonConst.FONT_WEIGHT_500) - .width(commonConst.THOUSANDTH_1000) + .fontWeight(Const.FONT_WEIGHT_500) + .width(Const.THOUSANDTH_1000) .fontFamily($r('app.string.HarmonyHeiTi_Medium')) .fontColor($r(`app.element.color.titleColor`)) } @@ -34,30 +34,29 @@ export default struct HomeTopView { Column() { Text($r('app.string.target_progress')) .titleTextStyle() - .opacity(commonConst.OPACITY_6) + .opacity(Const.OPACITY_6) .padding({ left: $r('app.float.default_24') }) Row() { HealthText({ title: this.homeStore.getDonePercent(), fontSize: $r('app.float.default_72'), fontFamily: $r('app.string.HarmonyHeiTi_Bold'), - fontWeight: commonConst.FONT_WEIGHT_700 + fontWeight: Const.FONT_WEIGHT_700 }) Text('%') .titleTextStyle() .fontSize($r('app.float.default_40')) .margin({ top: $r('app.float.default_12'), left: $r('app.float.default_8') }) } - .width(commonConst.THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .padding({ left: $r('app.float.default_24') }) WeekCalendar({ homeStore: $homeStore }) } - .width(commonConst.THOUSANDTH_1000) - .aspectRatio(12/11.0) + .height(Const.THOUSANDTH_500) .backgroundImagePosition({x: 0, y: 0}) .backgroundImage($r('app.media.ic_home_bg')) - .backgroundImageSize({ width: commonConst.THOUSANDTH_1000, height: commonConst.THOUSANDTH_900 }) + .backgroundImageSize({ width: Const.THOUSANDTH_1000, height: Const.THOUSANDTH_900 }) .justifyContent(FlexAlign.End) } } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/TaskCardComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/TaskCardComponent.ets index d44a45d0a54ae6f6ddb3af1768accffd82dffab8..e87885db3623630433e47268c795ed5e887762dd 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/TaskCardComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/TaskCardComponent.ets @@ -15,50 +15,56 @@ import { TaskMapById } from '../../model/TaskInitList'; import HealthText from '../../view/HealthTextComponent'; -import * as commonConst from '../../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; +import TaskInfo from '../../viewmodel/TaskInfo'; @Styles function allSize () { - .width(commonConst.THOUSANDTH_1000) - .height(commonConst.THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) + .height(Const.THOUSANDTH_1000) } @Extend(Text) function labelTextStyle () { .fontSize($r('app.float.default_16')) - .fontWeight(commonConst.FONT_WEIGHT_500) - .opacity(commonConst.OPACITY_6) + .fontWeight(Const.FONT_WEIGHT_500) + .opacity(Const.OPACITY_6) .fontFamily($r('app.string.HarmonyHeiTi')) } @Component export struct TaskCard { - @Prop taskInfoStr: string; - clickAction: (isClick: boolean) => void; + @Prop taskInfoStr: string = ''; + clickAction: Function = (isClick: boolean) => {}; + @State taskInfo: TaskInfo = new TaskInfo(-1, '', -1, '', false, '', '', '', false, '', false); + + aboutToAppear() { + this.taskInfo = JSON.parse(this.taskInfoStr); + } @Builder targetValueBuilder() { - if (JSON.parse(this.taskInfoStr).isDone) { + if (this.taskInfo.isDone) { HealthText({ title: '', titleResource: $r('app.string.task_done') }) } else { Row() { HealthText({ - title: JSON.parse(this.taskInfoStr).finValue || `--`, + title: this.taskInfo.finValue || `--`, fontSize: $r('app.float.default_24') }) - Text(` / ${JSON.parse(this.taskInfoStr).targetValue} ${TaskMapById[JSON.parse(this.taskInfoStr).taskID].unit}`) + Text(` / ${this.taskInfo.targetValue} ${TaskMapById[this.taskInfo.taskID - 1].unit}`) .labelTextStyle() - .fontWeight(commonConst.FONT_WEIGHT_400) + .fontWeight(Const.FONT_WEIGHT_400) } } } build() { Row() { - Row({ space: commonConst.DEFAULT_6 }) { - Image(TaskMapById[JSON.parse(this.taskInfoStr).taskID].icon) + Row({ space: Const.DEFAULT_6 }) { + Image(TaskMapById[this.taskInfo.taskID - 1].icon) .width($r('app.float.default_36')).height($r('app.float.default_36')) .objectFit(ImageFit.Contain) HealthText({ title: '', - titleResource: TaskMapById[JSON.parse(this.taskInfoStr).taskID].taskName, + titleResource: TaskMapById[this.taskInfo.taskID - 1].taskName, fontFamily: $r('app.string.HarmonyHeiTi') }) } @@ -68,7 +74,7 @@ export struct TaskCard { .allSize() .justifyContent(FlexAlign.SpaceBetween) .borderRadius($r('app.float.default_24')) - .padding({ left: commonConst.THOUSANDTH_50, right: commonConst.THOUSANDTH_33 }) + .padding({ left: Const.THOUSANDTH_50, right: Const.THOUSANDTH_33 }) .backgroundColor($r('app.color.white')) .onClick(() => this.clickAction(true)) .gesture(LongPressGesture().onAction(() => this.clickAction(false))) diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/WeekCalendarComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/WeekCalendarComponent.ets index b2f8d0875b14df9e5de662dba3b06f3992be7ddb..908a92fe86298ba143e7b08fef7920d7cb2960ea 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/WeekCalendarComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/home/WeekCalendarComponent.ets @@ -14,15 +14,16 @@ */ import display from '@ohos.display'; -import WeekCalendarMethods from '../../viewmodel/CalendarViewModel'; +import WeekCalendarMethods, { ScrollTo } from '../../viewmodel/CalendarViewModel'; import { HomeStore } from '../../viewmodel/HomeViewModel'; import HealthText from '../../view/HealthTextComponent'; import { WeekDateModel } from '../../model/WeekCalendarModel'; import { sameDate } from '../../common/utils/Utils'; -import * as commonConst from '../../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; import Logger from '../../common/utils/Logger'; -export const WEEK_DAY_WIDTH: number = 100 / commonConst.WEEK_DAY_NUM; +export const WEEK_DAY_WIDTH: number = 100 / Const.WEEK_DAY_NUM; + const DEFAULT_SCROLL_WIDTH = 336; // default calendar width const DEFAULT_SCROLL_PERCENT = 0.934; // default calendar width percent @@ -31,12 +32,11 @@ export struct WeekCalendar { @Link homeStore: HomeStore; currentPage: number = 1; private scroller: Scroller = new Scroller(); + scrollWidth: number = DEFAULT_SCROLL_WIDTH; private isLoadMore: boolean = false; private isPageScroll: boolean = false; - scrollWidth: number = DEFAULT_SCROLL_WIDTH; aboutToAppear() { - // get width try { let displayClass = display.getDefaultDisplaySync(); this.scrollWidth = displayClass.width / displayClass.densityPixels * DEFAULT_SCROLL_PERCENT; @@ -58,7 +58,8 @@ export struct WeekCalendar { return $r('app.media.ic_home_half_done'); } - @Builder ArrowIcon(isRight: boolean) { + @Builder + ArrowIcon(isRight: boolean) { Row() { Image($r('app.media.ic_right_grey')) .width($r('app.float.default_6')) @@ -66,9 +67,11 @@ export struct WeekCalendar { } .width($r('app.float.default_20')) .height($r('app.float.default_20')) - .rotate({ z: 1, angle: isRight ? 0 : commonConst.DEFAULT_180 }) + .rotate({ z: 1, angle: isRight ? 0 : Const.DEFAULT_180 }) .justifyContent(FlexAlign.Center) - .onClick(() => isRight ? WeekCalendarMethods.goToNextWeek.call(this) : WeekCalendarMethods.gotoPreviousWeek.call(this)) + .onClick(() => isRight ? + WeekCalendarMethods.goToNextWeek(this.currentPage, this.isPageScroll, this.homeStore, this.scroller) : + WeekCalendarMethods.gotoPreviousWeek(this.isPageScroll, this.homeStore, this.currentPage, this.scroller)) } build() { @@ -84,42 +87,76 @@ export struct WeekCalendar { Scroll(this.scroller) { Row() { - ForEach(this.homeStore.dateArr, (item: WeekDateModel, index: number) => { + ForEach(this.homeStore.dateArr, (item: WeekDateModel, index?: number) => { Column() { Text(item.weekTitle) .fontSize($r('app.float.default_12')) - .fontWeight(commonConst.FONT_WEIGHT_500) - .fontColor(sameDate(item.date, this.homeStore.showDate) ? $r('app.color.blueColor') : $r('app.color.titleColor')) + .fontWeight(Const.FONT_WEIGHT_500) + .fontColor(sameDate(item.date, this.homeStore.showDate) ? + $r('app.color.blueColor') : $r('app.color.titleColor')) .fontFamily($r('app.string.HarmonyHeiTi_Medium')) - .opacity(commonConst.OPACITY_6) + .opacity(Const.OPACITY_6) Divider() - .margin({top: commonConst.DEFAULT_2, bottom: $r('app.float.default_4')}) + .margin({ top: Const.DEFAULT_2, bottom: $r('app.float.default_4') }) .width($r('app.float.default_12')) .color(sameDate(item.date, this.homeStore.showDate) ? $r('app.color.blueColor') : $r('app.color.white')) Image(this.getProgressImg(item)) .height($r('app.float.default_28')) .objectFit(ImageFit.Contain) - .margin({ top: commonConst.THOUSANDTH_80 }) + .margin({ top: Const.THOUSANDTH_80 }) } .width(`${WEEK_DAY_WIDTH}%`) .justifyContent(FlexAlign.SpaceBetween) - .onClick(() => WeekCalendarMethods.calenderItemClickAction.call(this, item, index)) - }, item => JSON.stringify(item)) + .onClick(() => WeekCalendarMethods.calenderItemClickAction(item, index, this.homeStore)) + }) } } .scrollBar(BarState.Off) .scrollable(ScrollDirection.Horizontal) - .width(commonConst.THOUSANDTH_1000) - .onScrollStop(() => WeekCalendarMethods.onScrollEndAction.call(this)) - .onScrollEdge(() => WeekCalendarMethods.onScrollEdgeAction.call(this)) + .width(Const.THOUSANDTH_1000) + .onScrollStop(() => this.onScrollEndAction()) + .onScrollEdge((event) => this.onScrollEdgeAction(event)) } .borderRadius($r('app.float.default_24')) .backgroundColor($r('app.color.white')) - .width(commonConst.THOUSANDTH_1000) - .padding({ top: commonConst.THOUSANDTH_50, bottom: commonConst.THOUSANDTH_50 }) + .width(Const.THOUSANDTH_1000) + .height(Const.THOUSANDTH_1000) + .padding({ top: Const.THOUSANDTH_50, bottom: Const.THOUSANDTH_120 }) + + } + .width(Const.THOUSANDTH_1000) + .height(Const.THOUSANDTH_420) + .padding(Const.THOUSANDTH_33) + } + onScrollEndAction() { + if (this.isPageScroll === false) { + let page = Math.round(this.scroller.currentOffset().xOffset / this.scrollWidth); + page = (this.isLoadMore === true) ? page + 1 : page; + if (this.scroller.currentOffset().xOffset % this.scrollWidth != 0 || this.isLoadMore === true) { + let xOffset = page * this.scrollWidth; + this.scroller.scrollTo({ xOffset, yOffset: 0 } as ScrollTo); + this.isLoadMore = false; + } + this.currentPage = this.homeStore.dateArr.length / Const.WEEK_DAY_NUM - page - 1; + Logger.info('HomeIndex', 'onScrollEnd: page ' + page + ', listLength ' + this.homeStore.dateArr.length); + let dayModel: WeekDateModel = this.homeStore.dateArr[Const.WEEK_DAY_NUM * page+this.homeStore.selectedDay]; + Logger.info('HomeIndex', 'currentItem: ' + JSON.stringify(dayModel) + ', selectedDay ' + this.homeStore.selectedDay); + this.homeStore!.setSelectedShowDate(dayModel!.date!.getTime()); + } + this.isPageScroll = false; + } + + onScrollEdgeAction(side: Edge) { + if (side === Edge.Top && this.isPageScroll === false) { + Logger.info('HomeIndex', 'onScrollEdge: currentPage ' + this.currentPage); + if ((this.currentPage + 2) * Const.WEEK_DAY_NUM >= this.homeStore.dateArr.length) { + Logger.info('HomeIndex', 'onScrollEdge: load more data'); + let date: Date = new Date(this.homeStore.showDate); + date.setDate(date.getDate() - Const.WEEK_DAY_NUM); + this.homeStore.getPreWeekData(date, () => {}); + this.isLoadMore = true; + } } - .width(commonConst.THOUSANDTH_1000) - .padding(commonConst.THOUSANDTH_33) } } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskDetailComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskDetailComponent.ets index 8b9fb61b4b635ce424ae446e7e3d52b4b80b39f3..8125a7fc94080fb7da130b0c0ef3b8f54c986293 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskDetailComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskDetailComponent.ets @@ -16,10 +16,11 @@ import router from '@ohos.router'; import prompt from '@system.prompt'; +import common from '@ohos.app.ability.common'; import { ITaskItem } from '../../model/TaskInitList'; import Logger from '../../common/utils/Logger'; -import * as commonConst from '../../common/constants/CommonConstants'; -import { taskType } from '../../common/bean/TaskInfo'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; +import TaskInfo, { taskType } from '../../viewmodel/TaskInfo'; import { TaskChooseItem, TargetSetItem, @@ -31,12 +32,13 @@ import { BroadCast, BroadCastType } from '../../common/utils/BroadCast'; import { HealthDataSrcMgr } from '../../common/utils/HealthDataSrcMgr'; import { initFrequencyString, addTask, formatParams } from '../../viewmodel/TaskViewModel'; import { TaskDialogView } from '../dialog/TaskDialogView'; +import { GlobalContext } from '../../common/utils/GlobalContext'; @Styles function listItemStyle() { .backgroundColor($r('app.color.white')) - .height(commonConst.DEFAULT_56) - .borderRadius(commonConst.DEFAULT_10) - .padding({ left: commonConst.DEFAULT_12, right: commonConst.DEFAULT_12 }) + .height(Const.DEFAULT_56) + .borderRadius(Const.DEFAULT_10) + .padding({ left: Const.DEFAULT_12, right: Const.DEFAULT_12 }) } @Component @@ -47,7 +49,8 @@ export default struct TaskDetail { private isChanged: boolean = false; parseRouterParams() { - const routerParams: ITaskItem = JSON.parse(router.getParams()['params']); + let params = router.getParams() as Record; + const routerParams: ITaskItem = JSON.parse(params.params as string); return routerParams; } @@ -55,55 +58,48 @@ export default struct TaskDetail { this.isChanged = true; } - backIndexParams() { - return formatParams({ - ...this.settingParams, - isDone: true, - finValue: this.settingParams?.targetValue, - }); + backIndexParams(): string { + return formatParams(this.settingParams); } finishTaskEdit() { if (this.isChanged) { - addTask({ - id: commonConst.ZERO, - date: commonConst.GLOBAL_KEY, - ...this.settingParams, - isDone: false, - finValue: '', - }) - .then(res => { - router.back({ - url: 'pages/MainPage', - params: { - editTask: this.backIndexParams(), - } - }) - Logger.info('addTaskFinished', JSON.stringify(res)); + let context: Context = getContext(this) as common.Context; + let taskInfo: TaskInfo = new TaskInfo(Const.ZERO, Const.GLOBAL_KEY, this.settingParams.taskID, + this.settingParams.targetValue, this.settingParams.isAlarm, this.settingParams.startTime, + this.settingParams.endTime, this.settingParams.frequency, false, '', this.settingParams.isOpen); + addTask(taskInfo, context).then((res: number) => { + GlobalContext.getContext().setObject('taskListChange', true); + router.back({ + url: 'pages/MainPage', + params: { + editTask: this.backIndexParams(), + } }) - .catch(error => { - prompt.showToast({ - message: commonConst.SETTING_FINISH_FAILED_MESSAGE - }) - Logger.error('addTaskFailed', JSON.stringify(error)); + Logger.info('addTaskFinished', JSON.stringify(res)); + }).catch((error: Error) => { + prompt.showToast({ + message: Const.SETTING_FINISH_FAILED_MESSAGE }) + Logger.error('addTaskFailed', JSON.stringify(error)); + }) return; } router.back({ url: 'pages/MainPage', - }) + }); } aboutToAppear() { - this.broadCast.off(BroadCastType.SHOW_TARGET_SETTING_DIALOG, null); - this.broadCast.off(BroadCastType.SHOW_REMIND_TIME_DIALOG, null); - this.broadCast.off(BroadCastType.SHOW_FREQUENCY_DIALOG, null); + this.broadCast.off(BroadCastType.SHOW_TARGET_SETTING_DIALOG, () => {}); + this.broadCast.off(BroadCastType.SHOW_REMIND_TIME_DIALOG, () => {}); + this.broadCast.off(BroadCastType.SHOW_FREQUENCY_DIALOG, () => {}); } build() { Row() { Column() { - List({ space: commonConst.LIST_ITEM_SPACE }) { + List({ space: Const.LIST_ITEM_SPACE }) { ListItem() { TaskChooseItem() } @@ -115,12 +111,12 @@ export default struct TaskDetail { .listItemStyle() .enabled( this.settingParams?.isOpen - && this.settingParams?.taskID !== taskType.smile - && this.settingParams?.taskID !== taskType.brushTeeth + && this.settingParams?.taskID !== taskType.smile + && this.settingParams?.taskID !== taskType.brushTeeth ) .onClick(() => { this.broadCast.emit( - BroadCastType.SHOW_TARGET_SETTING_DIALOG); + BroadCastType.SHOW_TARGET_SETTING_DIALOG); }) ListItem() { @@ -142,31 +138,31 @@ export default struct TaskDetail { FrequencyItem() } .listItemStyle() - .enabled(this.settingParams?.isOpen) + .enabled(this.settingParams?.isOpen && this.settingParams?.isAlarm) .onClick(() => { this.broadCast.emit(BroadCastType.SHOW_FREQUENCY_DIALOG); }) } - .width(commonConst.THOUSANDTH_940) + .width(Const.THOUSANDTH_940) Button() { Text($r('app.string.complete')).fontSize($r('app.float.default_20')).fontColor($r('app.color.blueColor')) } - .width(commonConst.THOUSANDTH_800) - .height(commonConst.DEFAULT_48) + .width(Const.THOUSANDTH_800) + .height(Const.DEFAULT_48) .backgroundColor($r('app.color.borderColor')) .onClick(() => { this.finishTaskEdit(); }) .position({ - x: commonConst.THOUSANDTH_100, - y: commonConst.THOUSANDTH_800 + x: Const.THOUSANDTH_100, + y: Const.THOUSANDTH_800 }) TaskDialogView() } - .width(commonConst.THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) } } } diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskEditListItem.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskEditListItem.ets index f3ec1da286f7c577dd6968f43051fb5350425807..85ddf3892cfcb13365a4ca5dcb4c9e62e2ecf05d 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskEditListItem.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskEditListItem.ets @@ -14,41 +14,32 @@ */ import { ITaskItem } from '../../model/TaskInitList'; -import { - DEFAULT_8, - DEFAULT_12, - DEFAULT_20, - DEFAULT_16, - DEFAULT_32, - DEFAULT_56, - THOUSANDTH_1000, - PER_DAY -} from '../../common/constants/CommonConstants'; -import { taskType } from '../../common/bean/TaskInfo'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; +import { taskType } from '../../viewmodel/TaskInfo'; @Extend(Text) function targetSetCommon() { - .fontSize(DEFAULT_16) + .fontSize(Const.DEFAULT_16) .flexGrow(1) - .margin({ right: DEFAULT_8 }) + .margin({ right: Const.DEFAULT_8 }) .align(Alignment.End) } -@Extend(Text) function targetSettingStyle(isOpen, taskID) { +@Extend(Text) function targetSettingStyle(isOpen: boolean, taskID: number) { .fontColor(isOpen && taskID !== taskType.smile && taskID !== taskType.brushTeeth ? $r('app.color.titleColor') : $r('app.color.disabledColor')) } -@Extend(Text) function remindTimeStyle(isOpen, isAlarm) { +@Extend(Text) function remindTimeStyle(isOpen: boolean, isAlarm: boolean) { .fontColor(isOpen && isAlarm ? $r('app.color.titleColor') : $r('app.color.disabledColor')) } -@Extend(Text) function frequencyStyle(isOpen) { - .fontSize(DEFAULT_12) +@Extend(Text) function frequencyStyle(isOpen: boolean, isAlarm: boolean) { + .fontSize(Const.DEFAULT_12) .flexGrow(1) - .margin({ right: DEFAULT_8 }) + .margin({ right: Const.DEFAULT_8 }) .textAlign(TextAlign.End) - .fontColor(isOpen ? $r('app.color.titleColor') : $r('app.color.disabledColor')) + .fontColor(isOpen && isAlarm ? $r('app.color.titleColor') : $r('app.color.disabledColor')) } @@ -58,16 +49,16 @@ export struct TaskChooseItem { build() { Row() { - Text(this.settingParams.taskName).fontSize(DEFAULT_20).fontWeight(FontWeight.Medium) + Text(this.settingParams.taskName).fontSize(Const.DEFAULT_20).fontWeight(FontWeight.Medium) Toggle({ type: ToggleType.Switch, isOn: this.settingParams.isOpen }) - .width(DEFAULT_56) - .height(DEFAULT_32) + .width(Const.DEFAULT_56) + .height(Const.DEFAULT_32) .selectedColor($r('app.color.blueColor')) .onChange((isOn) => { this.settingParams.isOpen = isOn; }) } - .width(THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.SpaceBetween) } } @@ -79,7 +70,7 @@ export struct TargetSetItem { build() { Row() { Text($r('app.string.target_setting')) - .fontSize(DEFAULT_20) + .fontSize(Const.DEFAULT_20) .fontWeight(FontWeight.Medium) Blank() @@ -89,13 +80,13 @@ export struct TargetSetItem { .targetSetCommon() .targetSettingStyle(this.settingParams?.isOpen, this.settingParams?.taskID) } else { - Text(`${this.settingParams?.targetValue} ${this.settingParams?.unit} ${PER_DAY}`) + Text(`${this.settingParams?.targetValue} ${this.settingParams?.unit} ${Const.PER_DAY}`) .targetSetCommon() .targetSettingStyle(this.settingParams?.isOpen, this.settingParams?.taskID) } - Image($r('app.media.ic_right_grey')).width(DEFAULT_8).height(DEFAULT_16); + Image($r('app.media.ic_right_grey')).width(Const.DEFAULT_8).height(Const.DEFAULT_16); } - .width(THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.SpaceBetween) } } @@ -107,18 +98,18 @@ export struct OpenRemindItem { build() { Row() { Text($r('app.string.open_reminder')) - .fontSize(DEFAULT_20) + .fontSize(Const.DEFAULT_20) .fontWeight(FontWeight.Medium) Toggle({ type: ToggleType.Switch, isOn: this.settingParams?.isAlarm }) - .width(DEFAULT_56) - .height(DEFAULT_32) + .width(Const.DEFAULT_56) + .height(Const.DEFAULT_32) .selectedColor($r('app.color.blueColor')) .onChange((isOn) => { this.settingParams.isAlarm = isOn; }) } - .width(THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.SpaceBetween) } } @@ -129,15 +120,15 @@ export struct RemindTimeItem { build() { Row() { - Text($r('app.string.remind_time')).fontSize(DEFAULT_20).fontWeight(FontWeight.Medium) + Text($r('app.string.remind_time')).fontSize(Const.DEFAULT_20).fontWeight(FontWeight.Medium) Blank() .layoutWeight(1) Text(this.settingParams?.startTime) .targetSetCommon() .remindTimeStyle(this.settingParams?.isOpen, this.settingParams?.isAlarm) - Image($r('app.media.ic_right_grey')).width(DEFAULT_8).height(DEFAULT_16) + Image($r('app.media.ic_right_grey')).width(Const.DEFAULT_8).height(Const.DEFAULT_16) } - .width(THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.SpaceBetween) } } @@ -149,13 +140,13 @@ export struct FrequencyItem { build() { Row() { - Text($r('app.string.frequency')).fontSize(DEFAULT_20).fontWeight(FontWeight.Medium) + Text($r('app.string.frequency')).fontSize(Const.DEFAULT_20).fontWeight(FontWeight.Medium) Text(this.frequency) .targetSetCommon() - .frequencyStyle(this.settingParams?.isOpen) - Image($r('app.media.ic_right_grey')).width(DEFAULT_8).height(DEFAULT_16) + .frequencyStyle(this.settingParams?.isOpen, this.settingParams?.isAlarm) + Image($r('app.media.ic_right_grey')).width(Const.DEFAULT_8).height(Const.DEFAULT_16) } - .width(THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.SpaceBetween) } } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskListComponent.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskListComponent.ets index 78c12fca3e3ea37fa47c41a97d89b2a68fbfa959..1e6ecc0baa95bd5e17affa119a69822c6d961cbe 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskListComponent.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/view/task/TaskListComponent.ets @@ -14,7 +14,7 @@ */ import router from '@ohos.router'; -import * as commonConst from '../../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../../common/constants/CommonConstants'; import { formatParams } from '../../viewmodel/TaskViewModel'; import { ITaskItem } from '../../model/TaskInitList'; @@ -23,38 +23,38 @@ export default struct TaskList { @Consume taskList: ITaskItem[]; build() { - List({ space: commonConst.LIST_ITEM_SPACE }) { - ForEach(this.taskList, (item) => { + List({ space: Const.LIST_ITEM_SPACE }) { + ForEach(this.taskList, (item: ITaskItem) => { ListItem() { Row() { Row() { Image(item?.icon) - .width(commonConst.DEFAULT_24) - .height(commonConst.DEFAULT_24) - .margin({ right: commonConst.DEFAULT_8 }) - Text(item?.taskName).fontSize(commonConst.DEFAULT_20).fontColor($r('app.color.titleColor')) - }.width(commonConst.THOUSANDTH_500) + .width(Const.DEFAULT_24) + .height(Const.DEFAULT_24) + .margin({ right: Const.DEFAULT_8 }) + Text(item?.taskName).fontSize(Const.DEFAULT_20).fontColor($r('app.color.titleColor')) + }.width(Const.THOUSANDTH_500) Blank() .layoutWeight(1) if (item?.isOpen) { Text($r('app.string.already_open')) - .fontSize(commonConst.DEFAULT_16) + .fontSize(Const.DEFAULT_16) .flexGrow(1) .align(Alignment.End) - .margin({ right: commonConst.DEFAULT_8 }) + .margin({ right: Const.DEFAULT_8 }) .fontColor($r('app.color.titleColor')) } Image($r('app.media.ic_right_grey')) - .width(commonConst.DEFAULT_8) - .height(commonConst.DEFAULT_16) + .width(Const.DEFAULT_8) + .height(Const.DEFAULT_16) } - .width(commonConst.THOUSANDTH_1000) + .width(Const.THOUSANDTH_1000) .justifyContent(FlexAlign.SpaceBetween) - .padding({ left: commonConst.DEFAULT_12, right: commonConst.DEFAULT_12 }) + .padding({ left: Const.DEFAULT_12, right: Const.DEFAULT_12 }) } - .height(commonConst.THOUSANDTH_80) - .borderRadius(commonConst.DEFAULT_12) + .height(Const.THOUSANDTH_80) + .borderRadius(Const.DEFAULT_12) .onClick(() => { router.pushUrl({ url: 'pages/TaskEditPage', @@ -64,9 +64,9 @@ export default struct TaskList { }) }) .backgroundColor($r('app.color.white')) - }) + }, (item: ITaskItem) => JSON.stringify(item)) } - .height(commonConst.THOUSANDTH_1000) - .width(commonConst.THOUSANDTH_940) + .height(Const.THOUSANDTH_1000) + .width(Const.THOUSANDTH_940) } } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/AchievementInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/AchievementInfo.ets new file mode 100644 index 0000000000000000000000000000000000000000..e943f53660d2c4c349d6a7b90ffeeb9d4f85a563 --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/AchievementInfo.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Achievement info + */ +export default class AchievementInfo { + achievementLevel: number = 0; + showAchievement: boolean = false; +} diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/AchievementMapInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/AchievementMapInfo.ets new file mode 100644 index 0000000000000000000000000000000000000000..d060074966da058609ac78b2ea022648a5d0a51d --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/AchievementMapInfo.ets @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Achievement map info + */ +export default class AchievementMapInfo { + off_3: Resource = $r('app.media.ic_badge_3_off'); + on_3: Resource = $r('app.media.ic_badge_3_on'); + off_7: Resource = $r('app.media.ic_badge_7_off'); + on_7: Resource = $r('app.media.ic_badge_7_on'); + off_30: Resource = $r('app.media.ic_badge_30_off'); + on_30: Resource = $r('app.media.ic_badge_30_on'); + off_50: Resource = $r('app.media.ic_badge_50_off'); + on_50: Resource = $r('app.media.ic_badge_50_on'); + off_73: Resource = $r('app.media.ic_badge_73_off'); + on_73: Resource = $r('app.media.ic_badge_73_on'); + off_99: Resource = $r('app.media.ic_badge_99_off'); + on_99: Resource = $r('app.media.ic_badge_99_on'); +} diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/AchievementViewModel.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/AchievementViewModel.ets index 8273b1c4bcc9d758d93ec661d1ff31692ebd22ae..24b4bcce425e553b7a968a54e1a2b87fccabfb7b 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/AchievementViewModel.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/AchievementViewModel.ets @@ -12,17 +12,65 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import CardInfo from './CardInfo'; import { ACHIEVEMENT_LEVEL_LIST, AchievementMap } from '../model/TaskInitList'; -export function getBadgeCardItems(successiveDays: number):[string, Resource][] { +export function getBadgeCardItems(successiveDays: number): Array { let badgeMileStones = ACHIEVEMENT_LEVEL_LIST; - let cardItems:[string, Resource][] = []; + let cardItems: Array = []; for (let i = 0; i < badgeMileStones.length; i++) { let onOrOff = successiveDays >= badgeMileStones[i] ? 'on' : 'off'; let titleContent = String(badgeMileStones[i]); - let oneItem:[string, Resource] = [titleContent,AchievementMap[`${ badgeMileStones[i] }_${ onOrOff }`]]; - cardItems.push(oneItem); + let cardInfo: CardInfo = new CardInfo(); + cardInfo.titleContent = titleContent; + cardInfo.achievement = getAchievement(`${ onOrOff }_${ badgeMileStones[i] }`); + cardItems.push(cardInfo); } return cardItems; +} + +function getAchievement(key: string) { + let result = $r('app.string.empty'); + switch (key) { + case 'off_3': + result = AchievementMap.off_3; + break; + case 'on_3': + result = AchievementMap.on_3; + break; + case 'off_7': + result = AchievementMap.off_7; + break; + case 'on_7': + result = AchievementMap.on_7; + break; + case 'off_30': + result = AchievementMap.off_30; + break; + case 'on_30': + result = AchievementMap.on_30; + break; + case 'off_50': + result = AchievementMap.off_50; + break; + case 'on_50': + result = AchievementMap.on_50; + break; + case 'off_73': + result = AchievementMap.off_73; + break; + case 'on_73': + result = AchievementMap.on_73; + break; + case 'off_99': + result = AchievementMap.off_99; + break; + case 'on_99': + result = AchievementMap.on_99; + break; + default: + break; + } + return result; } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/BroadCastCallBackInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/BroadCastCallBackInfo.ets new file mode 100644 index 0000000000000000000000000000000000000000..8a0187df3979a5147ec9b08dd809acb0dfc1bcf5 --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/BroadCastCallBackInfo.ets @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Broad Cast CallBack Info + */ +export default class BroadCastCallBackInfo { + showAchievementDialog: Function = () => {}; + showTaskDetailDialog: Function = () => {}; + showTargetSettingDialog: Function = () => {}; + showRemindTimeDialog: Function = () => {}; + showFrequencyDialog: Function = () => {}; +} diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/CalendarViewModel.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/CalendarViewModel.ets index d37049a4f102ac424daf05f648c20bfc2626b2fb..ae39821fce84c6eeb1a0a28e59347a980580a2d9 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/CalendarViewModel.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/CalendarViewModel.ets @@ -15,84 +15,62 @@ import { WeekDateModel } from '../model/WeekCalendarModel'; import Logger from '../common/utils/Logger'; -import { WEEK_DAY_NUM, WEEK_DAY_TIME } from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; +import WeekCalendarMethodInfo from './WeekCalendarMethodInfo'; +import { HomeStore } from './HomeViewModel'; const LAZY_DATA_PAGE: number = 2; // lazy page number -function gotoPreviousWeek() { - this.isPageScroll = true; - let date: Date = new Date(this.homeStore.showDate); +export interface ScrollPage { + next: boolean; + direction?: Axis; +} + +export interface ScrollTo { + xOffset: number | string; + yOffset: number | string; +} + +function gotoPreviousWeek(isPageScroll: Boolean, homeStore: HomeStore, currentPage: number, scroller: Scroller) { + isPageScroll = true; + let date: Date = new Date(homeStore.showDate); Logger.info('HomeIndex', 'gotoPreviousWeek: showDate_' + date.toISOString()); - if ((this.currentPage + LAZY_DATA_PAGE) * WEEK_DAY_NUM > this.homeStore.dateArr.length) { + if ((currentPage + LAZY_DATA_PAGE) * Const.WEEK_DAY_NUM > homeStore.dateArr.length) { // get more history data - this.homeStore.getPreWeekData(date, () => { - this.homeStore.setSelectedShowDate(this.homeStore.showDate - WEEK_DAY_TIME); - this.currentPage += 1; + homeStore.getPreWeekData(date, () => { + homeStore.setSelectedShowDate(homeStore.showDate - Const.WEEK_DAY_TIME); + currentPage += 1; }); } else { - this.scroller.scrollPage({ next: false }); + scroller.scrollPage({ next: false } as ScrollPage); Logger.info('HomeIndex', 'gotoPreviousWeek'); - this.homeStore.setSelectedShowDate(this.homeStore.showDate - WEEK_DAY_TIME); - this.currentPage += 1; + homeStore.setSelectedShowDate(homeStore.showDate - Const.WEEK_DAY_TIME); + currentPage += 1; } } -function goToNextWeek() { - if (this.currentPage <= 0) { +function goToNextWeek(currentPage: number, isPageScroll: Boolean, homeStore: HomeStore, scroller: Scroller) { + if (currentPage <= 0) { Logger.info('HomeIndex', 'goToNextWeek: is the current week'); return; } - this.isPageScroll = true; + isPageScroll = true; Logger.info('HomeIndex', 'goToNextWeek: nextPage'); - this.homeStore.setSelectedShowDate(this.homeStore.showDate + WEEK_DAY_TIME); - this.currentPage -= 1; - this.scroller.scrollPage({ next: true }); + homeStore.setSelectedShowDate(homeStore.showDate + Const.WEEK_DAY_TIME); + currentPage -= 1; + scroller.scrollPage({ next: true } as ScrollPage); } -function onScrollEndAction() { - if (!this.isPageScroll) { - let page = Math.round(this.scroller.currentOffset().xOffset / this.scrollWidth); - page = this.isLoadMore ? page + 1 : page; - if (this.scroller.currentOffset().xOffset % this.scrollWidth != 0 || this.isLoadMore) { - let xOffset = page * this.scrollWidth; - this.scroller.scrollTo({ xOffset, yOffset: 0 }); - this.isLoadMore = false; - } - this.currentPage = this.homeStore.dateArr.length / WEEK_DAY_NUM - page - 1; - Logger.info('HomeIndex', 'onScrollEnd: page ' + page + ', listLength ' + this.homeStore.dateArr.length); - let dayModel = this.homeStore.dateArr[WEEK_DAY_NUM * page+this.homeStore.selectedDay]; - Logger.info('HomeIndex', 'currentItem: ' + JSON.stringify(dayModel) + ', selectedDay ' + this.homeStore.selectedDay); - this.homeStore.setSelectedShowDate(dayModel.date.getTime()); - } - this.isPageScroll = false; -} - -function onScrollEdgeAction(side: Edge) { - if (side == Edge.Top && !this.isPageScroll) { - Logger.info('HomeIndex', 'onScrollEdge: currentPage ' + this.currentPage); - if ((this.currentPage + 2) * WEEK_DAY_NUM >= this.homeStore.dateArr.length) { - Logger.info('HomeIndex', 'onScrollEdge: load more data'); - let date: Date = new Date(this.homeStore.showDate); - date.setDate(date.getDate() - WEEK_DAY_NUM); - this.homeStore.getPreWeekData(date); - this.isLoadMore = true; - } - } -} - -function calenderItemClickAction(item: WeekDateModel, index: number) { +function calenderItemClickAction(item: WeekDateModel, index: number, homeStore: HomeStore) { Logger.info('HomeIndex', 'click the calendarItem: ' + JSON.stringify(item)); - this.homeStore.setSelectedShowDate(item.date.getTime()); - this.homeStore.selectedDay = index % WEEK_DAY_NUM; + homeStore.setSelectedShowDate(item.date.getTime()); + homeStore.selectedDay = index % Const.WEEK_DAY_NUM; } -const WeekCalendarMethods = { - gotoPreviousWeek, - goToNextWeek, - onScrollEndAction, - onScrollEdgeAction, - calenderItemClickAction -} +const WeekCalendarMethods: WeekCalendarMethodInfo = new WeekCalendarMethodInfo(); +WeekCalendarMethods.gotoPreviousWeek = gotoPreviousWeek; +WeekCalendarMethods.goToNextWeek = goToNextWeek; +WeekCalendarMethods.calenderItemClickAction = calenderItemClickAction; export default WeekCalendarMethods; \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/CardInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/CardInfo.ets new file mode 100644 index 0000000000000000000000000000000000000000..e3c17e6fa4838310041fb4d19aed0d7c5f26f554 --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/CardInfo.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Agency card task info + */ +export default class CardInfo { + titleContent: string = ''; + achievement: Resource = $r('app.string.empty'); +} diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/bean/ColumnInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/ColumnInfo.ets similarity index 87% rename from ExcellentCase/Healthy_life/entry/src/main/ets/common/bean/ColumnInfo.ets rename to ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/ColumnInfo.ets index 5b6e8e6d2bf2a1a317b65b80858ecf88ea3f09d7..688668fcfe6de192411dda7a3c7ead532af1661b 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/bean/ColumnInfo.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/ColumnInfo.ets @@ -14,16 +14,16 @@ */ /** - * ColumnInfo + * Column Info. * */ export default class ColumnInfo { - name: string - type: string - length?: number - nullable?: boolean - primary?: boolean - autoincrement?: boolean + name: string; + type: string; + length?: number; + nullable?: boolean; + primary?: boolean; + autoincrement?: boolean; constructor(name: string, type: string, length?: number, nullable?: boolean, primary?: boolean, autoincrement?: boolean) { diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/CommonConstantsInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/CommonConstantsInfo.ets new file mode 100644 index 0000000000000000000000000000000000000000..8c425a14cce1e4ade31a5625608c46381113a1f4 --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/CommonConstantsInfo.ets @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Common constants info + */ +export default class CommonConstantsInfo { + dbName?: string = ''; + tableName?: string = ''; + columns?: Array = []; +} diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/bean/DayInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/DayInfo.ets similarity index 100% rename from ExcellentCase/Healthy_life/entry/src/main/ets/common/bean/DayInfo.ets rename to ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/DayInfo.ets diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/bean/GlobalInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/GlobalInfo.ets similarity index 100% rename from ExcellentCase/Healthy_life/entry/src/main/ets/common/bean/GlobalInfo.ets rename to ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/GlobalInfo.ets diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/HomeViewModel.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/HomeViewModel.ets index caf217cd37a082d7b6684cd05fe372a5aa34e27c..0aef81cefc8c143058a5e78ba5108e5e637b6a99 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/HomeViewModel.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/HomeViewModel.ets @@ -13,11 +13,11 @@ * limitations under the License. */ -import { DEFAULT_100 } from '../common/constants/CommonConstants'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; import { isReachNewAchievement, ACHIEVEMENT_LEVEL_KEY } from '../model/AchieveModel'; import { TaskMapById, ITaskItem, ACHIEVEMENT_LEVEL_LIST } from '../model/TaskInitList'; -import TaskInfo from '../common/bean/TaskInfo'; -import DayInfo from '../common/bean/DayInfo'; +import TaskInfo from './TaskInfo'; +import DayInfo from './DayInfo'; import { dateToStr, weekDateFormat } from '../common/utils/Utils'; import { WeekDateModel, initializeOnStartUp, getPreviousWeek, WEEK_DAY_NUM } from '../model/WeekCalendarModel'; import DatabaseApi from '../model/DatabaseModel'; @@ -25,6 +25,9 @@ import TaskInfoTableApi from '../common/database/tables/TaskInfoApi'; import DayInfoApi from '../common/database/tables/DayInfoApi'; import GlobalInfoApi from '../common/database/tables/GlobalInfoApi'; import Logger from '../common/utils/Logger'; +import GlobalInfo from './GlobalInfo'; +import WeekCalendarInfo from './WeekCalendarInfo'; +import AchievementInfo from './AchievementInfo'; @Observed export class HomeStore { @@ -33,7 +36,7 @@ export class HomeStore { public selectedDay: number; // selected day of on week public showDate: number; public dateTitle: string; - public selectedDayInfo: WeekDateModel; // task info on selected day + public selectedDayInfo: WeekDateModel = new WeekDateModel('', '', new Date()); // task info on selected day constructor(currentDate: Date) { this.currentDate = currentDate; @@ -43,29 +46,25 @@ export class HomeStore { } public initData() { - let [initArr, dateArr] = initializeOnStartUp(this.currentDate); - this.dateArr = initArr; + let weekCalendarInfo: WeekCalendarInfo = initializeOnStartUp(this.currentDate); + this.dateArr = weekCalendarInfo.arr; Logger.info('this.currentDate', this.currentDate.toDateString()); - Logger.info('initWeekData dateArr', JSON.stringify(dateArr)) + Logger.info('initWeekData dateArr', JSON.stringify(weekCalendarInfo.strArr)) // get data form db - DatabaseApi.query(dateToStr(new Date()), (taskList, dayInfo) => { + DatabaseApi.query(dateToStr(new Date()), (taskList: TaskInfo[], dayInfo: DayInfo) => { Logger.info('Current Day Task Info: ', JSON.stringify(taskList)); - DayInfoApi.queryList(dateArr, (res: DayInfo[]) => { + DayInfoApi.queryList(weekCalendarInfo.strArr, (res: DayInfo[]) => { let tempList = res.concat(dayInfo); Logger.info('initDayInfoList: ', JSON.stringify(res)); for (let i = 0; i < this.dateArr.length; i++) { - let tempDayInfo = tempList.find((item) => item.date == this.dateArr[i].dateStr) || { - date: this.dateArr[i].dateStr, - finTaskNum: 0, - targetTaskNum: 0 - }; - initArr[i].dayInfo = tempDayInfo; - if (this.dateArr[i].dateStr == dateToStr(new Date(this.showDate))) { + let tempDayInfo = tempList.find((item: DayInfo) => item.date === this.dateArr[i].dateStr) || new DayInfo(this.dateArr[i].dateStr, 0, 0); + weekCalendarInfo.arr[i].dayInfo = tempDayInfo; + if (this.dateArr[i].dateStr === dateToStr(new Date(this.showDate))) { // get tasks of showDate - initArr[i].taskList = taskList; + weekCalendarInfo.arr[i].taskList = taskList; } } - this.dateArr = initArr; + this.dateArr = weekCalendarInfo.arr; setTimeout(() => { this.setSelectedShowDate(this.showDate); }, 0) @@ -74,17 +73,19 @@ export class HomeStore { } public getPreWeekData(date: Date, callback: Function) { - let [initArr, dateArr] = getPreviousWeek(date); + let weekCalendarInfo: WeekCalendarInfo = getPreviousWeek(date); // get data form db - DayInfoApi.queryList(dateArr, (res: DayInfo[]) => { + DayInfoApi.queryList(weekCalendarInfo.strArr, (res: DayInfo[]) => { Logger.info('getPreWeekData->DayInfoList: ', JSON.stringify(res)); if (res.length > 0) { - for (let i = 0; i < initArr.length; i++) { - let dayInfo = res.find((item) => item.date == initArr[i].dateStr) || null; - initArr[i].dayInfo = dayInfo; + for (let i = 0; i < weekCalendarInfo.arr.length; i++) { + let dayInfo = res.find((item) => item.date === weekCalendarInfo.arr[i].dateStr); + if (dayInfo) { + weekCalendarInfo.arr[i].dayInfo = dayInfo; + } } } - this.dateArr = initArr.concat(...this.dateArr); + this.dateArr = weekCalendarInfo.arr.concat(...this.dateArr); callback(); }) } @@ -98,15 +99,22 @@ export class HomeStore { Logger.debug('updateSelectedDayInfo', JSON.stringify(selectedDayInfo)); if (selectedDayInfo.taskList?.length === 0) { // get data form db - TaskInfoTableApi.query(selectedDayInfo.dateStr, true, (res) => { + TaskInfoTableApi.query(selectedDayInfo.dateStr, true, (res: TaskInfo[]) => { Logger.info('Selected TaskInfoList: ', JSON.stringify(res)); selectedDayInfo.taskList = res; - this.dateArr = this.dateArr.map((item: WeekDateModel) => - item.dateStr == selectedDayInfo.dateStr ? { ...item, taskList: res } : item); - this.selectedDayInfo = { ...selectedDayInfo }; + this.dateArr = this.dateArr.map((item: WeekDateModel) => { + if(item.dateStr === selectedDayInfo.dateStr) { + let taskListStr = JSON.stringify(res); + item.taskList = JSON.parse(taskListStr); + return item; + } else { + return item; + } + }) + this.selectedDayInfo = selectedDayInfo; }); } else { - this.selectedDayInfo = { ...selectedDayInfo }; + this.selectedDayInfo = selectedDayInfo; } Logger.info("selectedDayTaskInfo: ", JSON.stringify(selectedDayInfo.taskList)); } @@ -114,39 +122,42 @@ export class HomeStore { public updateTaskInfoList(editedTaskInfo: ITaskItem) { if (editedTaskInfo?.taskID) { // edited task - const {taskID, targetValue, isAlarm, frequency, startTime, endTime, isOpen } = editedTaskInfo; - let task: TaskInfo = { - isOpen, - id: 0, - date: dateToStr(new Date()), - isDone: true, - taskID, - targetValue, - isAlarm, - frequency, - startTime, - endTime, - finValue: targetValue - } + let taskID = editedTaskInfo.taskID; + let targetValue = editedTaskInfo.targetValue; + let isAlarm = editedTaskInfo.isAlarm; + let frequency = editedTaskInfo.frequency; + let startTime = editedTaskInfo.startTime; + let endTime = editedTaskInfo.endTime; + let isOpen = editedTaskInfo.isOpen; + let task = new TaskInfo(0, dateToStr(new Date()), taskID, targetValue, isAlarm, + startTime, endTime, frequency, true, targetValue, isOpen); this.dateArr = this.dateArr.map((item: WeekDateModel) => { - if (task.date == item.dateStr) { + if (task.date === item.dateStr) { Logger.info('item', JSON.stringify(item)); let taskList: TaskInfo[] = item.taskList; const dayInfo: DayInfo = item.dayInfo; if (editedTaskInfo.isOpen) { // add task - taskList = taskList.filter((item) => item.taskID != taskID) + taskList = taskList.filter((taskItem) => taskItem.taskID != taskID) .concat(task) .sort((a, b) => a.taskID - b.taskID); - dayInfo.finTaskNum += 1; + let count: number = 0; + taskList.forEach((taskItem: TaskInfo) => { + if (taskItem.isDone) { + count++; + } + }); + if (count > dayInfo.finTaskNum) { + dayInfo.finTaskNum = count; + } } else { // delete task - let taskIndex = taskList.findIndex((item) => item.taskID == taskID); + let taskIndex = taskList.findIndex((taskItem) => taskItem.taskID === taskID); Logger.info('taskList[taskIndex]', JSON.stringify(taskList[taskIndex])); if (taskList[taskIndex]?.isDone) { dayInfo.finTaskNum -= 1; } - taskList = taskList.filter((item) => item.taskID != taskID); + taskList = taskList.filter((taskItem) => taskItem.taskID != taskID); } dayInfo.targetTaskNum = taskList.length; if (dayInfo.finTaskNum > dayInfo.targetTaskNum) { @@ -155,7 +166,11 @@ export class HomeStore { DayInfoApi.updateData(dayInfo, () => { }); Logger.debug("tempDayInfo", JSON.stringify(dayInfo)); - let currentDayInfo = { ...item, taskList, dayInfo }; + let weekDateModelStr = JSON.stringify(item); + let currentDayInfo: WeekDateModel = JSON.parse(weekDateModelStr); + currentDayInfo.date = item.date; + currentDayInfo.taskList = taskList; + currentDayInfo.dayInfo = dayInfo; if (this.checkCurrentDay()) { this.selectedDayInfo = currentDayInfo; } @@ -172,9 +187,9 @@ export class HomeStore { } this.showDate = showDateTime; this.dateTitle = weekDateFormat(this.showDate); - let selectedInfo = this.dateArr.find((item: WeekDateModel) => item.dateStr == dateToStr(new Date(showDateTime))); + let selectedInfo = this.dateArr.find((item: WeekDateModel) => item.dateStr === dateToStr(new Date(showDateTime))); if (selectedInfo) { - this.updateSelectedDayInfo({ ...selectedInfo }); + this.updateSelectedDayInfo(selectedInfo); } Logger.info('dateTitle', this.dateTitle); } @@ -184,9 +199,9 @@ export class HomeStore { Logger.debug("dayInfo", JSON.stringify(dayInfo)); if (dayInfo && (dayInfo?.finTaskNum || 0) > 0) { if (dayInfo.finTaskNum > dayInfo.targetTaskNum) { - return `${DEFAULT_100}`; + return `${Const.DEFAULT_100}`; } - return `${Math.ceil(dayInfo.finTaskNum / dayInfo.targetTaskNum * DEFAULT_100)}`; + return `${Math.ceil(dayInfo.finTaskNum / dayInfo.targetTaskNum * Const.DEFAULT_100)}`; } return '0'; } @@ -203,45 +218,47 @@ export class HomeStore { let taskItem = await this.updateTask(taskInfo); let dateStr = this.selectedDayInfo?.dateStr; if (!taskItem) { - return Promise.resolve({ + return { achievementLevel: 0, showAchievement: false - }); + } as AchievementInfo; } this.selectedDayInfo.taskList = this.selectedDayInfo.taskList.map((item) => { - return item.taskID == taskItem?.taskID ? taskItem : item; + return item.taskID === taskItem?.taskID ? taskItem : item; }); - let achievementLevel; + let achievementLevel: number = 0; if (taskItem.isDone) { let dayInfo = await this.updateDayInfo(); if (dayInfo && dayInfo?.finTaskNum === dayInfo?.targetTaskNum) { achievementLevel = await this.updateAchievement(this.selectedDayInfo.dayInfo); } } - this.dateArr = this.dateArr.map((item: WeekDateModel) => dateStr == item.dateStr ? this.selectedDayInfo : item); - Logger.info('achievementLevel', `${achievementLevel}`); - return Promise.resolve({ + this.dateArr = this.dateArr.map((item: WeekDateModel) => dateStr === item.dateStr ? this.selectedDayInfo : item); + return { achievementLevel: achievementLevel, showAchievement: ACHIEVEMENT_LEVEL_LIST.includes(achievementLevel) - }); + } as AchievementInfo; } updateTask(task: TaskInfo): Promise { return new Promise((resolve, reject) => { - let {taskID, targetValue, finValue} = task; - let updateTask = Object.assign({}, task); - let step = TaskMapById[taskID].step; + let taskID = task.taskID; + let targetValue = task.targetValue; + let finValue = task.finValue; + let updateTask = new TaskInfo(task.id, task.date, taskID, targetValue, task.isAlarm, task.startTime, + task.endTime, task.frequency, task.isDone, finValue, task.isOpen); + let step = TaskMapById[taskID - 1].step; let hasExceed = updateTask.isDone; if (step === 0) { updateTask.isDone = true; updateTask.finValue = targetValue; } else { let value = Number(finValue) + step; - updateTask.isDone = value >= Number(targetValue); + updateTask.isDone = updateTask.isDone || value >= Number(targetValue); updateTask.finValue = updateTask.isDone ? targetValue : `${value}`; } - TaskInfoTableApi.updateDataByDate(updateTask, (res) => { + TaskInfoTableApi.updateDataByDate(updateTask, (res: number) => { if (!res || hasExceed) { Logger.error('taskClock-updateTask', JSON.stringify(res)); reject(res); @@ -256,14 +273,15 @@ export class HomeStore { dayInfo.finTaskNum += 1; dayInfo.targetTaskNum = this.selectedDayInfo.taskList.length; return new Promise((resolve, reject) => { - DayInfoApi.updateData(dayInfo, (res) => { + DayInfoApi.updateData(dayInfo, (res: number) => { if (!res) { Logger.error('taskClock-updateDayInfo', JSON.stringify(res)); reject(res); } Logger.info('taskClock-updateDayInfo', JSON.stringify(dayInfo)); // 同步界面数据 - this.selectedDayInfo = { ...this.selectedDayInfo, dayInfo }; + let dayInfoStr = JSON.stringify(dayInfo); + this.selectedDayInfo.dayInfo = JSON.parse(dayInfoStr); resolve(dayInfo); }); }); @@ -277,25 +295,25 @@ export class HomeStore { preDay = new Date(preDay); let preDayStr = dateToStr(preDay); Logger.info('taskClock-updateAchievement-1', `${preDayStr}`); - DayInfoApi.query(preDayStr, (res) => { + DayInfoApi.query(preDayStr, (res: DayInfo) => { Logger.info('taskClock-updateAchievement-2', JSON.stringify(res)); - let isReset = res?.length === 0 || res?.targetTaskNum > res?.finTaskNum; - GlobalInfoApi.query((res) => { + let isReset = res?.date === '' || res?.targetTaskNum > res?.finTaskNum; + GlobalInfoApi.query((res: GlobalInfo) => { Logger.info('taskClock-globalInfoApi', JSON.stringify(res)); let achievementInfo = res; - isReset ? (achievementInfo.checkInDays = 1) : (achievementInfo.checkInDays += 1); + isReset ? (achievementInfo.checkInDays = 1) : (achievementInfo.checkInDays += 1); let isNewAchieve = isReachNewAchievement(achievementInfo); if (isNewAchieve) { AppStorage.SetOrCreate(ACHIEVEMENT_LEVEL_KEY, achievementInfo.checkInDays); achievementInfo.achievements = achievementInfo.achievements + ',' + achievementInfo.checkInDays; } - GlobalInfoApi.updateData(achievementInfo, (res) => { + GlobalInfoApi.updateData(achievementInfo, (res: number) => { if (!res) { Logger.error('taskClock-updateAchievement', JSON.stringify(res)); reject(res); } Logger.debug('taskClock-updateAchievement', JSON.stringify(achievementInfo)); - isNewAchieve ? resolve(achievementInfo.checkInDays) : resolve(0); + isNewAchieve ? resolve(achievementInfo.checkInDays) : resolve(0); }); }); }) diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/PublishReminderInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/PublishReminderInfo.ets new file mode 100644 index 0000000000000000000000000000000000000000..b55ab66015a56a70168ef1517f7f710db020308c --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/PublishReminderInfo.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Publish reminder info + */ +export default class PublishReminderInfo { + hour: number = 0; + minute: number = 0; + daysOfWeek: Array = []; + title: string = ''; + content: string = ''; + notificationId: number = 0; + +} diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/ReminderInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/ReminderInfo.ets new file mode 100644 index 0000000000000000000000000000000000000000..d1bc90142aacd06598de3f2a6746481ab5880538 --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/ReminderInfo.ets @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Reminder info + */ +export default class ReminderInfo { + publishReminder: Function = () => {}; + cancelReminder: Function = () => {}; + hasNotificationId: Function = () => {}; +} diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/common/bean/TaskInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/TaskInfo.ets similarity index 96% rename from ExcellentCase/Healthy_life/entry/src/main/ets/common/bean/TaskInfo.ets rename to ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/TaskInfo.ets index a01fc4eb8103649d1579eca8047ec5d5403178e6..fe0c858f34e1c60de105b283a37dc8f2ec36da4f 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/common/bean/TaskInfo.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/TaskInfo.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { oneWeekDictFunc } from '../../common/utils/Utils'; +import { oneWeekDictFunc } from '../common/utils/Utils'; /** * TaskInfo diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/TaskViewModel.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/TaskViewModel.ets index 2eb88c982f04b1469acdf37f6f243922dada1331..8ce6886768eadc2121f304471e3f1ee587bdb493 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/TaskViewModel.ets +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/TaskViewModel.ets @@ -13,32 +13,27 @@ * limitations under the License. */ -import { - EVERYDAY, - GLOBAL_KEY, - TODAY, - DRINK_STEP, - DRINK_MAX_RANGE, - EAT_APPLE_RANGE, - TIMES_100 -} from '../common/constants/CommonConstants'; -import TaskInfoApi from '../common/database/tables/TaskInfoApi'; +import { CommonConstants as Const } from '../common/constants/CommonConstants'; import Logger from '../common/utils/Logger'; -import TaskInfo, { oneWeek } from '../common/bean/TaskInfo'; -import { TaskMapById, ITaskItem } from '../model/TaskInitList'; +import reminder from '../service/ReminderAgent'; +import TaskInfoApi from '../common/database/tables/TaskInfoApi'; import { padTo2Digits } from '../common/utils/Utils'; +import TaskInfo, { oneWeek } from './TaskInfo'; +import { TaskMapById, RemindContentMap, ITaskItem } from '../model/TaskInitList'; +import PublishReminderInfo from './PublishReminderInfo'; -export const taskOriginData: ITaskItem[] = Object.keys(TaskMapById).map(item => { - return TaskMapById[item]; -}) +const publishReminder = reminder.publishReminder; +const cancelReminder = reminder.cancelReminder; +const hasNotificationId = reminder.hasNotificationId; +export const taskOriginData: ITaskItem[] = TaskMapById; /** * @description Get all task status * @return object[] Database query results */ -export const getAllTask = async () => { - return new Promise((resolve) => { - TaskInfoApi.query(GLOBAL_KEY, true, (res) => { +export const getAllTask = () => { + return new Promise((resolve) => { + TaskInfoApi.query(Const.GLOBAL_KEY, true, (res: TaskInfo[]) => { if (res?.length === 0) { Logger.warn('queryTaskList', 'has no data!!'); resolve(res ?? []); @@ -48,30 +43,101 @@ export const getAllTask = async () => { }); } +/** + * @description Call notification capability + * @param params { + * hour: Hour + * minute: Minute + * daysOfWeek: Frequency of a week + * title: Notice Title + * content: Contents of notice + * notificationId: Notification ID + */ +const useReminder = (params: TaskInfo, context: Context) => { + try { + let publishReminderInfo = new PublishReminderInfo(); + publishReminderInfo.hour = Number(params?.startTime.split(':')[0]); + publishReminderInfo.minute = Number(params?.startTime.split(':')[1]); + publishReminderInfo.daysOfWeek = params?.frequency.split(',').map(item => Number(item)); + publishReminderInfo.title = RemindContentMap[params?.taskID - 1].title; + publishReminderInfo.content = RemindContentMap[params?.taskID - 1].content; + publishReminderInfo.notificationId = params?.taskID; + publishReminder(publishReminderInfo, context); + } catch (error) { + Logger.error('publishReminder', JSON.stringify(error)); + } +} + +/** + * @description Call cancel notification capability + * @param reminderId Notification ID + */ +const useCancelReminder = (reminderId: number, context: Context) => { + try { + cancelReminder(reminderId, context); + } catch (error) { + Logger.error('cancelReminder', JSON.stringify(error)); + } +} + +/** + * @description Determine whether there is a notification + * @param notificationId Notification ID + */ +const isHasNotificationId = (notificationId: number) => { + return new Promise((resolve) => { + resolve(hasNotificationId(notificationId)); + }); +} + /** * @param params:TaskInfo */ -export const addTask = (params: TaskInfo) => { +export const addTask = (params: TaskInfo, context: Context) => { if (!params) { Logger.error('addTask', 'params is null!'); - return; + return new Promise((resolve) => { + resolve(-1); + }); } - return new Promise((resolve, reject) => { - TaskInfoApi.updateDataByDate(params, (flag) => { + return new Promise(async (resolve, reject) => { + Logger.info('TaskViewModel', 'addTask'); + if (params?.isOpen) { + if (params?.isAlarm) { + useReminder(params, context); + } else { + isHasNotificationId(params?.taskID).then((flag: boolean) => { + if (flag) { + useCancelReminder(params.taskID, context); + } + }); + } + } else { + isHasNotificationId(params?.taskID).then((flag: boolean) => { + if (flag) { + useCancelReminder(params.taskID, context); + } + }); + } + TaskInfoApi.updateDataByDate(params, (flag: number) => { if (!flag) { Logger.error('insertTaskSetting', 'updateTaskSetting Error!'); reject(flag); } resolve(flag); - }) - TaskInfoApi.updateDataByDate({ ...params, date: TODAY, isDone: true }, (flag) => { + }); + let taskInfoStr = JSON.stringify(params); + let taskInfo: TaskInfo = JSON.parse(taskInfoStr); + taskInfo.date = new Date().toDateString(); + taskInfo.isDone = true; + TaskInfoApi.updateDataByDate(taskInfo, (flag: number) => { if (!flag) { Logger.error('insertTaskSetting', 'updateTaskSetting Error!'); reject(flag); } resolve(flag); - }) - }) + }); + }); } /** @@ -79,7 +145,7 @@ export const addTask = (params: TaskInfo) => { * @param taskInitList Task list initial data * @param taskInfoData Database query data */ -export const taskIndexDataInit = (taskInitList, taskInfoData) => { +export const taskIndexDataInit = (taskInitList: ITaskItem[], taskInfoData: TaskInfo[]) => { const afterInitData = taskInitList.map((content) => { taskInfoData.forEach((item) => { if (item?.taskID === content?.taskID) { @@ -100,7 +166,7 @@ export const taskIndexDataInit = (taskInitList, taskInfoData) => { * @description format data as json string * @param params = {} */ -export const formatParams = (params = {}) => { +export const formatParams = (params: ITaskItem) => { return JSON.stringify(params); } @@ -109,14 +175,14 @@ export const formatParams = (params = {}) => { * @param frequencyIdCollection * @return string Frequency string */ -export const initFrequencyString = (frequencyIdCollection) => { +export const initFrequencyString = (frequencyIdCollection: string) => { if (frequencyIdCollection === '') { - return EVERYDAY; + return Const.EVERYDAY; } - const frequencyIdArray = frequencyIdCollection.split(',').map(item => Number(item)); + const frequencyIdArray: Array = frequencyIdCollection.split(',').map(item => Number(item) - 1); const length = frequencyIdArray.length; if (length === 7) { - return EVERYDAY; + return Const.EVERYDAY; } const frequencyString = frequencyIdArray.reduce((pre, current) => { return pre + ' ' + oneWeek[current]; @@ -129,8 +195,8 @@ export const initFrequencyString = (frequencyIdCollection) => { * @param currentTime * @return timestamp */ -export const returnTimeStamp = (currentTime: string) => { - const timeString = `${TODAY} ${currentTime}`; +export function returnTimeStamp(currentTime: string) { + const timeString = `${new Date().toDateString()} ${currentTime}`; return new Date(timeString).getTime(); } @@ -139,7 +205,9 @@ export const returnTimeStamp = (currentTime: string) => { * @param value */ export const formatTime = (value: TimePickerResult) => { - return `${padTo2Digits(value?.hour)}:${padTo2Digits(value?.minute)}`; + let hour = value?.hour ? value?.hour : 8; + let minute = value?.minute ? value?.minute : 0; + return `${padTo2Digits(hour)}:${padTo2Digits(minute)}`; } /** @@ -147,9 +215,9 @@ export const formatTime = (value: TimePickerResult) => { * @return Array */ export const createDrinkRange = () => { - const drinkRangeArr = [] - for (let i = DRINK_STEP; i <= DRINK_MAX_RANGE; i += DRINK_STEP) { - drinkRangeArr.push(`${i / TIMES_100} L`); + const drinkRangeArr: Array = [] + for (let i = Const.DRINK_STEP; i <= Const.DRINK_MAX_RANGE; i += Const.DRINK_STEP) { + drinkRangeArr.push(`${i / Const.TIMES_100} L`); } return drinkRangeArr; } @@ -159,8 +227,8 @@ export const createDrinkRange = () => { * @return Array */ export const createAppleRange = () => { - const appleRangeArr = [] - for (let i = 1; i <= EAT_APPLE_RANGE; i++) { + const appleRangeArr: Array = []; + for (let i = 1; i <= Const.EAT_APPLE_RANGE; i++) { appleRangeArr.push(`${i} 个`); } return appleRangeArr; diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/WeekCalendarInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/WeekCalendarInfo.ets new file mode 100644 index 0000000000000000000000000000000000000000..723d78ad5d8ce22be07d4e3ba4579df322b287e3 --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/WeekCalendarInfo.ets @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022 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 { WeekDateModel } from '../model/WeekCalendarModel'; + +/** + * Week calendar info + * + */ +export default class WeekCalendarInfo { + arr: Array = []; + strArr: Array = []; +} \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/WeekCalendarMethodInfo.ets b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/WeekCalendarMethodInfo.ets new file mode 100644 index 0000000000000000000000000000000000000000..dc5697c647580b1677d6b85da9e66a8a901ef4d5 --- /dev/null +++ b/ExcellentCase/Healthy_life/entry/src/main/ets/viewmodel/WeekCalendarMethodInfo.ets @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Week Calendar Method Info + */ +export default class WeekCalendarMethodInfo { + gotoPreviousWeek: Function = () => {}; + goToNextWeek: Function = () => {}; + calenderItemClickAction: Function = () => {}; +} diff --git a/ExcellentCase/Healthy_life/entry/src/main/resources/base/element/color.json b/ExcellentCase/Healthy_life/entry/src/main/resources/base/element/color.json index d0ddb219d661e90faa0d1ac145fa33969fa8548a..47dead7c976a6cc37d74aa29a4de90a6085608b0 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/resources/base/element/color.json +++ b/ExcellentCase/Healthy_life/entry/src/main/resources/base/element/color.json @@ -63,6 +63,38 @@ { "name": "disabledColor", "value": "#dddadc" + }, + { + "name": "list_background_color", + "value": "#33000000" + }, + { + "name": "no_data_background", + "value": "#cc727272" + }, + { + "name": "text_common_color", + "value": "#182431" + }, + { + "name": "hex_common_color", + "value": "#99182431" + }, + { + "name": "progress_background_color", + "value": "#08000000" + }, + { + "name": "numerator_text_color", + "value": "#007DFF" + }, + { + "name": "denominator_text_color", + "value": "#72787E" + }, + { + "name": "progress_column_color", + "value": "#0d000000" } ] } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/resources/base/element/dimen.json b/ExcellentCase/Healthy_life/entry/src/main/resources/base/element/dimen.json index 6668e668c3ae7292737551a536d94781032f622b..9cbe1ba25a72bb1c5530eea0bb5aff6eefc6e45e 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/resources/base/element/dimen.json +++ b/ExcellentCase/Healthy_life/entry/src/main/resources/base/element/dimen.json @@ -135,6 +135,86 @@ { "name": "default_451", "value": "451vp" + }, + { + "name": "agency_item_margin", + "value": "6vp" + }, + { + "name": "agency_item_radius", + "value": "6vp" + }, + { + "name": "agency_padding_left", + "value": "12vp" + }, + { + "name": "agency_padding_top", + "value": "10vp" + }, + { + "name": "agency_padding_right", + "value": "6vp" + }, + { + "name": "agency_padding_bottom", + "value": "10vp" + }, + { + "name": "empty_data_size", + "value": "16fp" + }, + { + "name": "agency_image_size", + "value": "26vp" + }, + { + "name": "text_common_size", + "value": "14fp" + }, + { + "name": "agency_text_bold", + "value": "22fp" + }, + { + "name": "agency_row_padding", + "value": "15vp" + }, + { + "name": "progress_component_size", + "value": "108vp" + }, + { + "name": "progress_stroke_width", + "value": "13vp" + }, + { + "name": "percent_text_size", + "value": "27fp" + }, + { + "name": "percent_sign_size", + "value": "13fp" + }, + { + "name": "percent_sign_margin", + "value": "10vp" + }, + { + "name": "numerator_text_size", + "value": "15fp" + }, + { + "name": "numerator_line_height", + "value": "19vp" + }, + { + "name": "denominator_text_size", + "value": "15fp" + }, + { + "name": "denominator_line_height", + "value": "19vp" } ] } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/resources/en_US/element/string.json b/ExcellentCase/Healthy_life/entry/src/main/resources/en_US/element/string.json index 24cab575b83116946693a3793fe7f9d4c5fff93e..b8e525512e771ada965a23e5ac36b0a40192666d 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/resources/en_US/element/string.json +++ b/ExcellentCase/Healthy_life/entry/src/main/resources/en_US/element/string.json @@ -1,12 +1,36 @@ { "string": [ { - "name": "EntryAbility_desc", + "name": "module_desc", "value": "description" }, + { + "name": "EntryAbility_desc", + "value": "There's always a new way to play sports." + }, { "name": "EntryAbility_label", - "value": "label" + "value": "Healthy living" + }, + { + "name": "EntryFormAbility_desc", + "value": "form_description" + }, + { + "name": "EntryFormAbility_label", + "value": "form_label" + }, + { + "name": "agencyNoTask", + "value": "Go to Healthy Living to add tasks" + }, + { + "name": "task_reason", + "value": "Used to publish/cancel task reminders" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/entry/src/main/resources/zh_CN/element/string.json b/ExcellentCase/Healthy_life/entry/src/main/resources/zh_CN/element/string.json index 597ecf95e61d7e30367c22fe2f8638008361b044..c08cf9d7a24377e3683e62c22af108cfdb169b21 100644 --- a/ExcellentCase/Healthy_life/entry/src/main/resources/zh_CN/element/string.json +++ b/ExcellentCase/Healthy_life/entry/src/main/resources/zh_CN/element/string.json @@ -6,11 +6,31 @@ }, { "name": "EntryAbility_desc", - "value": "description" + "value": "运动总有新玩法" }, { "name": "EntryAbility_label", - "value": "label" + "value": "健康生活" + }, + { + "name": "EntryFormAbility_desc", + "value": "卡片创建,删除,修改,查询等操作入口" + }, + { + "name": "EntryFormAbility_label", + "value": "服务卡片" + }, + { + "name": "agencyNoTask", + "value": "请前往健康生活添加任务" + }, + { + "name": "task_reason", + "value": "用于发布/取消任务提醒" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/ExcellentCase/Healthy_life/figures/1.png b/ExcellentCase/Healthy_life/figures/1.png deleted file mode 100644 index ee8240bed773b6a801d76835fa38b6a8d365c7de..0000000000000000000000000000000000000000 Binary files a/ExcellentCase/Healthy_life/figures/1.png and /dev/null differ diff --git a/ExcellentCase/Healthy_life/figures/2.png b/ExcellentCase/Healthy_life/figures/2.png deleted file mode 100644 index 73d9724b1a49df7621983585d94cf72232548144..0000000000000000000000000000000000000000 Binary files a/ExcellentCase/Healthy_life/figures/2.png and /dev/null differ diff --git a/ExcellentCase/Healthy_life/figures/3.png b/ExcellentCase/Healthy_life/figures/3.png deleted file mode 100644 index 4c9c920e65efcfc311ce54debbb62e9d669cbb16..0000000000000000000000000000000000000000 Binary files a/ExcellentCase/Healthy_life/figures/3.png and /dev/null differ diff --git a/ExcellentCase/Healthy_life/figures/4.png b/ExcellentCase/Healthy_life/figures/4.png deleted file mode 100644 index fb2db2aeb6347c1a7bf4bf52f672bebab8275851..0000000000000000000000000000000000000000 Binary files a/ExcellentCase/Healthy_life/figures/4.png and /dev/null differ diff --git a/ExcellentCase/Healthy_life/hvigor/hvigor-config.json5 b/ExcellentCase/Healthy_life/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/ExcellentCase/Healthy_life/hvigor/hvigor-config.json5 +++ b/ExcellentCase/Healthy_life/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/ExcellentCase/Multi_device_V2/README.md b/ExcellentCase/Multi_device_V2/README.md index 43da80f8a0cb8a6c400739d96295b7e56bd29b04..da4132b058d2bb7ce83bd0e093d5327735a7d306 100644 --- a/ExcellentCase/Multi_device_V2/README.md +++ b/ExcellentCase/Multi_device_V2/README.md @@ -20,13 +20,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -54,16 +54,16 @@ ``` ├──common // 公共能力层 │ ├──src/main/ets -│ │ ├──bean // 资源类接口 -│ │ │ ├──BottomTabsItem.ets -│ │ │ ├──DriveTabsItem.ets -│ │ │ ├──FindTabsItem.ets -│ │ │ ├──HomeTabsItem.ets -│ │ │ └──MineTabsItem.ets │ │ ├──constants │ │ │ └──CommonConstants.ets // 公共常量类 -│ │ └──utils -│ │ └──BreakpointSystem.ets // 断点工具类 +│ │ ├──utils +│ │ │ └──BreakpointSystem.ets // 断点工具类 +│ │ └──viewmodel // 资源类接口 +│ │ ├──BottomTabsItem.ets +│ │ ├──DriveTabsItem.ets +│ │ ├──FindTabsItem.ets +│ │ ├──HomeTabsItem.ets +│ │ └──MineTabsItem.ets │ └──src/main/resources // 资源文件夹 └──product // 产品定制层 ├──default/src/main/ets // 支持手机(含折叠屏)、平板 @@ -223,7 +223,7 @@ export struct FindTabs { }) { ... // 榜单内容 } - }, item => JSON.stringify(item)) + }, (item: FindTabsItem) => JSON.stringify(item)) } } ... @@ -262,7 +262,7 @@ export struct DriveTabs { GridCol({ span: { xs: Const.NUM_2, sm: Const.NUM_2, md: Const.NUM_2, lg: Const.NUM_2 } }) { ... // 云盘内容 } - }, item => JSON.stringify(item)) + }, (item: DriveTabsItem) => JSON.stringify(item)) } } ... diff --git a/ExcellentCase/Multi_device_V2/common/index.ets b/ExcellentCase/Multi_device_V2/common/index.ets index 46a5f34105a73b3ce0df146bee708149f168a1c7..f8b8ccd8ba8cb2f0cc9898476e78c2295d04b954 100644 --- a/ExcellentCase/Multi_device_V2/common/index.ets +++ b/ExcellentCase/Multi_device_V2/common/index.ets @@ -13,10 +13,10 @@ * limitations under the License. */ -export type { BottomTabsItem } from './src/main/ets/bean/BottomTabsItem'; -export type { HomeTabsItem } from './src/main/ets/bean/HomeTabsItem'; -export type { FindTabsItem } from './src/main/ets/bean/FindTabsItem'; -export type { DriveTabsItem } from './src/main/ets/bean/DriveTabsItem'; -export type { MineTabsItem } from './src/main/ets/bean/MineTabsItem'; +export { BottomTabsItem } from './src/main/ets/viewmodel/BottomTabsItem'; +export { HomeTabsItem } from './src/main/ets/viewmodel/HomeTabsItem'; +export { FindTabsItem } from './src/main/ets/viewmodel/FindTabsItem'; +export { DriveTabsItem } from './src/main/ets/viewmodel/DriveTabsItem'; +export { MineTabsItem } from './src/main/ets/viewmodel/MineTabsItem'; export { CommonConstants } from './src/main/ets/constants/CommonConstants'; export { BreakpointSystem } from './src/main/ets/utils/BreakpointSystem'; diff --git a/ExcellentCase/Multi_device_V2/common/src/main/ets/utils/BreakpointSystem.ets b/ExcellentCase/Multi_device_V2/common/src/main/ets/utils/BreakpointSystem.ets index f4fd02119cdd67e13226e5b6d07244e184050d72..6c10566cba95d3b2aa9b3b602457311e799fd61c 100644 --- a/ExcellentCase/Multi_device_V2/common/src/main/ets/utils/BreakpointSystem.ets +++ b/ExcellentCase/Multi_device_V2/common/src/main/ets/utils/BreakpointSystem.ets @@ -18,9 +18,9 @@ import { CommonConstants as Const } from '../constants/CommonConstants'; export class BreakpointSystem { private currentBreakpoint: string = Const.MD; - private smListener: mediaQuery.MediaQueryListener; - private mdListener: mediaQuery.MediaQueryListener; - private lgListener: mediaQuery.MediaQueryListener; + private smListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(Const.BREAKPOINTS_SCOPE_1); + private mdListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(Const.BREAKPOINTS_SCOPE_2); + private lgListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(Const.BREAKPOINTS_SCOPE_3); private updateCurrentBreakpoint(breakpoint: string) { if (this.currentBreakpoint !== breakpoint) { @@ -29,19 +29,19 @@ export class BreakpointSystem { } } - private isBreakpointSM = (mediaQueryResult) => { + private isBreakpointSM = (mediaQueryResult: mediaQuery.MediaQueryResult) => { if (mediaQueryResult.matches) { this.updateCurrentBreakpoint(Const.SM); } } - private isBreakpointMD = (mediaQueryResult) => { + private isBreakpointMD = (mediaQueryResult: mediaQuery.MediaQueryResult) => { if (mediaQueryResult.matches) { this.updateCurrentBreakpoint(Const.MD); } } - private isBreakpointLG = (mediaQueryResult) => { + private isBreakpointLG = (mediaQueryResult: mediaQuery.MediaQueryResult) => { if (mediaQueryResult.matches) { this.updateCurrentBreakpoint(Const.LG); } diff --git a/ExcellentCase/Multi_device_V2/common/src/main/ets/bean/BottomTabsItem.ets b/ExcellentCase/Multi_device_V2/common/src/main/ets/viewmodel/BottomTabsItem.ets similarity index 100% rename from ExcellentCase/Multi_device_V2/common/src/main/ets/bean/BottomTabsItem.ets rename to ExcellentCase/Multi_device_V2/common/src/main/ets/viewmodel/BottomTabsItem.ets diff --git a/ExcellentCase/Multi_device_V2/common/src/main/ets/bean/DriveTabsItem.ets b/ExcellentCase/Multi_device_V2/common/src/main/ets/viewmodel/DriveTabsItem.ets similarity index 100% rename from ExcellentCase/Multi_device_V2/common/src/main/ets/bean/DriveTabsItem.ets rename to ExcellentCase/Multi_device_V2/common/src/main/ets/viewmodel/DriveTabsItem.ets diff --git a/ExcellentCase/Multi_device_V2/common/src/main/ets/bean/FindTabsItem.ets b/ExcellentCase/Multi_device_V2/common/src/main/ets/viewmodel/FindTabsItem.ets similarity index 100% rename from ExcellentCase/Multi_device_V2/common/src/main/ets/bean/FindTabsItem.ets rename to ExcellentCase/Multi_device_V2/common/src/main/ets/viewmodel/FindTabsItem.ets diff --git a/ExcellentCase/Multi_device_V2/common/src/main/ets/bean/HomeTabsItem.ets b/ExcellentCase/Multi_device_V2/common/src/main/ets/viewmodel/HomeTabsItem.ets similarity index 100% rename from ExcellentCase/Multi_device_V2/common/src/main/ets/bean/HomeTabsItem.ets rename to ExcellentCase/Multi_device_V2/common/src/main/ets/viewmodel/HomeTabsItem.ets diff --git a/ExcellentCase/Multi_device_V2/common/src/main/ets/bean/MineTabsItem.ets b/ExcellentCase/Multi_device_V2/common/src/main/ets/viewmodel/MineTabsItem.ets similarity index 100% rename from ExcellentCase/Multi_device_V2/common/src/main/ets/bean/MineTabsItem.ets rename to ExcellentCase/Multi_device_V2/common/src/main/ets/viewmodel/MineTabsItem.ets diff --git a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/BottomTabsComponent.ets b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/BottomTabsComponent.ets index 56adfd1ca97ab13ea2d96a299b3ceaf7f28e7b4e..a0763add421d646e2ee82146879ba5d3d8439395 100644 --- a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/BottomTabsComponent.ets +++ b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/BottomTabsComponent.ets @@ -55,7 +55,7 @@ export struct BottomTabs { .onClick(() => { this.bottomTabIndex = BottomTabsList.indexOf(item); }) - }, item => JSON.stringify(item)) + }, (item: BottomTabsItem) => JSON.stringify(item)) } .width(Const.FULL_SIZE) .height(Const.BOTTOM_TAB_HEIGHT) diff --git a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/DriveTabsComponent.ets b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/DriveTabsComponent.ets index b92dbc2f2008e409265ce4c1f8a118366f75b3e6..6da265fbc85c35ce0571655b81edba8981a15ded 100644 --- a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/DriveTabsComponent.ets +++ b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/DriveTabsComponent.ets @@ -63,7 +63,7 @@ export struct DriveTabs { .margin({ bottom: $r('app.float.drive_text_margin') }) } } - }, item => JSON.stringify(item)) + }, (item: DriveTabsItem) => JSON.stringify(item)) } } .width(Const.FULL_SIZE) diff --git a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/FindTabsComponent.ets b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/FindTabsComponent.ets index 567d03152ec1eff359c38f1c95fff6999f86b092..71ec0fd216869400a6eb83f3f1c5fbe31af9f9c6 100644 --- a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/FindTabsComponent.ets +++ b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/FindTabsComponent.ets @@ -121,7 +121,7 @@ export struct FindTabs { .width(Const.FULL_SIZE) .margin({ bottom: $r('app.float.find_margin5') }) } - }, item => JSON.stringify(item)) + }, (item: FindTabsItem) => JSON.stringify(item)) } } .width(Const.FULL_SIZE) diff --git a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/HomeTabsComponent.ets b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/HomeTabsComponent.ets index afd8114750499d07072cd482887f23764e1fedf2..7d5cb51421f418778ec010e6d71c66c03dab4ec5 100644 --- a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/HomeTabsComponent.ets +++ b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/HomeTabsComponent.ets @@ -78,7 +78,7 @@ export struct HomeTabs { .alignItems(HorizontalAlign.Start) .margin({ top: $r('app.float.home_text_margin_3'), left: $r('app.float.home_text_margin_2') }) } - }, item => JSON.stringify(item)) + }, (item: HomeTabsItem) => JSON.stringify(item)) } .height($r('app.float.home_swiper_height')) .itemSpace(Const.ITEM_SPACE) diff --git a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/LeftTabsComponent.ets b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/LeftTabsComponent.ets index 35da456551ff4fc2071b5643b6b3985cccbd0544..269a279c7e82171d7d33e1888fb9658b1578dde9 100644 --- a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/LeftTabsComponent.ets +++ b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/LeftTabsComponent.ets @@ -60,7 +60,7 @@ export struct LeftTabs { .onClick(() => { this.bottomTabIndex = BottomTabsList.indexOf(item); }) - }, item => JSON.stringify(item)) + }, (item: BottomTabsItem) => JSON.stringify(item)) Row() .width(Const.FULL_SIZE) diff --git a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/MineTabsComponent.ets b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/MineTabsComponent.ets index a32bf3888312971f75b55630e032f50143692cdd..d80cab1c8d111f4b78c39771a14170ab780ddcf5 100644 --- a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/MineTabsComponent.ets +++ b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/MineTabsComponent.ets @@ -67,7 +67,7 @@ export struct MineTabs { } .width(Const.FULL_SIZE) .height($r('app.float.mine_list_height')) - }, item => JSON.stringify(item)) + }, (item: MineTabsItem) => JSON.stringify(item)) } .width(Const.FULL_SIZE) .height(Const.FULL_SIZE) diff --git a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/RecentlyPlayedComponent.ets b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/RecentlyPlayedComponent.ets index 937d34856848e96960a3bbf72f751a3a8028f544..af99903ff3710a4dca37c19c37f21f73f1476197 100644 --- a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/RecentlyPlayedComponent.ets +++ b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/RecentlyPlayedComponent.ets @@ -59,7 +59,7 @@ export struct RecentlyPlayed { .opacity(Const.OPACITY) } } - }, item => JSON.stringify(item)) + }, (item: HomeTabsItem) => JSON.stringify(item)) } .width(Const.FULL_SIZE) .height($r('app.float.home_row_height1')) diff --git a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/RecommendedComponent.ets b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/RecommendedComponent.ets index c888bbd31fc74611c3785cca0459a33b6538020b..ebe973beca1c536fc380b425ddce193ee1ee324e 100644 --- a/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/RecommendedComponent.ets +++ b/ExcellentCase/Multi_device_V2/product/default/src/main/ets/view/RecommendedComponent.ets @@ -49,7 +49,7 @@ export struct Recommended { .margin({ bottom: $r('app.float.home_margin1') }) } } - }, item => JSON.stringify(item)) + }, (item: HomeTabsItem) => JSON.stringify(item)) } .width(Const.FULL_SIZE) .height($r('app.float.home_list_height2')) diff --git a/GraphicImage/GestureScreenshot/README.md b/GraphicImage/GestureScreenshot/README.md index 715fda0f583189f1fc31ef8b7c2206d27f9dad08..89b5d331332aed4a407d047fff3da6ee19c02262 100644 --- a/GraphicImage/GestureScreenshot/README.md +++ b/GraphicImage/GestureScreenshot/README.md @@ -4,75 +4,76 @@ 本篇Codelab基于手势处理和截屏能力,介绍了手势截屏的实现过程。样例主要包括以下功能: -1. 根据下滑手势调用全屏截图功能。 -2. 全屏截图,同时右下角有弹窗提示截图成功。 -3. 根据双击手势调用区域截图功能。 -4. 区域截图,通过调整选择框大小完成。 +1. 根据下滑手势调用全屏截图功能。 +2. 全屏截图,同时右下角有弹窗提示截图成功。 +3. 根据双击手势调用区域截图功能。 +4. 区域截图,通过调整选择框大小完成。 ![](./figures/GestureScreenshot.gif) ### 相关概念 -- [Canvas](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-components-canvas-canvas.md):画布组件,用于自定义绘制图形。 -- [CanvasRenderingContext2D对象](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-canvasrenderingcontext2d.md):使用RenderingContext在Canvas组件上进行绘制,绘制对象可以是矩形、文本、图片等。 -- [双击手势](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-tapgesture.md):手指双击屏幕回调事件。 -- [手指滑动手势](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-pangesture.md):手指在屏幕滑动回调事件。 +- [Canvas](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-components-canvas-canvas.md):画布组件,用于自定义绘制图形。 +- [CanvasRenderingContext2D对象](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-canvasrenderingcontext2d.md):使用RenderingContext在Canvas组件上进行绘制,绘制对象可以是矩形、文本、图片等。 +- [双击手势](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-tapgesture.md):手指双击屏幕回调事件。 +- [手指滑动手势](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-pangesture.md):手指在屏幕滑动回调事件。 ### 相关权限 -- 本篇Codelab用到屏幕截图的能力,需要在配置文件module.json5里添加屏幕截图的权限:ohos.permission.CAPTURE\_SCREEN。 -- 本篇Codelab需要使用的screenshot为系统接口。需要使用Full SDK手动从镜像站点获取,并在DevEco Studio中替换,具体操作可参考[替换指南](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/faqs/full-sdk-switch-guide.md)。 +- 本篇Codelab用到屏幕截图的能力,需要在配置文件module.json5里添加屏幕截图的权限:ohos.permission.CAPTURE\_SCREEN。 +- 本篇Codelab需要使用的screenshot为系统接口。需要使用Full SDK手动从镜像站点获取,并在DevEco Studio中替换,具体操作可参考[替换指南](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/faqs/full-sdk-switch-guide.md)。 +- 本篇Codelab使用的部分API仅系统应用可用,需要提升应用等级为system_core。具体可参考指南[《访问控制授权申请指导》](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-overview.md#%E5%BA%94%E7%94%A8apl%E7%AD%89%E7%BA%A7%E8%AF%B4%E6%98%8E)。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 -- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: -1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以3.2 Release版本为例: +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以3.2 Release版本为例: ![](figures/zh-cn_image_0000001569303293.png) -2. 搭建烧录环境。 - 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) - 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) -3. 搭建开发环境。 - 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 - 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 - 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 ## 代码结构解读 本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 ``` -├──entry/src/main/ets // 代码区 +├──entry/src/main/ets // 代码区 │ ├──common │ │ └──utils │ │ ├──CommonConstants.ets // 公共常量类 │ │ ├──DrawUtil.ets // 画布相关工具类 -│ │ └──Logger.ets // 日志打印类 +│ │ └──Logger.ets // 日志打印类 │ ├──entryability -│ │ └──EntryAbility.ts // 程序入口类 +│ │ └──EntryAbility.ets // 程序入口类 │ ├──model │ │ └──OffsetModel.ets // 区域截图坐标相关工具类 │ ├──pages -│ │ └──Index.ets // 主界面 +│ │ └──GestureScreenshot.ets // 主界面 │ └──view │ ├──AreaScreenshot.ets // 自定义区域截屏组件类 │ └──ScreenshotDialog.ets // 自定义截屏显示弹窗组件类 -└──entry/src/main/resources // 资源文件目录 +└──entry/src/main/resources // 资源文件目录 ``` ## 构建截屏主页面 @@ -83,9 +84,9 @@ 主界面主要实现以下功能: -1. 下滑手势绑定在主界面上,双击手势绑定在区域手势的最底层Stack组件上。 -2. 如果使用下滑手势,就进行全屏截图并展示图片。 -3. 如果使用双击手势,就唤起区域截图相关组件。 +1. 下滑手势绑定在主界面上,双击手势绑定在区域手势的最底层Stack组件上。 +2. 如果使用下滑手势,就进行全屏截图并展示图片。 +3. 如果使用双击手势,就唤起区域截图相关组件。 ```typescript // GestureScreenshot.ets @@ -95,45 +96,47 @@ Stack() { Column() { ... }) - // 添加滑动手势事件 - .gesture( - // fingers:触发手指数 direction:触发方向 distance:触发滑动距离 - PanGesture({ fingers: 1, direction: PanDirection.Down, distance: CommonConstants.MINIMUM_FINGER_DISTANCE }) - // 触发开始回调 - .onActionStart(() => { - let ScreenshotOptions = { - rotation: 0 - }; - screenshot.save(ScreenshotOptions, (err, data: image.PixelMap) => { - if (err) { - Logger.error(`Failed to save the screenshot. Error:${ JSON.stringify(err) }`); - } - if (this.pixelMap !== undefined) { - this.pixelMap.release(); - } - this.pixelMap = data; - this.dialogController.open(); - }); - }) - ) - .scale(this.scaleNum) - - // 区域截图相关组件 - AreaScreenshot({ showScreen: $showScreen, pixelMap: $pixelMap, scaleNum: $scaleNum }); -} - .backgroundColor($r('app.color.black_area')) - // 添加双击手势事件 + // 添加滑动手势事件 .gesture( - TapGesture({ count: 2 }) - .onAction(() => { - this.showScreen = true; - this.scaleNum = { - x: CommonConstant.X_SCALE_DOWN, - y: CommonConstant.Y_SCALE_DOWN - } + // fingers:触发手指数 direction:触发方向 distance:触发滑动距离 + PanGesture({ + fingers: 1, + direction: PanDirection.Down, + distance: CommonConstants.MINIMUM_FINGER_DISTANCE + })// 触发开始回调 + .onActionStart(() => { + let screenshotOptions: screenshot.ScreenshotOptions = { + rotation: 0 + }; + screenshot.save(screenshotOptions, (err: Error, data: image.PixelMap) => { + if (err) { + Logger.error(`Failed to save the screenshot. Error:${ JSON.stringify(err) }`); + } + if (this.pixelMap !== undefined) { + this.pixelMap.release(); + } + this.pixelMap = data; + this.dialogController.open(); + }); }) ) + .scale(this.scaleNum) + + // 区域截图相关组件 + AreaScreenshot({ showScreen: this.showScreen, pixelMap: this.pixelMap, scaleNum: this.scaleNum }) } +.backgroundColor($r('app.color.black_area')) +// 添加双击手势事件 +.gesture( + TapGesture({ count: 2 }) + .onAction(() => { + this.showScreen = true; + this.scaleNum = { + x: CommonConstants.X_SCALE_DOWN, + y: CommonConstants.Y_SCALE_DOWN + } + }) +) ``` ## 构建区域截图组件 @@ -152,7 +155,7 @@ aboutToAppear() { let property = window.getWindowProperties(); this.systemBarHeight = property.windowRect.top; - drawMUtil.initDrawUtil( + drawUtil.initDrawUtil( this.canvasRenderingContext, px2vp(property.windowRect.width), px2vp(property.windowRect.height) @@ -166,7 +169,7 @@ aboutToAppear() { // 在展示截图的时候,用于计算图片大小 this.screenAspectRatio = px2vp(property.windowRect.height) / px2vp(property.windowRect.width); }) - .catch((err) => { + .catch((err: Error) => { Logger.error(`window loading has error: ${ JSON.stringify(err) }`); }) } @@ -174,11 +177,11 @@ aboutToAppear() { 在AreaScreenshot.ets布局页面中添加Canvas组件,通过showScreen变量控制局部截屏页面的显示,并控制主页面的缩放。步骤如下: -1. 根据手指按下的位置确定需要移动的边框。 -2. 手指移动后,更新offsetModel记录的坐标信息。 -3. 根据offsetModel提供的坐标,使用drawUtil绘制区域选择框。 -4. 点击保存按钮后,设置截屏区域坐标。 -5. 根据截屏区域坐标进行区域截屏。 +1. 根据手指按下的位置确定需要移动的边框。 +2. 手指移动后,更新offsetModel记录的坐标信息。 +3. 根据offsetModel提供的坐标,使用drawUtil绘制区域选择框。 +4. 点击保存按钮后,设置截屏区域坐标。 +5. 根据截屏区域坐标进行区域截屏。 ```typescript // AreaScreenshot.ets @@ -207,23 +210,23 @@ if (this.showScreen) { // 区域截图并展示图像 Image($r('app.media.ic_save')) .onClick(() => { - let ScreenshotOptions = { + let screenshotOptions: screenshot.ScreenshotOptions = { // 截屏区域Rect参数 screenRect: { left: vp2px(offsetModel.getXLeft()), top: vp2px(offsetModel.getYTop()) + this.systemBarHeight, width: vp2px(offsetModel.getWidth()), height: vp2px(offsetModel.getHeight()) - }, + } as screenshot.Rect, // 截图的大小 imageSize: { width: vp2px(offsetModel.getWidth()), height: vp2px(offsetModel.getHeight()) - }, + } as screenshot.Size, rotation: 0, displayId: 0 }; - screenshot.save(ScreenshotOptions, (err, data: image.PixelMap) => { + screenshot.save(screenshotOptions, (err: Error, data: image.PixelMap) => { if (err) { Logger.error(`Failed to save the screenshot. Error:${JSON.stringify(err)}`); } @@ -243,8 +246,8 @@ if (this.showScreen) { switch(event.type) { case TouchType.Down: // 根据手指位置,判断移动哪个坐标 - this.offsetModel.setXLocationType(event.touches[0].screenX); - this.offsetModel.setYLocationType(event.touches[0].screenY); + offsetModel.setXLocationType(event.touches[0].screenX); + offsetModel.setYLocationType(event.touches[0].screenY); break; case TouchType.Move: // 更新坐标信息,并保证坐标值合法 @@ -264,14 +267,14 @@ if (this.showScreen) { 使用OffsetModel校验坐标的范围,并保存坐标相关信息。 -1. 在初始化对象的时候,根据屏幕的缩放比例计算出黑色区域的宽高。 -2. 使用setXLocationType方法和setYLocationType方法,判断需要移动的x、y坐标位置。 -3. 根据传入的x、y坐标值,更改offset对应的坐标值,并保证选择框的宽高大于等于预设的选择框的最小值。 -4. 再次校验offset坐标值,是否超出可截屏区域。 +1. 在初始化对象的时候,根据屏幕的缩放比例计算出黑色区域的宽高。 +2. 使用setXLocationType方法和setYLocationType方法,判断需要移动的x、y坐标位置。 +3. 根据传入的x、y坐标值,更改offset对应的坐标值,并保证选择框的宽高大于等于预设的选择框的最小值。 +4. 再次校验offset坐标值,是否超出可截屏区域。 ```typescript // OffsetModel.ets -constructor(width: number, height: number) { +public initOffsetModel(width: number, height: number) { ... this.blackAreaWidth = this.screenWidth * (1 - CommonConstant.X_SCALE_DOWN); this.blackAreaWidth = this.blackAreaWidth / CommonConstant.BLACK_AREA_NUM; @@ -374,9 +377,7 @@ private drawLines() { (this.offsetXLeft - Constants.GAP_WIDTH), (this.offsetYTop + Constants.LINES_MAX_LENGTH) ); - ... - this.canvasContext.stroke(); } ``` @@ -385,24 +386,26 @@ private drawLines() { 本篇Codelab采用弹窗组件展示截屏,需要在aboutToAppear方法中计算对应的宽度: -1. 截图长宽比小于或者等于屏幕长宽比:此截图展示时和全屏截图展示时等宽。 -2. 截图长宽比大于屏幕长宽比:此截图展示时和全屏截图展示时等长,通过计算对应的宽来实现。 +1. 截图长宽比小于或者等于屏幕长宽比:此截图展示时和全屏截图展示时等宽。 +2. 截图长宽比大于屏幕长宽比:此截图展示时和全屏截图展示时等长,通过计算对应的宽来实现。 ```typescript -// ScreenShot.ets +// ScreenshotDialog.ets aboutToAppear() { this.getDialogWidth(); } ... private async getDialogWidth() { - let info = await this.pixelMap.getImageInfo(); - let pixelMapAspectRatio = info.size.height / info.size.width; - - if ((this.screenAspectRatio !== -1) && (pixelMapAspectRatio > this.screenAspectRatio)) { - let width = CommonConstants.HEIGHT_FIRST / pixelMapAspectRatio * this.screenAspectRatio; - this.dialogWidth = width + '%'; - } else { - this.dialogWidth = CommonConstants.WIDTH_FIRST; + if (this.pixelMap !== undefined) { + let info = await this.pixelMap.getImageInfo(); + let pixelMapAspectRatio = info.size.height / info.size.width; + + if ((this.screenAspectRatio !== -1) && (pixelMapAspectRatio > this.screenAspectRatio)) { + let width = CommonConstants.HEIGHT_FIRST / pixelMapAspectRatio * this.screenAspectRatio; + this.dialogWidth = width + '%'; + } else { + this.dialogWidth = CommonConstants.WIDTH_FIRST; + } } } ``` @@ -411,8 +414,8 @@ private async getDialogWidth() { 您已经完成了本次Codelab的学习,并了解到以下知识点: -1. 使用Canvas绘制区域选择框。 -2. 使用手势事件。 -3. 进行全屏截图和区域截图。 +1. 使用Canvas绘制区域选择框。 +2. 使用手势事件。 +3. 进行全屏截图和区域截图。 ![](figures/zh-cn_image_0000001580558789.gif) diff --git a/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/CommonConstaint.ets b/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/CommonConstaint.ets index 6a1cfc5126c17c56b3e0488a072c4b96f3e31376..fec92c4be14eeaf836c6d81f5c11e8ba83272da3 100644 --- a/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/CommonConstaint.ets +++ b/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/CommonConstaint.ets @@ -13,10 +13,22 @@ * limitations under the License. */ +interface XLocationEnumInterface { + XLeft: number, + XRight: number, + noChange: number +} + +interface YLocationEnumInterface { + YTop: number, + YBottom: number, + noChange: number +} + /** * The x location to be changed. */ -export const XLocationEnum = { +export const XLocationEnum: XLocationEnumInterface = { XLeft: 0, XRight: 1, noChange: -1 @@ -25,12 +37,17 @@ export const XLocationEnum = { /** * The y location to be changed. */ -export const YLocationEnum = { +export const YLocationEnum: YLocationEnumInterface = { YTop: 0, YBottom: 1, noChange: -1 } +export interface ScaleInterface { + x: number, + y: number +} + /** * Common constants for project. */ diff --git a/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/DrawUtil.ets b/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/DrawUtil.ets index df1a6244afcb62aa0de86652d04f6ad8cfb11902..094459273c9c6d98906bdab77db6a7368e6e98af 100644 --- a/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/DrawUtil.ets +++ b/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/DrawUtil.ets @@ -20,7 +20,8 @@ import offsetModel from '../../model/OffsetModel'; export class DrawUtil { private screenWidth: number = 0; private screenHeight: number = 0; - private canvasContext: CanvasRenderingContext2D; + private settings: RenderingContextSettings = new RenderingContextSettings(true); + private canvasContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); private offsetXLeft: number = 0; private offsetXRight: number = 0; private offsetYTop: number = 0; diff --git a/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/Logger.ets b/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/Logger.ets index cf720316962602d49e020113573c0b8290c550f2..8350f92c2f35da4daa6d3106e754ea85884d071f 100644 --- a/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/Logger.ets +++ b/GraphicImage/GestureScreenshot/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/GraphicImage/GestureScreenshot/entry/src/main/ets/entryability/EntryAbility.ts b/GraphicImage/GestureScreenshot/entry/src/main/ets/entryability/EntryAbility.ets similarity index 100% rename from GraphicImage/GestureScreenshot/entry/src/main/ets/entryability/EntryAbility.ts rename to GraphicImage/GestureScreenshot/entry/src/main/ets/entryability/EntryAbility.ets diff --git a/GraphicImage/GestureScreenshot/entry/src/main/ets/pages/GestureScreenshot.ets b/GraphicImage/GestureScreenshot/entry/src/main/ets/pages/GestureScreenshot.ets index d97cdfc57538c694f0e1e46a297784cff60dffe0..fe1c1448c9e800e36da928d5e3974292dd499f8d 100644 --- a/GraphicImage/GestureScreenshot/entry/src/main/ets/pages/GestureScreenshot.ets +++ b/GraphicImage/GestureScreenshot/entry/src/main/ets/pages/GestureScreenshot.ets @@ -18,19 +18,18 @@ import image from '@ohos.multimedia.image'; import AreaScreenshot from '../view/AreaScreenshot'; import Logger from '../common/utils/Logger'; import ScreenshotDialog from '../view/ScreenshotDialog'; -import CommonConstant from '../common/utils/CommonConstaint'; import CommonConstants from '../common/utils/CommonConstaint'; +import { ScaleInterface } from '../common/utils/CommonConstaint'; @Entry @Component struct GestureScreenshot { - @State pixelMap: image.PixelMap = undefined; + @State pixelMap: image.PixelMap| undefined = undefined; @State showScreen: boolean = false; - @State scaleNum: Object = { - x: CommonConstant.NO_SCALE_DOWN, - y: CommonConstant.NO_SCALE_DOWN + @State scaleNum: ScaleInterface = { + x: CommonConstants.NO_SCALE_DOWN, + y: CommonConstants.NO_SCALE_DOWN }; - dialogController: CustomDialogController = new CustomDialogController({ builder: ScreenshotDialog({ pixelMap: this.pixelMap }), alignment: DialogAlignment.BottomEnd, @@ -42,7 +41,7 @@ struct GestureScreenshot { Column() { Text($r('app.string.title_content')) .fontSize($r('app.float.title_font_size')) - .fontWeight(CommonConstant.TITLE_FONT_WEIGHT) + .fontWeight(CommonConstants.TITLE_FONT_WEIGHT) .width(CommonConstants.FULL_PARAM) .textAlign(TextAlign.Start) Image($r('app.media.ic_mountain')) @@ -56,24 +55,27 @@ struct GestureScreenshot { .lineHeight($r('app.float.text_height')) } .backgroundColor($r('app.color.main_area')) - .width(CommonConstant.FULL_PARAM) - .height(CommonConstant.FULL_PARAM) + .width(CommonConstants.FULL_PARAM) + .height(CommonConstants.FULL_PARAM) .padding({ left: $r('app.float.main_margin_size'), right: $r('app.float.main_margin_size') }) .gesture( // fingers:The number of Trigger Fingers,direction:Triggering direction,distance:Trigger sliding distance. - PanGesture({ fingers: 1, direction: PanDirection.Down, distance: CommonConstants.MINIMUM_FINGER_DISTANCE }) - // Trigger Start Callback. + PanGesture({ + fingers: 1, + direction: PanDirection.Down, + distance: CommonConstants.MINIMUM_FINGER_DISTANCE + })// Trigger Start Callback. .onActionStart(() => { // Screenshot Parameters and APIs. - let ScreenshotOptions = { + let screenshotOptions: screenshot.ScreenshotOptions = { rotation: 0 }; - screenshot.save(ScreenshotOptions, (err, data: image.PixelMap) => { + screenshot.save(screenshotOptions, (err: Error, data: image.PixelMap) => { if (err) { - Logger.error(`Failed to save the screenshot. Error:${ JSON.stringify(err) }`); + Logger.error(`Failed to save the screenshot. Error:${JSON.stringify(err)}`); } if (this.pixelMap !== undefined) { this.pixelMap.release(); @@ -85,7 +87,7 @@ struct GestureScreenshot { ) .scale(this.scaleNum) - AreaScreenshot({ showScreen: $showScreen, pixelMap: $pixelMap, scaleNum: $scaleNum }) + AreaScreenshot({ showScreen: this.showScreen, pixelMap: this.pixelMap, scaleNum: this.scaleNum }) } .backgroundColor($r('app.color.black_area')) .gesture( @@ -93,8 +95,8 @@ struct GestureScreenshot { .onAction(() => { this.showScreen = true; this.scaleNum = { - x: CommonConstant.X_SCALE_DOWN, - y: CommonConstant.Y_SCALE_DOWN + x: CommonConstants.X_SCALE_DOWN, + y: CommonConstants.Y_SCALE_DOWN } }) ) diff --git a/GraphicImage/GestureScreenshot/entry/src/main/ets/view/AreaScreenshot.ets b/GraphicImage/GestureScreenshot/entry/src/main/ets/view/AreaScreenshot.ets index d3bdb94872d4740bad551ca1c7fe7dff2ad5da59..6682e6774be336a3b91b352e6d944421db339e97 100644 --- a/GraphicImage/GestureScreenshot/entry/src/main/ets/view/AreaScreenshot.ets +++ b/GraphicImage/GestureScreenshot/entry/src/main/ets/view/AreaScreenshot.ets @@ -21,6 +21,7 @@ import ScreenshotDialog from './ScreenshotDialog'; import drawUtil from '../common/utils/DrawUtil'; import offsetModel from '../model/OffsetModel'; import CommonConstants from '../common/utils/CommonConstaint'; +import { ScaleInterface } from '../common/utils/CommonConstaint'; /** * Custom component to determine the screenshot area. @@ -29,7 +30,7 @@ import CommonConstants from '../common/utils/CommonConstaint'; export default struct AreaScreenShot { @Link showScreen: boolean; @Link pixelMap: image.PixelMap; - @Link scaleNum: Object; + @Link scaleNum: ScaleInterface; private screenAspectRatio: number = 0; dialogController: CustomDialogController = new CustomDialogController({ builder: ScreenshotDialog({ @@ -62,8 +63,8 @@ export default struct AreaScreenShot { this.screenAspectRatio = px2vp(property.windowRect.height) / px2vp(property.windowRect.width); }) - .catch((err) => { - Logger.error(`window loading has error: ${ JSON.stringify(err) }`); + .catch((err: Error) => { + Logger.error(`window loading has error: ${JSON.stringify(err)}`); }) } @@ -105,21 +106,21 @@ export default struct AreaScreenShot { Image($r('app.media.ic_save')) .onClick(() => { - let ScreenshotOptions = { + let screenshotOptions: screenshot.ScreenshotOptions = { screenRect: { left: vp2px(offsetModel.getXLeft()), top: vp2px(offsetModel.getYTop()) + this.systemBarHeight, width: vp2px(offsetModel.getWidth()), height: vp2px(offsetModel.getHeight()) - }, + } as screenshot.Rect, imageSize: { width: vp2px(offsetModel.getWidth()), height: vp2px(offsetModel.getHeight()) - }, + } as screenshot.Size, rotation: 0, displayId: 0 }; - screenshot.save(ScreenshotOptions, (err, data: image.PixelMap) => { + screenshot.save(screenshotOptions, (err: Error, data: image.PixelMap) => { if (err) { Logger.error(`Failed to save the screenshot. Error:${JSON.stringify(err)}`); } @@ -141,7 +142,7 @@ export default struct AreaScreenShot { .height(CommonConstants.FULL_PARAM) .alignContent(Alignment.Top) .onTouch((event: TouchEvent) => { - switch(event.type) { + switch (event.type) { case TouchType.Down: offsetModel.setXLocationType(event.touches[0].screenX); offsetModel.setYLocationType(event.touches[0].screenY); diff --git a/GraphicImage/GestureScreenshot/entry/src/main/ets/view/ScreenshotDialog.ets b/GraphicImage/GestureScreenshot/entry/src/main/ets/view/ScreenshotDialog.ets index 5f88c38fedc48044d46257ee0a4dfe9eeae8c607..49de356d887994f12caf071901f88e505b5610be 100644 --- a/GraphicImage/GestureScreenshot/entry/src/main/ets/view/ScreenshotDialog.ets +++ b/GraphicImage/GestureScreenshot/entry/src/main/ets/view/ScreenshotDialog.ets @@ -19,7 +19,7 @@ import CommonConstants from '../common/utils/CommonConstaint'; export default struct ScreenshotDialog { @State dialogWidth: string = CommonConstants.WIDTH_FIRST; controller: CustomDialogController; - private pixelMap: PixelMap = null; + private pixelMap?: PixelMap; private screenAspectRatio: number = -1; aboutToAppear() { @@ -38,7 +38,7 @@ export default struct ScreenshotDialog { .width(CommonConstants.FULL_PARAM) .justifyContent(FlexAlign.End) Row() { - Image(this.pixelMap) + Image(this.pixelMap !== undefined ? this.pixelMap : '') .width(CommonConstants.IMAGE_ON_DIALOG) .margin(CommonConstants.IMAGE_MARGIN) .objectFit(ImageFit.Contain) @@ -54,14 +54,16 @@ export default struct ScreenshotDialog { } private async getDialogWidth() { - let info = await this.pixelMap.getImageInfo(); - let pixelMapAspectRatio = info.size.height / info.size.width; + if (this.pixelMap !== undefined) { + let info = await this.pixelMap.getImageInfo(); + let pixelMapAspectRatio = info.size.height / info.size.width; - if ((this.screenAspectRatio !== -1) && (pixelMapAspectRatio > this.screenAspectRatio)) { - let width = CommonConstants.HEIGHT_FIRST / pixelMapAspectRatio * this.screenAspectRatio; - this.dialogWidth = width + '%'; - } else { - this.dialogWidth = CommonConstants.WIDTH_FIRST; + if ((this.screenAspectRatio !== -1) && (pixelMapAspectRatio > this.screenAspectRatio)) { + let width = CommonConstants.HEIGHT_FIRST / pixelMapAspectRatio * this.screenAspectRatio; + this.dialogWidth = width + '%'; + } else { + this.dialogWidth = CommonConstants.WIDTH_FIRST; + } } } } \ No newline at end of file diff --git a/GraphicImage/GestureScreenshot/entry/src/main/module.json5 b/GraphicImage/GestureScreenshot/entry/src/main/module.json5 index 8b628a64d4e8cb136a01f1aca30add329ba038d3..fc03af4b208bb0fb57847c1f16c224b6c6d19eca 100644 --- a/GraphicImage/GestureScreenshot/entry/src/main/module.json5 +++ b/GraphicImage/GestureScreenshot/entry/src/main/module.json5 @@ -14,7 +14,7 @@ "abilities": [ { "name": "EntryAbility", - "srcEntry": "./ets/entryability/EntryAbility.ts", + "srcEntry": "./ets/entryability/EntryAbility.ets", "description": "$string:EntryAbility_desc", "icon": "$media:icon", "label": "$string:app_name", diff --git a/GraphicImage/GestureScreenshot/hvigor/hvigor-config.json5 b/GraphicImage/GestureScreenshot/hvigor/hvigor-config.json5 index e5bf1bf2b10d77ae8849c97d378d3831f13480b2..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/GraphicImage/GestureScreenshot/hvigor/hvigor-config.json5 +++ b/GraphicImage/GestureScreenshot/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.1.1", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.1.1" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/Media/AudioPlayer/README.md b/Media/AudioPlayer/README.md index 852bce80ec684252e1508c780251203148511b01..d581f1fb196e76a8b234cf951e9166bafe981945 100644 --- a/Media/AudioPlayer/README.md +++ b/Media/AudioPlayer/README.md @@ -23,13 +23,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -56,15 +56,16 @@ ``` ├──entry/src/main/ets // 代码区 -│ ├──common -│ │ ├──bean -│ │ │ └──MusicItem.ets // 音乐类 +│ ├──common │ │ ├──constants │ │ │ └──CommonConstants.ets // 公共常量 +│ │ ├──model +│ │ │ └──PlayBarModel // 播放栏数据模型 │ │ └──utils │ │ ├──AvSessionUtil.ets // 媒体会话工具类 │ │ ├──BackgroundTaskUtil.ets // 后台任务工具类 │ │ ├──CommonUtil.ets // 公共工具类 +│ │ ├──GlobalContext.ets // 公共工具类 │ │ ├──Logger.ets // 日志类 │ │ └──ResourceManagerUtil.ets // 资源管理工具类 │ ├──controller @@ -84,6 +85,7 @@ │ │ ├──PlayListMusicView.ets // 弹窗音乐模块 │ │ └──ProgressView.ets // 播放页 │ └──viewmodel +│ ├──MusicItem.ets // 音乐类 │ └──MusicViewModel.ets // 歌单音乐模型 └──entry/src/main/resources // 应用资源目录 ``` @@ -100,22 +102,16 @@ ```typescript // AudioPlayerController.ets -import media from '@ohos.multimedia.media'; -... -export class AudioPlayerController { - ... - initAudioPlayer() { - media.createAVPlayer((error, video) => { - if (CommonUtil.isEmpty(video)) { - this.avPlayer = video; - Logger.error(TAG, `createAVPlayer fail, error: ${error}`); - } else { - this.avPlayer = video; - Logger.info(TAG, 'createAVPlayer success'); - } - }); - } - ... +initAudioPlayer() { + media.createAVPlayer((error, video) => { + if (video === undefined) { + this.avPlayer = video; + Logger.error(TAG, `createAVPlayer fail, error: ${error}`); + } else { + this.avPlayer = video; + Logger.info(TAG, 'createAVPlayer success'); + } + }); } ``` @@ -124,75 +120,94 @@ export class AudioPlayerController { ```typescript // AudioPlayerController.ets // 注册AVPlayer回调函数 -setEventCallBack(context) { - if (CommonUtil.isEmpty(context)) { - Logger.info(TAG, 'setEventCallBack fail,context is empty.'); - return; - } - // 状态变更回调函数 +setEventCallBack() { + ... + // 状态变更回调函数。 this.avPlayer.on('stateChange', async (state) => { + ... switch (state) { case StateEvent.IDLE: // 调用reset成功后触发此状态。 ... - break; case StateEvent.INITIALIZED: // 设置播放源触发此状态。 ... - break; case StateEvent.PREPARED: ... - break; case StateEvent.PLAYING: ... - break; case StateEvent.COMPLETED: ... - break; default: Logger.error('unknown state: ' + state); break; } }) -} +} ``` 设置音频资源,AVPlayer进入initialized状态。在initialized状态回调中,调用prepare方法,准备播放,AVPlayer进入prepared状态。 ```typescript // AudioPlayerController.ets -// 设置播放源 -this.avPlayer.fdSrc = src; -... -// 设置播放源后进入initialized状态 -case stateEvent.INITIALIZED: - Logger.info(TAG, 'state initialized called'); - this.avPlayerState = playerState.INITIALIZED; - this.avPlayer.prepare().then(() => { - Logger.info(TAG, 'prepare success'); - }, (err) => { - Logger.error(TAG, 'prepare failed,error message is: ' + err.message); +async play(src: media.AVFileDescriptor, seekTo: number) { + Logger.info(TAG, 'audioPlayer play'); + ... + // 设置播放源 + this.avPlayer.fdSrc = src; +} + +setEventCallBack() { + ... + this.avPlayer.on('stateChange', async (state) => { + ... + switch (state) { + ... + case StateEvent.INITIALIZED:// 设置播放源后进入initialized状态 + Logger.info(TAG, 'state initialized called'); + this.avPlayerState = PlayerState.INITIALIZED; + this.avPlayer.prepare().then(() => { + Logger.info(TAG, 'prepare success'); + }, (err) => { + Logger.error(TAG, `prepare failed,error message is: ${err.message}`); + }) + break; + ... + } }) - break; +} ``` AVPlayer进入prepared状态,可进行音频播控操作。包括播放play\(\)、跳转至指定位置播放seek\(\)、暂停pause\(\)、停止stop\(\)等操作。 ```typescript // AudioPlayerController.ets -case stateEvent.PREPARED: - Logger.info(TAG, 'state prepared called'); - this.avPlayer.play(); - break; +setEventCallBack() { + ... + this.avPlayer.on('stateChange', async (state) => { + ... + switch (state) { + ... + case StateEvent.PREPARED: + Logger.info(TAG, 'state prepared called'); + this.avPlayer.play(); + break; + ... + } + }) +} ``` 切换歌曲播放时,需调用reset\(\)重置资源。此时AVPlayer重新进入idle状态,允许更换资源。 ```typescript // AudioPlayerController.ets -if (this.avPlayerState === playerState.INITIALIZED) { - await this.avPlayer.reset(); - Logger.info(TAG, 'play reset success'); +async play(src: media.AVFileDescriptor, seekTo: number) { + ... + if (this.avPlayerState === PlayerState.INITIALIZED) { + await this.avPlayer.reset(); + Logger.info(TAG, 'play reset success'); + } + ... } -this.avPlayer.fdSrc = src; ``` >![](public_sys-resources/icon-note.gif) **说明:** @@ -249,8 +264,10 @@ async release() { import wantAgent from '@ohos.app.ability.wantAgent'; import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'; ... - public static startContinuousTask(context) { - if (CommonUtil.isEmpty(context)) { +export class BackgroundTaskUtil { + ... + public static startContinuousTask(context: Context) { + if (context === undefined) { Logger.info(TAG, 'startContinuousTask fail,context is empty.'); return; } @@ -266,7 +283,7 @@ import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager' operationType: wantAgent.OperationType.START_ABILITY, // 用户定义的私有属性 requestCode: CommonConstants.BACKGROUND_REQUEST_CODE - }; + } as wantAgent.WantAgentInfo; // 通过WanAgent模块的方法获取WanAgent对象 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => { @@ -274,15 +291,16 @@ import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager' backgroundTaskManager.startBackgroundRunning(context, backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, wantAgentObj).then(() => { Logger.info(TAG, 'startBackgroundRunning succeeded'); - }).catch((err) => { - Logger.error(TAG, 'startBackgroundRunning failed Cause: ' + JSON.stringify(err)); + }).catch((err: Error) => { + Logger.error(TAG, 'startBackgroundRunning failed, Cause: ' + JSON.stringify(err)); }); } catch (error) { Logger.error(TAG, `startBackgroundRunning failed. code is ${error.code} message is ${error.message}`); } }); } -... + ... +} ``` 暂停音乐播放,结束长时任务。 @@ -292,22 +310,24 @@ import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager' import wantAgent from '@ohos.app.ability.wantAgent'; import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'; ... - public static stopContinuousTask(context) { - if (CommonUtil.isEmpty(context)) { +export class BackgroundTaskUtil { + ... + public static stopContinuousTask(context: Context) { + if (context === undefined) { Logger.info(TAG, 'stopContinuousTask fail,context is empty.'); return; } try { backgroundTaskManager.stopBackgroundRunning(context).then(() => { Logger.info(TAG, 'stopBackgroundRunning succeeded'); - }).catch((err) => { + }).catch((err: Error) => { Logger.error(TAG, 'stopBackgroundRunning failed Cause: ' + JSON.stringify(err)); }); } catch (error) { Logger.error(TAG, `stopBackgroundRunning failed. code is ${error.code} message is ${error.message}`); } } -... +} ``` ## 总结 diff --git a/Media/AudioPlayer/entry/src/main/ets/common/constants/CommonConstants.ets b/Media/AudioPlayer/entry/src/main/ets/common/constants/CommonConstants.ets index 30f59586c43820635172fbfdaa92d77d864fb151..e0b3ea4636ce3627ed1c71da1d75cba7efaa1833 100644 --- a/Media/AudioPlayer/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/Media/AudioPlayer/entry/src/main/ets/common/constants/CommonConstants.ets @@ -21,203 +21,159 @@ export class CommonConstants { * FontWeight bolder. */ static readonly FONT_WEIGHT_BOLDER: number = 500; - /** * Weight of 100%. */ static readonly FULL_WIDTH: string = '100%'; - /** * Height of 100%. */ static readonly FULL_HEIGHT: string = '100%'; - /** * Music list page. */ static readonly PAGE_MUSIC_LIST: string = 'pages/MusicList'; - /** * Play page. */ static readonly PAGE_PLAY: string = 'pages/Play'; - /** * Start up delayTime. */ static readonly DELAY_TIME: number = 1000; - /** * Start position. */ static readonly START_POSITION: number = 0; - /** * Total value. */ static readonly TOTAL_VALUE: number = 100; - /** * Divider color. */ static readonly DIVIDER_COLOR: number = 0x33000000; - /** * Start up page const. */ - static readonly START_UP_PAGE = { - IMAGE_WIDTH: '53.3%', - IMAGE_HEIGHT: '24.6%', - IMAGE_CONTAINER: '75.5%' - } - + static readonly START_IMAGE_WIDTH: string = '53.3%'; + static readonly START_IMAGE_HEIGHT: string = '24.6%'; + static readonly START_IMAGE_CONTAINER: string = '75.5%'; /** * Music list page const. */ - static readonly MUSIC_LIST_PAGE = { - TEXT_MARGIN_LEFT: '6.7%', - TEXT_MARGIN_RIGHT: '6.7%', - TEXT_MARGIN_TOP: '1.5%', - TEXT_MARGIN_BOTTOM: '1.5%', - TEXT_WIDTH: '86.7%', - TEXT_HEIGHT: '6.7%' - } - + static readonly TEXT_MARGIN_LEFT: string = '6.7%'; + static readonly TEXT_MARGIN_RIGHT: string = '6.7%'; + static readonly TEXT_MARGIN_TOP: string = '1.5%'; + static readonly TEXT_MARGIN_BOTTOM: string = '1.5%'; + static readonly TEXT_WIDTH: string = '86.7%'; + static readonly TEXT_HEIGHT: string = '6.7%'; /** * Play page const. */ - static readonly PLAY_PAGE = { - NAVIGATOR_WIDTH: '6.7%', - NAVIGATOR_HEIGHT: '3.1%', - LAYOUT_WEIGHT: 1, - NAVIGATOR_PADDING_LEFT: '6.7%', - NAVIGATOR_PADDING_RIGHT: '6.7%', - NAVIGATOR_PADDING_TOP: '1.9%', - NAVIGATOR_PADDING_BOTTOM: '1.9%', - CONTROL_WIDTH: '81.2%' - } - + static readonly NAVIGATOR_WIDTH: string = '6.7%'; + static readonly NAVIGATOR_HEIGHT: string = '3.1%'; + static readonly LAYOUT_WEIGHT: number = 1; + static readonly NAVIGATOR_PADDING_LEFT: string = '6.7%'; + static readonly NAVIGATOR_PADDING_RIGHT: string = '6.7%'; + static readonly NAVIGATOR_PADDING_TOP: string = '1.9%'; + static readonly NAVIGATOR_PADDING_BOTTOM: string = '1.9%'; + static readonly CONTROL_WIDTH: string = '81.2%'; /** * Control view const. */ - static readonly CONTROL_VIEW = { - MODE_ICON_WIDTH: '7.5%', - MODE_ICON_HEIGHT: '3.1%', - MODE_ICON_MARGIN_RIGHT: '12%', - PREVIOUS_WIDTH: '8.3%', - PREVIOUS_HEIGHT: '3.8%', - PREVIOUS_MARGIN_RIGHT: '9%', - STATE_ICON_WIDTH: '18.9%', - STATE_ICON_HEIGHT: '8.7%', - STATE_ICON_MARGIN_RIGHT: '9%', - NEXT_WIDTH: '8.3%', - NEXT_HEIGHT: '3.8%', - NEXT_MARGIN_RIGHT: '12%', - PLAY_LIST_WIDTH: '7.5%', - PLAY_LIST_HEIGHT: '3.1%', - PAGE_MARGIN_TOP: '4.6%' - } - + static readonly MODE_ICON_WIDTH: string = '7.5%'; + static readonly MODE_ICON_HEIGHT: string = '3.1%'; + static readonly MODE_ICON_MARGIN_RIGHT: string = '12%'; + static readonly PREVIOUS_WIDTH: string = '8.3%'; + static readonly PREVIOUS_HEIGHT: string = '3.8%'; + static readonly PREVIOUS_MARGIN_RIGHT: string = '9%'; + static readonly STATE_ICON_WIDTH: string = '18.9%'; + static readonly STATE_ICON_HEIGHT: string = '8.7%'; + static readonly STATE_ICON_MARGIN_RIGHT: string = '9%'; + static readonly NEXT_WIDTH: string = '8.3%'; + static readonly NEXT_HEIGHT: string = '3.8%'; + static readonly NEXT_MARGIN_RIGHT: string = '12%'; + static readonly PLAY_LIST_WIDTH: string = '7.5%'; + static readonly PLAY_LIST_HEIGHT: string = '3.1%'; + static readonly PAGE_MARGIN_TOP: string = '4.6%'; /** * Music card view const. */ - static readonly MUSIC_CARD_VIEW = { - IMAGE_HEIGHT: '41.7%', - NAME_MARGIN_TOP: '3.1%', - SINGER_MARGIN_TOP: '1.5%', - LYRICS_MARGIN_TOP: '1%' - } - + static readonly IMAGE_HEIGHT: string = '41.7%'; + static readonly NAME_MARGIN_TOP: string = '3.1%'; + static readonly SINGER_MARGIN_TOP: string = '1.5%'; + static readonly LYRICS_MARGIN_TOP: string = '1%'; /** * Music view const. */ - static readonly MUSIC_VIEW = { - IMAGE_WIDTH: '17.8%', - IMAGE_HEIGHT: '8.2%', - ROW_MARGIN_LEFT: '4.4%', - PAGE_MARGIN_LEFT: '3%', - PAGE_MARGIN_TOP: '1.5%', - PAGE_MARGIN_RIGHT: '3%', - PAGE_MARGIN_BUTTON: '1.5%' - } - + static readonly IMAGE_WIDTH: string = '17.8%'; + static readonly MUSIC_IMAGE_HEIGHT: string = '8.2%'; + static readonly ROW_MARGIN_LEFT: string = '4.4%'; + static readonly PAGE_MARGIN_LEFT: string = '3%'; + static readonly MUSIC_MARGIN_TOP: string = '1.5%'; + static readonly PAGE_MARGIN_RIGHT: string = '3%'; + static readonly PAGE_MARGIN_BUTTON: string = '1.5%'; /** * List dialog const. */ - static readonly LIST_DIALOG = { - IMAGE_WIDTH: '6.7%', - IMAGE_HEIGHT: '3.1%', - IMAGE_MARGIN_RIGHT: '3.3%', - ROW_WIDTH: '90%', - ROW_MARGIN_TOP: '3%', - ROW_MARGIN_BOTTOM: '3%', - LIST_WIDTH: '90%', - LIST_HEIGHT: '57.4%', - PAGE_MARGIN_LEFT: '3.3%', - LIST_SPACE: 10, - LIST_INITIAL_INDEX: 0, - DIVIDER_STROKE_WIDTH: 1, - DIVIDER_START_MARGIN: 0, - END_MARGIN: 20 - } - + static readonly DIALOG_IMAGE_WIDTH: string = '6.7%'; + static readonly DIALOG_IMAGE_HEIGHT: string = '3.1%'; + static readonly IMAGE_MARGIN_RIGHT: string = '3.3%'; + static readonly ROW_WIDTH: string = '90%'; + static readonly ROW_MARGIN_TOP: string = '3%'; + static readonly ROW_MARGIN_BOTTOM: string = '3%'; + static readonly LIST_WIDTH: string = '90%'; + static readonly LIST_HEIGHT: string = '57.4%'; + static readonly DIALOG_MARGIN_LEFT: string = '3.3%'; + static readonly LIST_SPACE: number = 10; + static readonly LIST_INITIAL_INDEX: number = 0; + static readonly DIVIDER_STROKE_WIDTH: number = 1; + static readonly DIVIDER_START_MARGIN: number = 0; + static readonly END_MARGIN: number = 20; /** * List dialog music. */ - static readonly LIST_DIALOG_MUSIC = { - IMAGE_WIDTH: '4.4%', - IMAGE_HEIGHT: '2.1%', - IMAGE_MARGIN_RIGHT: '2.1%', - LINE_HEIGHT: 21, - MUSIC_MARGIN_TOP: '1.7%', - MUSIC_MARGIN_BOTTOM: '1.7%' - } - + static readonly LIST_IMAGE_WIDTH: string = '4.4%'; + static readonly LIST_IMAGE_HEIGHT: string = '2.1%'; + static readonly LIST_MARGIN_RIGHT: string = '2.1%'; + static readonly LINE_HEIGHT: number = 21; + static readonly LIST_MARGIN_TOP: string = '1.7%'; + static readonly MUSIC_MARGIN_BOTTOM: string = '1.7%'; /** * Progress view const. */ - static readonly PROGRESS_VIEW = { - TEXT_MARGIN_RIGHT: '3.3%', - TEXT_MARGIN_LEFT: '3.3%', - VIEW_MARGIN_TOP: '8.2%', - PROGRESS_MIN: 0 - } - + static readonly PROGRESS_MARGIN_RIGHT: string = '3.3%'; + static readonly PROGRESS_MARGIN_LEFT: string = '3.3%'; + static readonly VIEW_MARGIN_TOP: string = '8.2%'; + static readonly PROGRESS_MIN: number = 0; /** * BackgroundTask parameter. */ static readonly BACKGROUND_REQUEST_CODE: number = 0; - /** * Const of commonUtil. */ - static readonly COMMON_UTIL = { - SECOND_PRECISION: 0, - SECOND_TO_MS: 1000, - MIN_TO_SEC: 60, - MAX_OF_INDIVIDUAL: 9 - } - + static readonly SECOND_PRECISION: number = 0; + static readonly SECOND_TO_MS: number = 1000; + static readonly MIN_TO_SEC: number = 60; + static readonly MAX_OF_INDIVIDUAL: number = 9; /** * Default id. */ static readonly DEFAULT_TIME_ID: number = -1; - /** * Number of modes. */ static readonly MODE_QUANTITY: number = 3; - /** * Number of musics. */ static readonly MUSICS_QUANTITY: number = 6; - /** * Bundle name. */ static readonly BUNDLE_NAME: string = 'com.example.audioplayer'; - /** * Ability name. */ diff --git a/Media/AudioPlayer/entry/src/main/ets/common/model/PlayBarModel.ets b/Media/AudioPlayer/entry/src/main/ets/common/model/PlayBarModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..d0709a9d446de5aaafc57df4f2931f27f5252b82 --- /dev/null +++ b/Media/AudioPlayer/entry/src/main/ets/common/model/PlayBarModel.ets @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MusicItem } from '../../viewmodel/MusicItem'; +import { CommonConstants, PlayMode, PlayState } from '../constants/CommonConstants'; + +@Observed +export class PlayBarModel { + playValue: number = CommonConstants.START_POSITION; + playMode: number = PlayMode.LIST_LOOP; + playStateIcon: Resource = $r('app.media.ic_play'); + playModeIcon: Resource = $r('app.media.ic_list_mode'); + totalValue: number = CommonConstants.TOTAL_VALUE; + musicItem?: MusicItem; + playState: number = PlayState.PLAY; +} \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/common/utils/AvSessionUtil.ets b/Media/AudioPlayer/entry/src/main/ets/common/utils/AvSessionUtil.ets index ad51cfe911f37aa583c9c233fcd0a535a4d77864..2c40fe32194fb1969432564108630760db46473c 100644 --- a/Media/AudioPlayer/entry/src/main/ets/common/utils/AvSessionUtil.ets +++ b/Media/AudioPlayer/entry/src/main/ets/common/utils/AvSessionUtil.ets @@ -14,8 +14,10 @@ */ import avSession from '@ohos.multimedia.avsession'; +import { AudioPlayerController } from '../../controller/AudioPlayerControllerl'; +import { PlayBarModel } from '../model/PlayBarModel'; import Logger from '../utils/Logger'; -import { CommonUtil } from './CommonUtil'; +import { GlobalContext } from './GlobalContext'; const TAG = '[AvSessionUtil]'; @@ -23,43 +25,41 @@ const TAG = '[AvSessionUtil]'; * Media session tool class. */ export class AvSessionUtil { - /** * Initializing the playback control center. * * @param context Context. */ - public static initAvSession(context) { - if (CommonUtil.isEmpty(context)) { - Logger.error(TAG, 'initAvSession fail,context is empty.'); - return; - } - return new Promise(async () => { + public static initAvSession(playBarModel: PlayBarModel) { + return new Promise(async () => { try { // Sets the current music metadata. let metadata = { - assetId: context.musicItem.id.toString(), - title: context.musicItem.name, - artist: context.musicItem.singer - }; - await globalThis.currentSession.setAVMetadata(metadata); + assetId: playBarModel!.musicItem!.id.toString(), + title: playBarModel!.musicItem!.name, + artist: playBarModel!.musicItem!.singer + } as avSession.AVMetadata; + let currentSession = GlobalContext.getContext().getObject('currentSession') as avSession.AVSession; + await currentSession.setAVMetadata(metadata); // Set the playback status and give an initial status. AvSessionUtil.setAVPlayState(avSession.PlaybackState.PLAYBACK_STATE_PLAY); // The following are all callback listeners. Currently, only the playback and pause functions are implemented. - globalThis.currentSession.on('play', () => { + currentSession.on('play', () => { Logger.info(TAG, 'Invoke the playback method of avSession.'); - globalThis.AudioPlayerController.play(context.musicItem.rawFileDescriptor, context.playValue); - context.playStateIcon = $r('app.media.ic_play'); + let playController = GlobalContext.getContext().getObject('audioPlayerController') as AudioPlayerController; + playController.play(playBarModel!.musicItem!.rawFileDescriptor, playBarModel.playValue); + playBarModel.playStateIcon = $r('app.media.ic_play'); AvSessionUtil.setAVPlayState(avSession.PlaybackState.PLAYBACK_STATE_PLAY); }); // Registering and suspending command listening. - globalThis.currentSession.on('pause', () => { + currentSession.on('pause', () => { Logger.info(TAG, 'Invoke the pause method of avSession.'); - globalThis.AudioPlayerController.pause(); - context.playStateIcon = $r('app.media.ic_pause'); + let playController = GlobalContext.getContext().getObject('audioPlayerController') as AudioPlayerController; + playController.pause(); + playBarModel.playStateIcon = $r('app.media.ic_pause'); AvSessionUtil.setAVPlayState(avSession.PlaybackState.PLAYBACK_STATE_PAUSE); }); } @@ -74,17 +74,18 @@ export class AvSessionUtil { * * @param state Status of the Playback Control Center. */ - public static setAVPlayState(state:avSession.PlaybackState) { - if (CommonUtil.isEmpty(state)) { + public static setAVPlayState(state: avSession.PlaybackState) { + if (state === undefined) { Logger.info(TAG, 'setAVPlayState fail,state is empty.'); return; } - globalThis.currentSession.setAVPlaybackState({ state: state }) + let currentSession = GlobalContext.getContext().getObject('currentSession') as avSession.AVSession; + currentSession.setAVPlaybackState({ state: state }) .then(() => { Logger.info(TAG, 'setAVPlaybackState successfully'); }) - .catch((err) => { - Logger.info(TAG, `setAVPlaybackState : ERROR : ${err.message}`); + .catch((err: Error) => { + Logger.info(TAG, `setAVPlaybackState : ERROR : ${err}`); }); } @@ -93,16 +94,13 @@ export class AvSessionUtil { * * @param context Context. */ - public static setAVMetadata(context) { - if (CommonUtil.isEmpty(context)) { - Logger.error(TAG, 'setAVMetadata fail,context is empty.'); - return; - } + public static setAVMetadata(playBarModel: PlayBarModel) { let metadata = { - assetId: context.musicItem.id.toString(), - title: context.musicItem.name, - artist: context.musicItem.singer - }; - globalThis.currentSession.setAVMetadata(metadata); + assetId: playBarModel!.musicItem!.id.toString(), + title: playBarModel!.musicItem!.name, + artist: playBarModel!.musicItem!.singer + } as avSession.AVMetadata; + let currentSession = GlobalContext.getContext().getObject('currentSession') as avSession.AVSession; + currentSession.setAVMetadata(metadata); } } \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/common/utils/BackgroundTaskUtil.ets b/Media/AudioPlayer/entry/src/main/ets/common/utils/BackgroundTaskUtil.ets index 1799bbb0f946aea57e0e391b4f91fb4776b80c3f..4f66d5ea066e7f6ab8003158c3dac51f4bbdc008 100644 --- a/Media/AudioPlayer/entry/src/main/ets/common/utils/BackgroundTaskUtil.ets +++ b/Media/AudioPlayer/entry/src/main/ets/common/utils/BackgroundTaskUtil.ets @@ -17,7 +17,6 @@ import wantAgent from '@ohos.app.ability.wantAgent'; import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'; import { CommonConstants } from '../constants/CommonConstants'; import Logger from '../utils/Logger'; -import { CommonUtil } from './CommonUtil'; const TAG = '[BackgroundTaskUtil]'; @@ -25,14 +24,13 @@ const TAG = '[BackgroundTaskUtil]'; * Background task tool class. */ export class BackgroundTaskUtil { - /** * Start a long-time task in the background. * * @param context Context. */ - public static startContinuousTask(context) { - if (CommonUtil.isEmpty(context)) { + public static startContinuousTask(context: Context) { + if (context === undefined) { Logger.info(TAG, 'startContinuousTask fail,context is empty.'); return; } @@ -48,7 +46,7 @@ export class BackgroundTaskUtil { operationType: wantAgent.OperationType.START_ABILITY, // A private value defined by the user. requestCode: CommonConstants.BACKGROUND_REQUEST_CODE - }; + } as wantAgent.WantAgentInfo; // Obtain the WantAgent object by using the method of the wantAgent module. wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => { @@ -56,8 +54,8 @@ export class BackgroundTaskUtil { backgroundTaskManager.startBackgroundRunning(context, backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, wantAgentObj).then(() => { Logger.info(TAG, 'startBackgroundRunning succeeded'); - }).catch((err) => { - Logger.error(TAG, 'startBackgroundRunning failed Cause: ' + JSON.stringify(err)); + }).catch((err: Error) => { + Logger.error(TAG, 'startBackgroundRunning failed, Cause: ' + JSON.stringify(err)); }); } catch (error) { Logger.error(TAG, `startBackgroundRunning failed. code is ${error.code} message is ${error.message}`); @@ -70,15 +68,15 @@ export class BackgroundTaskUtil { * * @param context context. */ - public static stopContinuousTask(context) { - if (CommonUtil.isEmpty(context)) { + public static stopContinuousTask(context: Context) { + if (context === undefined) { Logger.info(TAG, 'stopContinuousTask fail,context is empty.'); return; } try { backgroundTaskManager.stopBackgroundRunning(context).then(() => { Logger.info(TAG, 'stopBackgroundRunning succeeded'); - }).catch((err) => { + }).catch((err: Error) => { Logger.error(TAG, 'stopBackgroundRunning failed Cause: ' + JSON.stringify(err)); }); } catch (error) { diff --git a/Media/AudioPlayer/entry/src/main/ets/common/utils/CommonUtil.ets b/Media/AudioPlayer/entry/src/main/ets/common/utils/CommonUtil.ets index dc8a0f9fc9f0e3a5483f611827da909f83649d44..bda99fd73e4671f6d784189a8231255beb07f12f 100644 --- a/Media/AudioPlayer/entry/src/main/ets/common/utils/CommonUtil.ets +++ b/Media/AudioPlayer/entry/src/main/ets/common/utils/CommonUtil.ets @@ -29,12 +29,12 @@ export class CommonUtil { if (ms < 0) { ms = 0; } - const secondPrecision = CommonConstants.COMMON_UTIL.SECOND_PRECISION; - const secondDuration = ms / CommonConstants.COMMON_UTIL.SECOND_TO_MS; - let min = Math.floor(secondDuration / CommonConstants.COMMON_UTIL.MIN_TO_SEC); - let sec = Math.round(secondDuration - min * CommonConstants.COMMON_UTIL.MIN_TO_SEC); + const secondPrecision = CommonConstants.SECOND_PRECISION; + const secondDuration = ms / CommonConstants.SECOND_TO_MS; + let min = Math.floor(secondDuration / CommonConstants.MIN_TO_SEC); + let sec = Math.round(secondDuration - min * CommonConstants.MIN_TO_SEC); let secStr = sec.toFixed(secondPrecision); - if (parseInt(secStr) <= CommonConstants.COMMON_UTIL.MAX_OF_INDIVIDUAL) { + if (Number.parseInt(secStr) <= CommonConstants.MAX_OF_INDIVIDUAL) { secStr = `0${secStr}`; } return `${min}:${secStr}`; @@ -48,23 +48,15 @@ export class CommonUtil { */ public static getRandomNumber(n: number) { // Generates an array from 0 to n-1. - let arr: number[] = Array.from(Array(n), (v, k) => k); + let arr: number[] = Array.from(Array(n), (v: number, k: number) => k); // Randomly disrupted. for (let i = 0; i < n; i++) { let j = Math.floor(Math.random() * (arr.length - i) + i); - [arr[i], arr[j]] = [arr[j], arr[i]]; + let tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; } arr.length = n; return arr; } - - /** - * Check obj is empty or not. - * - * @param obj Object. - * @returns - */ - public static isEmpty(obj) { - return typeof obj === 'undefined' || obj == null || obj === ''; - } } \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/common/utils/GlobalContext.ets b/Media/AudioPlayer/entry/src/main/ets/common/utils/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..23f5130a61c9e0ac09c5d885cdcaa2c878e0d522 --- /dev/null +++ b/Media/AudioPlayer/entry/src/main/ets/common/utils/GlobalContext.ets @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { + } + + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/common/utils/Logger.ets b/Media/AudioPlayer/entry/src/main/ets/common/utils/Logger.ets index a54d8c0b0d01f05febc716b8672136e41d512e75..196544ecc2e7e792b9313adec740941a233ae547 100644 --- a/Media/AudioPlayer/entry/src/main/ets/common/utils/Logger.ets +++ b/Media/AudioPlayer/entry/src/main/ets/common/utils/Logger.ets @@ -33,19 +33,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Media/AudioPlayer/entry/src/main/ets/common/utils/ResourceManagerUtil.ets b/Media/AudioPlayer/entry/src/main/ets/common/utils/ResourceManagerUtil.ets index ea05eb56404dd5e77d6a595802eef08850c65cb7..ad98dc64c41d3853d88d66fde8b56688cd3cdf96 100644 --- a/Media/AudioPlayer/entry/src/main/ets/common/utils/ResourceManagerUtil.ets +++ b/Media/AudioPlayer/entry/src/main/ets/common/utils/ResourceManagerUtil.ets @@ -12,9 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import resourceManager from '@ohos.resourceManager'; import Logger from '../utils/Logger'; -import { CommonUtil } from './CommonUtil'; +import { GlobalContext } from './GlobalContext'; const TAG = '[ResourceManagerUtil]'; @@ -22,7 +23,6 @@ const TAG = '[ResourceManagerUtil]'; * Resource management tool class. */ export class ResourceManagerUtil { - /** * Obtains the description of a media file. * @@ -30,12 +30,14 @@ export class ResourceManagerUtil { * @param callback Callback function. */ public static getSrcPath(path: string, callback: Function) { - if (CommonUtil.isEmpty(callback)) { + if (callback === undefined) { Logger.error(TAG, 'getSrcPath fail,callback is empty.'); return; } try { - globalThis.resourceManager.getRawFd(path, (error, value) => { + let resourceManager = GlobalContext.getContext() + .getObject('resourceManager') as resourceManager.ResourceManager; + resourceManager.getRawFd(path, (error, value) => { if (error != null) { Logger.error(TAG, `callback getRawFd failed error code: ${error.code}, message: ${error.message}.`); } else { diff --git a/Media/AudioPlayer/entry/src/main/ets/controller/AudioPlayerControllerl.ets b/Media/AudioPlayer/entry/src/main/ets/controller/AudioPlayerControllerl.ets index 339db673a8892cdc00929074af4f2a76a9c3e653..bbac218366f4d137fa17fdcf8c829022922c649f 100644 --- a/Media/AudioPlayer/entry/src/main/ets/controller/AudioPlayerControllerl.ets +++ b/Media/AudioPlayer/entry/src/main/ets/controller/AudioPlayerControllerl.ets @@ -14,23 +14,26 @@ */ import media from '@ohos.multimedia.media'; -import { MusicItem } from '../common/bean/MusicItem'; +import { MusicItem } from '../viewmodel/MusicItem'; import { PlayMode, PlayerState, StateEvent, CommonConstants } from '../common/constants/CommonConstants'; import { BackgroundTaskUtil } from '../common/utils/BackgroundTaskUtil'; import { AvSessionUtil } from '../common/utils/AvSessionUtil'; import Logger from '../common/utils/Logger'; -import { CommonUtil } from '../common/utils/CommonUtil'; +import { GlobalContext } from '../common/utils/GlobalContext'; +import { PlayBarModel } from '../common/model/PlayBarModel'; const TAG = '[AudioPlayerController]'; export class AudioPlayerController { - avPlayer: media.AVPlayer; + public playBarModel: PlayBarModel; + avPlayer?: media.AVPlayer; musicList: Array = []; currentTimeMs: number = 0; // Current playback position. timeId = CommonConstants.DEFAULT_TIME_ID; avPlayerState = PlayerState.IDLE; - constructor() { + constructor(playBarModel: PlayBarModel) { + this.playBarModel = playBarModel; this.initAudioPlayer(); } @@ -43,7 +46,7 @@ export class AudioPlayerController { */ initAudioPlayer() { media.createAVPlayer((error, video) => { - if (CommonUtil.isEmpty(video)) { + if (video === undefined) { this.avPlayer = video; Logger.error(TAG, `createAVPlayer fail, error: ${error}`); } else { @@ -58,13 +61,15 @@ export class AudioPlayerController { * * @param context Context. */ - setEventCallBack(context) { - if (CommonUtil.isEmpty(context)) { - Logger.info(TAG, 'setEventCallBack fail,context is empty.'); + setEventCallBack() { + if (this.avPlayer === undefined) { return; } // Callback function for state machine changes. this.avPlayer.on('stateChange', async (state) => { + if (this.avPlayer === undefined) { + return; + } switch (state) { case StateEvent.IDLE: // This state machine is triggered after the reset interface is successfully invoked. Logger.info(TAG, 'state idle called'); @@ -87,12 +92,12 @@ export class AudioPlayerController { if (this.currentTimeMs > 0) { this.avPlayer.seek(this.currentTimeMs); } - this.progressChange(context); + this.progressChange(); break; case StateEvent.COMPLETED: Logger.info(TAG, 'state completed called'); BackgroundTaskUtil.stopContinuousTask(getContext(this)) - this.loopPlay(context); + this.loopPlay(); break; default: Logger.error('unknown state: ' + state); @@ -107,7 +112,7 @@ export class AudioPlayerController { * @param src Resource path. * @param seekTo Playing position. */ - async play(src, seekTo) { + async play(src: media.AVFileDescriptor, seekTo: number) { Logger.info(TAG, 'audioPlayer play'); if (this.timeId === CommonConstants.DEFAULT_TIME_ID) { clearInterval(this.timeId); @@ -115,6 +120,9 @@ export class AudioPlayerController { // Enable a long-term task to allow long-term playback in the background. BackgroundTaskUtil.startContinuousTask(getContext(this)); this.currentTimeMs = Math.max(0, seekTo); + if (this.avPlayer === undefined) { + return; + } if (this.avPlayerState === PlayerState.INITIALIZED) { await this.avPlayer.reset(); Logger.info(TAG, 'play reset success'); @@ -127,6 +135,9 @@ export class AudioPlayerController { if (this.timeId === CommonConstants.DEFAULT_TIME_ID) { clearInterval(this.timeId); } + if (this.avPlayer === undefined) { + return; + } BackgroundTaskUtil.stopContinuousTask(getContext(this)); await this.avPlayer.pause(); } @@ -142,54 +153,57 @@ export class AudioPlayerController { } } - progressChange(context) { - context.playValue = this.currentTimeMs; - context.totalValue = this.avPlayer.duration; + progressChange() { + this.playBarModel.playValue = this.currentTimeMs; + if (this.avPlayer === undefined) { + return; + } + this.playBarModel.totalValue = this.avPlayer.duration; this.timeId = setInterval(() => { - context.playValue = this.avPlayer.currentTime; + if (this.avPlayer === undefined) { + return; + } + this.playBarModel.playValue = this.avPlayer.currentTime; }, CommonConstants.DELAY_TIME) } - loopPlay(context) { - if (CommonUtil.isEmpty(context)) { - Logger.info(TAG, 'setEventCallBack fail,context is empty.'); - return; - } + loopPlay() { this.currentTimeMs = 0; // Play the next song in loop mode. - switch (context.playMode) { + switch (this.playBarModel.playMode) { case PlayMode.SINGLE_LOOP: - this.play(context.musicItem.rawFileDescriptor, 0); + this.play(this.playBarModel!.musicItem!.rawFileDescriptor, 0); break; case PlayMode.LIST_LOOP: let nextIndex = this.musicList.length - 1; this.musicList.forEach((item, index) => { - if (item.id === context.musicItem.id) { + if (item.id === this.playBarModel!.musicItem!.id) { nextIndex = index + 1 > this.musicList.length - 1 ? 0 : index + 1; return; } }) - context.musicItem = this.musicList[nextIndex]; - this.play(context.musicItem.rawFileDescriptor, 0); - // Sets the current music metadata. - AvSessionUtil.setAVMetadata(context); + this.playBarModel.musicItem = this.musicList[nextIndex]; + this.play(this.playBarModel.musicItem.rawFileDescriptor, 0); + // Sets the current music metadata. + AvSessionUtil.setAVMetadata(this.playBarModel); break; case PlayMode.RANDOM_PLAY: - // Obtain the previous song in the random list. - let nextIndexRandom = globalThis.randomList.length - 1; - globalThis.randomList.forEach((item, index) => { - if (item === context.musicItem.id) { - nextIndexRandom = index + 1 > globalThis.randomList.length - 1 ? 0 : index + 1; + // Obtain the previous song in the random list. + let randomList = GlobalContext.getContext().getObject('randomList') as number[]; + let nextIndexRandom = randomList.length - 1; + randomList.forEach((item, index) => { + if (item === this.playBarModel!.musicItem!.id) { + nextIndexRandom = index + 1 > randomList.length - 1 ? 0 : index + 1; return; } }) - context.musicItem = this.musicList[globalThis.randomList[nextIndexRandom]]; - this.play(context.musicItem.rawFileDescriptor, 0); - // Sets the current music metadata. - AvSessionUtil.setAVMetadata(context); + this.playBarModel.musicItem = this.musicList[randomList[nextIndexRandom]]; + this.play(this.playBarModel.musicItem.rawFileDescriptor, 0); + // Sets the current music metadata. + AvSessionUtil.setAVMetadata(this.playBarModel); break; default: - Logger.error('unknown mode: ' + context.playMode); + Logger.error('unknown mode: ' + this.playBarModel.playMode); break; } } diff --git a/Media/AudioPlayer/entry/src/main/ets/controller/PlayBarController.ets b/Media/AudioPlayer/entry/src/main/ets/controller/PlayBarController.ets index f6521ad9170092445ef4fbb23ba17f88a2b86e3e..c9a00065482f3a10e49c06b3c5d578f1d8d53680 100644 --- a/Media/AudioPlayer/entry/src/main/ets/controller/PlayBarController.ets +++ b/Media/AudioPlayer/entry/src/main/ets/controller/PlayBarController.ets @@ -18,53 +18,55 @@ import { CommonUtil } from '../common/utils/CommonUtil'; import { AvSessionUtil } from '../common/utils/AvSessionUtil'; import { PlayState, PlayMode, CommonConstants } from '../common/constants/CommonConstants'; import Logger from '../common/utils/Logger'; +import { GlobalContext } from '../common/utils/GlobalContext'; +import { AudioPlayerController } from './AudioPlayerControllerl'; +import { MusicItem } from '../viewmodel/MusicItem'; +import { PlayBarModel } from '../common/model/PlayBarModel'; const TAG = '[PlayBarController]'; export class PlayBarController { + public playBarModel: PlayBarModel; + + constructor(playBarModel: PlayBarModel) { + this.playBarModel = playBarModel; + } + /** * Toggle playback mode. - * - * @param context Context. */ - switchPlayMode(context) { - if (CommonUtil.isEmpty(context)) { - Logger.info(TAG, 'switchPlayMode fail,context is empty.'); - return; - } - context.playMode = (context.playMode + 1) % CommonConstants.MODE_QUANTITY; - if (context.playMode === PlayMode.LIST_LOOP) { - context.playModeIcon = $r('app.media.ic_list_mode'); - } else if (context.playMode === PlayMode.SINGLE_LOOP) { - context.playModeIcon = $r('app.media.ic_single_mode'); + switchPlayMode() { + this.playBarModel.playMode = (this.playBarModel.playMode + 1) % CommonConstants.MODE_QUANTITY; + if (this.playBarModel.playMode === PlayMode.LIST_LOOP) { + this.playBarModel.playModeIcon = $r('app.media.ic_list_mode'); + } else if (this.playBarModel.playMode === PlayMode.SINGLE_LOOP) { + this.playBarModel.playModeIcon = $r('app.media.ic_single_mode'); } else { - context.playModeIcon = $r('app.media.ic_random_mode'); + this.playBarModel.playModeIcon = $r('app.media.ic_random_mode'); // Random mode, generating random play list. - globalThis.randomMusicList = []; - globalThis.randomList = CommonUtil.getRandomNumber(CommonConstants.MUSICS_QUANTITY); + let randomList = CommonUtil.getRandomNumber(CommonConstants.MUSICS_QUANTITY); + GlobalContext.getContext().setObject('randomList', randomList); } } /** * Switching the Playback Status. * - * @param context Context. + * @param playState */ - switchPlayState(context) { - if (CommonUtil.isEmpty(context)) { - Logger.info(TAG, 'switchPlayState fail,context is empty.'); - return; - } - if (context.playState === PlayState.PLAY) { - context.playState = PlayState.PAUSE; - context.playStateIcon = $r('app.media.ic_pause'); - globalThis.AudioPlayerController.pause(); + switchPlayState(playState: number) { + let playController = GlobalContext.getContext().getObject('audioPlayerController') as AudioPlayerController; + if (playState === PlayState.PLAY) { + this.playBarModel.playState = PlayState.PAUSE; + this.playBarModel.playStateIcon = $r('app.media.ic_pause'); + playController.pause(); AvSessionUtil.setAVPlayState(avSession.PlaybackState.PLAYBACK_STATE_PAUSE); } else { - context.playState = PlayState.PLAY; - context.playStateIcon = $r('app.media.ic_play'); - Logger.info(TAG, `rawFileDescriptor: ${context.musicItem.rawFileDescriptor} playValue ${context.playValue}`); - globalThis.AudioPlayerController.play(context.musicItem.rawFileDescriptor, context.playValue); + this.playBarModel.playState = PlayState.PLAY; + this.playBarModel.playStateIcon = $r('app.media.ic_play'); + Logger.info(TAG, `rawFileDescriptor: ${this.playBarModel!.musicItem!.rawFileDescriptor}, + playValue ${this.playBarModel!.playValue}`); + playController.play(this.playBarModel.musicItem!.rawFileDescriptor, this.playBarModel.playValue); AvSessionUtil.setAVPlayState(avSession.PlaybackState.PLAYBACK_STATE_PLAY); } } @@ -72,78 +74,76 @@ export class PlayBarController { /** * Previous song. * - * @param context Context. + * @param musicList + * @param playState */ - getPreviousMusic(context) { - if (CommonUtil.isEmpty(context)) { - Logger.info(TAG, 'getPreviousMusic fail,context is empty.'); - return; - } - if (context.playMode === PlayMode.RANDOM_PLAY) { + getPreviousMusic(musicList: Array, playState: number) { + if (this.playBarModel.playMode === PlayMode.RANDOM_PLAY) { // Obtain the previous song in the random list. let preIndex = 0; - globalThis.randomList.forEach((item, index) => { - if (item === context.musicItem.id) { - preIndex = index - 1 < 0 ? globalThis.randomList.length - 1 : index - 1; + let randomList = GlobalContext.getContext().getObject('randomList') as number[]; + randomList.forEach((item: number, index: number) => { + if (item === this.playBarModel!.musicItem!.id) { + preIndex = index - 1 < 0 ? randomList.length - 1 : index - 1; return; } }) - context.musicItem = context.musicList[globalThis.randomList[preIndex]]; + this.playBarModel.musicItem = musicList[randomList[preIndex]]; } else { let preIndex = 0; - context.musicList.forEach((item, index) => { - if (item.id === context.musicItem.id) { - preIndex = index - 1 < 0 ? context.musicList.length - 1 : index - 1; + musicList.forEach((item: MusicItem, index: number) => { + if (item.id === this.playBarModel.musicItem!.id) { + preIndex = index - 1 < 0 ? musicList.length - 1 : index - 1; return; } }) - context.musicItem = context.musicList[preIndex]; + this.playBarModel.musicItem = musicList[preIndex]; } - Logger.info(TAG, 'state pre called' + context.playValue); - globalThis.AudioPlayerController.play(context.musicItem.rawFileDescriptor, 0); - context.playState = PlayState.PLAY; - context.playStateIcon = $r('app.media.ic_play'); + Logger.info(TAG, 'state pre called' + this.playBarModel.playValue); + let playController = GlobalContext.getContext().getObject('audioPlayerController') as AudioPlayerController; + playController.play(this.playBarModel.musicItem.rawFileDescriptor, 0); + this.playBarModel.playState = PlayState.PLAY; + this.playBarModel.playStateIcon = $r('app.media.ic_play'); // Sets the current music metadata. - AvSessionUtil.setAVMetadata(context); + AvSessionUtil.setAVMetadata(this.playBarModel); AvSessionUtil.setAVPlayState(avSession.PlaybackState.PLAYBACK_STATE_PLAY); } /** * Get next song. * - * @param context Context. + * @param musicList + * @param playState */ - getNextMusic(context) { - if (CommonUtil.isEmpty(context)) { - Logger.info(TAG, 'getNextMusic fail,context is empty.'); - return; - } + getNextMusic(musicList: Array) { // Random mode, which is used to obtain the next song randomly. - if (context.playMode === PlayMode.RANDOM_PLAY) { + if (this.playBarModel.playMode === PlayMode.RANDOM_PLAY) { // Obtain the previous song in the random list. - let nextIndex = globalThis.randomList.length - 1; - globalThis.randomList.forEach((item, index) => { - if (item === context.musicItem.id) { - nextIndex = index + 1 > globalThis.randomList.length - 1 ? 0 : index + 1; + let randomList = GlobalContext.getContext().getObject('randomList') as number[]; + let nextIndex = randomList.length - 1; + randomList.forEach((item: number, index: number) => { + if (item === this.playBarModel!.musicItem!.id) { + nextIndex = index + 1 > randomList.length - 1 ? 0 : index + 1; return; } }) - context.musicItem = context.musicList[globalThis.randomList[nextIndex]] + this.playBarModel.musicItem = musicList[randomList[nextIndex]] } else { - let nextIndex = context.musicList.length - 1; - context.musicList.forEach((item, index) => { - if (item.id === context.musicItem.id) { - nextIndex = index + 1 > context.musicList.length - 1 ? 0 : index + 1; + let nextIndex = musicList.length - 1; + musicList.forEach((item: MusicItem, index: number) => { + if (item.id === this.playBarModel!.musicItem!.id) { + nextIndex = index + 1 > musicList.length - 1 ? 0 : index + 1; return; } }) - context.musicItem = context.musicList[nextIndex]; + this.playBarModel.musicItem = musicList[nextIndex]; } - globalThis.AudioPlayerController.play(context.musicItem.rawFileDescriptor, 0); - context.playState = PlayState.PLAY; - context.playStateIcon = $r('app.media.ic_play'); + let playController = GlobalContext.getContext().getObject('audioPlayerController') as AudioPlayerController; + playController.play(this.playBarModel.musicItem.rawFileDescriptor, 0); + this.playBarModel.playState = PlayState.PLAY; + this.playBarModel.playStateIcon = $r('app.media.ic_play'); // Sets the current music metadata. - AvSessionUtil.setAVMetadata(context); + AvSessionUtil.setAVMetadata(this.playBarModel); AvSessionUtil.setAVPlayState(avSession.PlaybackState.PLAYBACK_STATE_PLAY); } } \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/entryability/EntryAbility.ets b/Media/AudioPlayer/entry/src/main/ets/entryability/EntryAbility.ets index 55f50a541ee6c8dbc9abe9b56530ce40adcdf3f0..cc2ab71bc74a57724b000a2901b35e316f8c1701 100644 --- a/Media/AudioPlayer/entry/src/main/ets/entryability/EntryAbility.ets +++ b/Media/AudioPlayer/entry/src/main/ets/entryability/EntryAbility.ets @@ -18,41 +18,48 @@ import Window from '@ohos.window'; import avSession from '@ohos.multimedia.avsession'; import { AudioPlayerController } from '../controller/AudioPlayerControllerl'; import Logger from '../common/utils/Logger'; +import { GlobalContext } from '../common/utils/GlobalContext'; +import { PlayBarModel } from '../common/model/PlayBarModel'; export default class EntryAbility extends UIAbility { onDestroy() { Logger.info('Ability onDestroy'); // Release resources. - globalThis.AudioPlayerController.release(); - globalThis.currentSession.off('play'); - globalThis.currentSession.off('pause'); - globalThis.currentSession.deactivate().then(() => { - globalThis.currentSession.destroy(); + let audioPlayerController = GlobalContext.getContext().getObject('audioPlayerController') as AudioPlayerController; + audioPlayerController.release(); + + let currentSession = GlobalContext.getContext().getObject('currentSession') as avSession.AVSession; + currentSession.off('play'); + currentSession.off('pause'); + currentSession.deactivate().then(() => { + currentSession.destroy(); }); } onWindowStageCreate(windowStage: Window.WindowStage) { // Main window is created, set main page for this ability. let context = this.context; - globalThis.resourceManager = context.resourceManager; + let resourceManager = context.resourceManager; + GlobalContext.getContext().setObject('resourceManager', resourceManager); // Create an audioPlayer instance. - globalThis.AudioPlayerController = new AudioPlayerController(); + let audioPlayerController = new AudioPlayerController(new PlayBarModel()); + GlobalContext.getContext().setObject('audioPlayerController', audioPlayerController); // Creating an Audio Session. avSession.createAVSession(context, 'AudioAppSample', 'audio').then((session) => { - globalThis.currentSession = session; - globalThis.currentSession.activate(); // Activating a Session. - }).catch((err) => { - Logger.error(`createAVSession : ERROR : ${err.message}`); + session.activate(); + GlobalContext.getContext().setObject('currentSession', session); + }).catch((err: Error) => { + Logger.error(`createAVSession fail, Cause: ${err}`); }); windowStage.loadContent('pages/AudioStartUp', (err, data) => { if (err.code) { - Logger.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + Logger.error('testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); return; } - Logger.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); + Logger.info('testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); }); } } \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/pages/AudioStartUp.ets b/Media/AudioPlayer/entry/src/main/ets/pages/AudioStartUp.ets index 0d2c1463feca36ab3fc112db8b99b6cffc562fa9..db576fd8aae70716e1389ba22e0982ce6f5f8380 100644 --- a/Media/AudioPlayer/entry/src/main/ets/pages/AudioStartUp.ets +++ b/Media/AudioPlayer/entry/src/main/ets/pages/AudioStartUp.ets @@ -20,7 +20,7 @@ import { CommonConstants } from '../common/constants/CommonConstants'; @Entry @Component struct AudioStartUp { - private timeId: number; + private timeId: number = -1; aboutToAppear() { // The play list page is automatically displayed 1s later. @@ -28,7 +28,7 @@ struct AudioStartUp { router.pushUrl({ url: CommonConstants.PAGE_MUSIC_LIST, params: {} - }).catch(err => { + }).catch((err: Error) => { Logger.error('push url fail: ' + err); }) }, CommonConstants.DELAY_TIME) @@ -43,14 +43,15 @@ struct AudioStartUp { Column() { Column() { Image($r('app.media.icon')) - .width(CommonConstants.START_UP_PAGE.IMAGE_WIDTH) - .height(CommonConstants.START_UP_PAGE.IMAGE_HEIGHT) + .width(CommonConstants.START_IMAGE_WIDTH) + .height(CommonConstants.START_IMAGE_HEIGHT) .objectFit(ImageFit.Contain) } - .height(CommonConstants.START_UP_PAGE.IMAGE_CONTAINER) + .height(CommonConstants.START_IMAGE_CONTAINER) .width(CommonConstants.FULL_WIDTH) .alignItems(HorizontalAlign.Center) .justifyContent(FlexAlign.Center) + Text($r('app.string.app_name')) .fontSize($r("app.float.start_title")) .textAlign(TextAlign.Center) diff --git a/Media/AudioPlayer/entry/src/main/ets/pages/MusicList.ets b/Media/AudioPlayer/entry/src/main/ets/pages/MusicList.ets index d0abec0958b688278072dcd6bb7daf9b50a5754b..5dc74c54590ab479eddc4ae1027872fce363437e 100644 --- a/Media/AudioPlayer/entry/src/main/ets/pages/MusicList.ets +++ b/Media/AudioPlayer/entry/src/main/ets/pages/MusicList.ets @@ -15,7 +15,7 @@ import router from '@ohos.router'; import Logger from '../common/utils/Logger'; -import { MusicItem } from '../common/bean/MusicItem'; +import { MusicItem } from '../viewmodel/MusicItem'; import { MusicView } from '../view/MusicView'; import { CommonConstants } from '../common/constants/CommonConstants'; import { initializeMusic } from '../viewmodel/MusicViewModel'; @@ -34,13 +34,13 @@ struct MusicList { Column() { Text($r('app.string.hot_music')) .fontSize($r('app.float.musicList_title')) - .width(CommonConstants.MUSIC_LIST_PAGE.TEXT_WIDTH) - .height(CommonConstants.MUSIC_LIST_PAGE.TEXT_HEIGHT) + .width(CommonConstants.TEXT_WIDTH) + .height(CommonConstants.TEXT_HEIGHT) .margin({ - left: CommonConstants.MUSIC_LIST_PAGE.TEXT_MARGIN_LEFT, - top: CommonConstants.MUSIC_LIST_PAGE.TEXT_MARGIN_TOP, - right: CommonConstants.MUSIC_LIST_PAGE.TEXT_MARGIN_RIGHT, - bottom: CommonConstants.MUSIC_LIST_PAGE.TEXT_MARGIN_BOTTOM + left: CommonConstants.TEXT_MARGIN_LEFT, + top: CommonConstants.TEXT_MARGIN_TOP, + right: CommonConstants.TEXT_MARGIN_RIGHT, + bottom: CommonConstants.TEXT_MARGIN_BOTTOM }) ForEach(this.musicData, (item: MusicItem) => { MusicView({ item: item }) @@ -48,11 +48,11 @@ struct MusicList { router.pushUrl({ url: CommonConstants.PAGE_PLAY, params: { 'item': item } - }).catch((error) => { + }).catch((error: Error) => { Logger.error(`go to play list fail,error: ${error}`); }) }) - }, item => JSON.stringify(item)) + }, (item: MusicItem) => JSON.stringify(item)) } } } \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/pages/Play.ets b/Media/AudioPlayer/entry/src/main/ets/pages/Play.ets index 188e9e2dd86a7fc0ab91ebc5c71937c075ba2a6e..bf7cbe40b9c2b93ccb479c93613f22511618b16e 100644 --- a/Media/AudioPlayer/entry/src/main/ets/pages/Play.ets +++ b/Media/AudioPlayer/entry/src/main/ets/pages/Play.ets @@ -14,40 +14,43 @@ */ import router from '@ohos.router'; -import { MusicItem } from '../common/bean/MusicItem'; +import { MusicItem } from '../viewmodel/MusicItem'; import { AvSessionUtil } from '../common/utils/AvSessionUtil'; import { PlayBarView } from '../view/PlayBarView'; import { ProgressView } from '../view/ProgressView'; import { MusicCardView } from '../view/MusicCardView'; import { CommonConstants, PlayMode } from '../common/constants/CommonConstants'; -import { CommonUtil } from '../common/utils/CommonUtil'; import Logger from '../common/utils/Logger'; +import { GlobalContext } from '../common/utils/GlobalContext'; +import { AudioPlayerController } from '../controller/AudioPlayerControllerl'; +import { PlayBarModel } from '../common/model/PlayBarModel'; +import { PlayBarController } from '../controller/PlayBarController'; @Entry @Component struct Play { @StorageLink('musicList') musicList: Array = []; - @State musicItem: MusicItem = this.musicList[0]; - @State playValue: number = CommonConstants.START_POSITION; // Progress bar position. - @State totalValue: number = CommonConstants.TOTAL_VALUE; // Total length of the progress bar. - @State playMode: number = PlayMode.LIST_LOOP; // Playback mode. - @State playStateIcon: Resource = $r('app.media.ic_play') // Playback status icon. + @Provide playBarModel: PlayBarModel = new PlayBarModel(); + playBarController: PlayBarController = new PlayBarController(this.playBarModel); aboutToAppear() { - globalThis.AudioPlayerController.setMusicList(this.musicList); + let playController = GlobalContext.getContext().getObject('audioPlayerController') as AudioPlayerController; + playController.setMusicList(this.musicList); // Obtain the music file to be played. - this.musicItem = router.getParams()['item']; - if (CommonUtil.isEmpty(this.musicItem)) { + let params = router.getParams() as Record; + this.playBarModel.musicItem = params.item as MusicItem; + if (this.playBarModel.musicItem === undefined) { Logger.error('play fail,musicItem is empty.'); return; } // Access the playback control center. - AvSessionUtil.initAvSession(this); + AvSessionUtil.initAvSession(this.playBarModel); // Setting the media source triggers the dataLoad callback. - globalThis.AudioPlayerController.setEventCallBack(this); - globalThis.AudioPlayerController.play(this.musicItem.rawFileDescriptor, CommonConstants.START_POSITION); + playController.playBarModel = this.playBarModel; + playController.setEventCallBack(); + playController.play(this.playBarModel.musicItem.rawFileDescriptor, CommonConstants.START_POSITION); } build() { @@ -56,37 +59,34 @@ struct Play { Navigator({ target: CommonConstants.PAGE_MUSIC_LIST, type: NavigationType.Back }) { Image($r('app.media.ic_back')) .objectFit(ImageFit.Contain) - .width(CommonConstants.PLAY_PAGE.NAVIGATOR_WIDTH) - .height(CommonConstants.PLAY_PAGE.NAVIGATOR_HEIGHT) + .width(CommonConstants.NAVIGATOR_WIDTH) + .height(CommonConstants.NAVIGATOR_HEIGHT) } + Text($r('app.string.play_title')) .fontSize($r('app.float.play_text')) .fontWeight(CommonConstants.FONT_WEIGHT_BOLDER) .fontColor($r("app.color.font_color_black")) - .layoutWeight(CommonConstants.PLAY_PAGE.LAYOUT_WEIGHT) + .layoutWeight(CommonConstants.LAYOUT_WEIGHT) .textAlign(TextAlign.Center) .width(CommonConstants.FULL_WIDTH) } .width(CommonConstants.FULL_WIDTH) .padding({ - left: CommonConstants.PLAY_PAGE.NAVIGATOR_PADDING_LEFT, - right: CommonConstants.PLAY_PAGE.NAVIGATOR_PADDING_RIGHT + left: CommonConstants.NAVIGATOR_PADDING_LEFT, + right: CommonConstants.NAVIGATOR_PADDING_RIGHT }) .margin({ - top: CommonConstants.PLAY_PAGE.NAVIGATOR_PADDING_TOP, - bottom: CommonConstants.PLAY_PAGE.NAVIGATOR_PADDING_BOTTOM + top: CommonConstants.NAVIGATOR_PADDING_TOP, + bottom: CommonConstants.NAVIGATOR_PADDING_BOTTOM }) + Column() { - MusicCardView({ musicItem: $musicItem }) - ProgressView({ playValue: $playValue, totalValue: $totalValue }) - PlayBarView({ - musicItem: $musicItem, - playMode: $playMode, - playValue: $playValue, - playStateIcon: $playStateIcon - }) + MusicCardView() + ProgressView() + PlayBarView({ playBarController: this.playBarController }) } - .width(CommonConstants.PLAY_PAGE.CONTROL_WIDTH) + .width(CommonConstants.CONTROL_WIDTH) .alignItems(HorizontalAlign.Start) } .height(CommonConstants.FULL_HEIGHT) diff --git a/Media/AudioPlayer/entry/src/main/ets/view/MusicCardView.ets b/Media/AudioPlayer/entry/src/main/ets/view/MusicCardView.ets index e8ac061992c9b2bde06546996ad5065c583ba6ea..a10bd49bd93862e12cc097e31ad8bffa88757c61 100644 --- a/Media/AudioPlayer/entry/src/main/ets/view/MusicCardView.ets +++ b/Media/AudioPlayer/entry/src/main/ets/view/MusicCardView.ets @@ -13,34 +13,34 @@ * limitations under the License. */ -import { MusicItem } from '../common/bean/MusicItem'; import { CommonConstants } from '../common/constants/CommonConstants'; +import { PlayBarModel } from '../common/model/PlayBarModel'; @Component export struct MusicCardView { - @Link musicItem: MusicItem; + @Consume playBarModel: PlayBarModel; build() { Column() { Image($r('app.media.ic_play_icon')) .width(CommonConstants.FULL_WIDTH) - .height(CommonConstants.MUSIC_CARD_VIEW.IMAGE_HEIGHT) - Text(this.musicItem.name) + .height(CommonConstants.IMAGE_HEIGHT) + Text(this.playBarModel.musicItem!.name) .fontSize($r('app.float.music_name')) .fontColor($r("app.color.music_card_color")) .fontWeight(CommonConstants.FONT_WEIGHT_BOLDER) - .margin({ top: CommonConstants.MUSIC_CARD_VIEW.NAME_MARGIN_TOP }) - Text(this.musicItem.singer) + .margin({ top: CommonConstants.NAME_MARGIN_TOP }) + Text(this.playBarModel.musicItem!.singer) .fontSize($r('app.float.music_singer')) .fontColor($r("app.color.music_card_color")) .fontWeight(FontWeight.Normal) - .margin({ top: CommonConstants.MUSIC_CARD_VIEW.SINGER_MARGIN_TOP }) - Text($r('app.string.lyrics', this.musicItem.lyrics)) + .margin({ top: CommonConstants.SINGER_MARGIN_TOP }) + Text($r('app.string.lyrics', this.playBarModel.musicItem!.lyrics)) .fontSize($r('app.float.music_lyrics')) .fontColor($r("app.color.music_card_color")) .fontWeight(FontWeight.Normal) .opacity($r('app.float.lyrics_opacity')) - .margin({ top: CommonConstants.MUSIC_CARD_VIEW.LYRICS_MARGIN_TOP }) + .margin({ top: CommonConstants.LYRICS_MARGIN_TOP }) } .alignItems(HorizontalAlign.Start) } diff --git a/Media/AudioPlayer/entry/src/main/ets/view/MusicView.ets b/Media/AudioPlayer/entry/src/main/ets/view/MusicView.ets index 3ea3e314899d2818e6bc6d75af863675d7e660a4..d52407d8fba12584843a18a07cdf20c23419fd38 100644 --- a/Media/AudioPlayer/entry/src/main/ets/view/MusicView.ets +++ b/Media/AudioPlayer/entry/src/main/ets/view/MusicView.ets @@ -13,19 +13,19 @@ * limitations under the License. */ -import { MusicItem } from '../common/bean/MusicItem'; +import { MusicItem } from '../viewmodel/MusicItem'; import { CommonConstants } from '../common/constants/CommonConstants'; @Component export struct MusicView { - private item: MusicItem; + private item: MusicItem = new MusicItem(); build() { Column() { Row() { Image(this.item.image) - .height(CommonConstants.MUSIC_VIEW.IMAGE_HEIGHT) - .width(CommonConstants.MUSIC_VIEW.IMAGE_WIDTH) + .height(CommonConstants.MUSIC_IMAGE_HEIGHT) + .width(CommonConstants.IMAGE_WIDTH) Column() { Text(this.item.name) .fontSize($r('app.float.musicView_name')) @@ -37,17 +37,17 @@ export struct MusicView { .fontWeight(CommonConstants.FONT_WEIGHT_BOLDER) .opacity($r('app.float.singer_opacity')) } - .margin({ left: CommonConstants.MUSIC_VIEW.ROW_MARGIN_LEFT }) + .margin({ left: CommonConstants.ROW_MARGIN_LEFT }) .alignItems(HorizontalAlign.Start) } .width(CommonConstants.FULL_WIDTH) .alignSelf(ItemAlign.Start) } .margin({ - left: CommonConstants.MUSIC_VIEW.PAGE_MARGIN_LEFT, - top: CommonConstants.MUSIC_VIEW.PAGE_MARGIN_TOP, - right: CommonConstants.MUSIC_VIEW.PAGE_MARGIN_RIGHT, - bottom: CommonConstants.MUSIC_VIEW.PAGE_MARGIN_BUTTON + left: CommonConstants.PAGE_MARGIN_LEFT, + top: CommonConstants.MUSIC_MARGIN_TOP, + right: CommonConstants.PAGE_MARGIN_RIGHT, + bottom: CommonConstants.PAGE_MARGIN_BUTTON }) } } \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/view/PlayBarView.ets b/Media/AudioPlayer/entry/src/main/ets/view/PlayBarView.ets index 051e38f7f33aa8a850c6a54e3e79209535407961..3805b112c1b90cc42c8c88a4e760d2cce4f580e0 100644 --- a/Media/AudioPlayer/entry/src/main/ets/view/PlayBarView.ets +++ b/Media/AudioPlayer/entry/src/main/ets/view/PlayBarView.ets @@ -14,72 +14,65 @@ */ import { PlayListDialogView } from '../view/PlayListDialogView'; -import { MusicItem } from '../common/bean/MusicItem'; +import { MusicItem } from '../viewmodel/MusicItem'; import { PlayBarController } from '../controller/PlayBarController'; -import { CommonConstants, PlayState } from '../common/constants/CommonConstants'; +import { CommonConstants } from '../common/constants/CommonConstants'; +import { PlayBarModel } from '../common/model/PlayBarModel'; @Component export struct PlayBarView { @StorageLink('musicList') musicList: Array = []; - @Link musicItem: MusicItem; - @State playModeIcon: Resource = $r('app.media.ic_list_mode'); // Playback mode icon. - @Link playStateIcon: Resource; - @Link playMode: number; // Playback mode. - @Link playValue: number; // Playback duration position. - playState: number = PlayState.PLAY; // Playback status. - PlayBarController: PlayBarController = new PlayBarController(); + private playBarController?: PlayBarController; + @Consume playBarModel: PlayBarModel; dialogController: CustomDialogController = new CustomDialogController({ builder: PlayListDialogView({ - musicList: $musicList, - musicItem: $musicItem, - playModeIcon: $playModeIcon, - playMode: $playMode + musicList: $musicList }), alignment: DialogAlignment.Bottom }) build() { Row() { - Image(this.playModeIcon) - .width(CommonConstants.CONTROL_VIEW.MODE_ICON_WIDTH) - .height(CommonConstants.CONTROL_VIEW.MODE_ICON_HEIGHT) + Image(this.playBarModel.playModeIcon) + .width(CommonConstants.MODE_ICON_WIDTH) + .height(CommonConstants.MODE_ICON_HEIGHT) .onClick(() => { - this.PlayBarController.switchPlayMode(this); + this.playBarController!.switchPlayMode(); }) Blank() .layoutWeight(1) Image($r('app.media.ic_previous')) - .width(CommonConstants.CONTROL_VIEW.PREVIOUS_WIDTH) - .height(CommonConstants.CONTROL_VIEW.PREVIOUS_HEIGHT) + .width(CommonConstants.PREVIOUS_WIDTH) + .height(CommonConstants.PREVIOUS_HEIGHT) .onClick(() => { - this.PlayBarController.getPreviousMusic(this); + this.playBarController!.getPreviousMusic(this.musicList, this.playBarModel.playState); }) Blank() .layoutWeight(1) - Image(this.playStateIcon) - .width(CommonConstants.CONTROL_VIEW.STATE_ICON_WIDTH) - .height(CommonConstants.CONTROL_VIEW.STATE_ICON_HEIGHT) + Image(this.playBarModel.playStateIcon) + .width(CommonConstants.STATE_ICON_WIDTH) + .height(CommonConstants.STATE_ICON_HEIGHT) .objectFit(ImageFit.Contain) .onClick(() => { - this.PlayBarController.switchPlayState(this); + this.playBarController!.switchPlayState(this.playBarModel.playState); }) Blank() .layoutWeight(1) Image($r('app.media.ic_next')) - .width(CommonConstants.CONTROL_VIEW.NEXT_WIDTH) - .height(CommonConstants.CONTROL_VIEW.NEXT_HEIGHT) + .width(CommonConstants.NEXT_WIDTH) + .height(CommonConstants.NEXT_HEIGHT) .onClick(() => { - this.PlayBarController.getNextMusic(this); + this.playBarController!.getNextMusic(this.musicList); }) Blank() .layoutWeight(1) Image($r('app.media.ic_play_list')) - .width(CommonConstants.CONTROL_VIEW.PLAY_LIST_WIDTH) - .height(CommonConstants.CONTROL_VIEW.PLAY_LIST_HEIGHT) + .width(CommonConstants.PLAY_LIST_WIDTH) + .height(CommonConstants.PLAY_LIST_HEIGHT) .onClick(() => { this.dialogController.open(); }) } - .margin({ top: CommonConstants.CONTROL_VIEW.PAGE_MARGIN_TOP }) + .margin({ top: CommonConstants.PAGE_MARGIN_TOP }) } } \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/view/PlayListDialogView.ets b/Media/AudioPlayer/entry/src/main/ets/view/PlayListDialogView.ets index 8dedbcf04d98a9aa8b94340126cd7550315b8354..c10c15cc870b1ab9fe5ebd02018551b55cc2d0e8 100644 --- a/Media/AudioPlayer/entry/src/main/ets/view/PlayListDialogView.ets +++ b/Media/AudioPlayer/entry/src/main/ets/view/PlayListDialogView.ets @@ -14,22 +14,21 @@ */ import { PlayListMusicView } from './PlayListMusicView'; -import { MusicItem } from '../common/bean/MusicItem'; +import { MusicItem } from '../viewmodel/MusicItem'; import { CommonConstants, PlayMode } from '../common/constants/CommonConstants'; +import { PlayBarModel } from '../common/model/PlayBarModel'; @CustomDialog export struct PlayListDialogView { @Link musicList: Array; - @Link musicItem: MusicItem; - @Link playModeIcon: Resource; - @Link playMode: number; + @Consume playBarModel: PlayBarModel; @State playModeDesc: Resource = $r('app.string.sequence'); - controller: CustomDialogController; + controller: CustomDialogController = new CustomDialogController({ builder: {} }); switchPlayModeDesc() { - if (this.playMode === PlayMode.RANDOM_PLAY) { + if (this.playBarModel.playMode === PlayMode.RANDOM_PLAY) { this.playModeDesc = $r('app.string.random'); - } else if (this.playMode === PlayMode.SINGLE_LOOP) { + } else if (this.playBarModel.playMode === PlayMode.SINGLE_LOOP) { this.playModeDesc = $r('app.string.single'); } else { this.playModeDesc = $r('app.string.sequence'); @@ -43,10 +42,10 @@ export struct PlayListDialogView { build() { Column() { Row() { - Image(this.playModeIcon) - .width(CommonConstants.LIST_DIALOG.IMAGE_WIDTH) - .height(CommonConstants.LIST_DIALOG.IMAGE_HEIGHT) - .margin({ right: CommonConstants.LIST_DIALOG.IMAGE_MARGIN_RIGHT }) + Image(this.playBarModel.playModeIcon) + .width(CommonConstants.DIALOG_IMAGE_WIDTH) + .height(CommonConstants.DIALOG_IMAGE_HEIGHT) + .margin({ right: CommonConstants.IMAGE_MARGIN_RIGHT }) Text(this.playModeDesc) .fontSize($r("app.float.play_mode_description")) .fontWeight(CommonConstants.FONT_WEIGHT_BOLDER) @@ -54,32 +53,33 @@ export struct PlayListDialogView { .textAlign(TextAlign.Start) .alignSelf(ItemAlign.Start) } - .width(CommonConstants.LIST_DIALOG.ROW_WIDTH) + .width(CommonConstants.ROW_WIDTH) .margin({ - top: CommonConstants.LIST_DIALOG.ROW_MARGIN_TOP, - bottom: CommonConstants.LIST_DIALOG.ROW_MARGIN_BOTTOM + top: CommonConstants.ROW_MARGIN_TOP, + bottom: CommonConstants.ROW_MARGIN_BOTTOM }) + List({ - space: CommonConstants.LIST_DIALOG.LIST_SPACE, - initialIndex: CommonConstants.LIST_DIALOG.LIST_INITIAL_INDEX + space: CommonConstants.LIST_SPACE, + initialIndex: CommonConstants.LIST_INITIAL_INDEX }) { ForEach(this.musicList, (item: MusicItem) => { ListItem() { - PlayListMusicView({ musicItem: $musicItem, item: item }) + PlayListMusicView({item: item }) } - }, item => JSON.stringify(item)) + }, (item: MusicItem) => JSON.stringify(item)) } .listDirection(Axis.Vertical) .divider({ - strokeWidth: CommonConstants.LIST_DIALOG.DIVIDER_STROKE_WIDTH, + strokeWidth: CommonConstants.DIVIDER_STROKE_WIDTH, color: CommonConstants.DIVIDER_COLOR, - startMargin: CommonConstants.LIST_DIALOG.DIVIDER_START_MARGIN, - endMargin: CommonConstants.LIST_DIALOG.END_MARGIN + startMargin: CommonConstants.DIVIDER_START_MARGIN, + endMargin: CommonConstants.END_MARGIN }) - .height(CommonConstants.LIST_DIALOG.LIST_HEIGHT) - .width(CommonConstants.LIST_DIALOG.LIST_WIDTH) + .height(CommonConstants.LIST_HEIGHT) + .width(CommonConstants.LIST_WIDTH) } .width(CommonConstants.FULL_WIDTH) - .margin({ left: CommonConstants.LIST_DIALOG.PAGE_MARGIN_LEFT }) + .margin({ left: CommonConstants.DIALOG_MARGIN_LEFT }) } } \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/view/PlayListMusicView.ets b/Media/AudioPlayer/entry/src/main/ets/view/PlayListMusicView.ets index 60d5cddf728b51778aaa678af11131ac6432b4b6..4327653c2f0c651797e6ca59a2df8b0508102852 100644 --- a/Media/AudioPlayer/entry/src/main/ets/view/PlayListMusicView.ets +++ b/Media/AudioPlayer/entry/src/main/ets/view/PlayListMusicView.ets @@ -13,29 +13,32 @@ * limitations under the License. */ -import { MusicItem } from '../common/bean/MusicItem'; +import { MusicItem } from '../viewmodel/MusicItem'; import { CommonConstants } from '../common/constants/CommonConstants'; +import { PlayBarModel } from '../common/model/PlayBarModel'; @Component export struct PlayListMusicView { - @Link musicItem: MusicItem; - private item: MusicItem; + @Consume playBarModel: PlayBarModel; + private item: MusicItem = new MusicItem(); build() { Column() { Text(this.item.name) .fontSize($r('app.float.dialog_name')) - .fontColor(this.musicItem.id === this.item.id ? $r("app.color.font_color_pink") : $r("app.color.dialog_name_color")) + .fontColor(this.playBarModel!.musicItem!.id === this.item.id ? $r('app.color.font_color_pink') : + $r('app.color.dialog_name_color')) .fontWeight(FontWeight.Normal) - .lineHeight(CommonConstants.LIST_DIALOG_MUSIC.LINE_HEIGHT) + .lineHeight(CommonConstants.LINE_HEIGHT) Row() { Image(this.item.isVip ? $r('app.media.ic_vip') : $r('app.media.ic_hd')) - .width(CommonConstants.LIST_DIALOG_MUSIC.IMAGE_WIDTH) - .height(CommonConstants.LIST_DIALOG_MUSIC.IMAGE_HEIGHT) - .margin({ right: CommonConstants.LIST_DIALOG_MUSIC.IMAGE_MARGIN_RIGHT }) + .width(CommonConstants.LIST_IMAGE_WIDTH) + .height(CommonConstants.LIST_IMAGE_HEIGHT) + .margin({ right: CommonConstants.LIST_MARGIN_RIGHT }) Text(this.item.singer) .fontSize($r('app.float.dialog_singer')) - .fontColor(this.musicItem.id === this.item.id ? $r("app.color.font_color_pink") : $r("app.color.dialog_singer_color")) + .fontColor(this.playBarModel!.musicItem!.id === this.item.id ? $r('app.color.font_color_pink') : + $r('app.color.dialog_singer_color')) .fontWeight(FontWeight.Normal) } .width(CommonConstants.FULL_WIDTH) @@ -44,8 +47,8 @@ export struct PlayListMusicView { .alignItems(HorizontalAlign.Start) .width(CommonConstants.FULL_WIDTH) .margin({ - top: CommonConstants.LIST_DIALOG_MUSIC.MUSIC_MARGIN_TOP, - bottom: CommonConstants.LIST_DIALOG_MUSIC.MUSIC_MARGIN_BOTTOM + top: CommonConstants.LIST_MARGIN_TOP, + bottom: CommonConstants.MUSIC_MARGIN_BOTTOM }) } } \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/view/ProgressView.ets b/Media/AudioPlayer/entry/src/main/ets/view/ProgressView.ets index 9c395e292178d7545040de5f06657b2ae75e6e88..ed5057e46ec726cbc797f45ebe7fa227de993ac2 100644 --- a/Media/AudioPlayer/entry/src/main/ets/view/ProgressView.ets +++ b/Media/AudioPlayer/entry/src/main/ets/view/ProgressView.ets @@ -15,32 +15,32 @@ import { CommonUtil } from '../common/utils/CommonUtil'; import { CommonConstants } from '../common/constants/CommonConstants'; +import { PlayBarModel } from '../common/model/PlayBarModel'; @Component export struct ProgressView { - @Link playValue: number; - @Link totalValue: number; + @Consume playBarModel: PlayBarModel; build() { Row() { - Text(CommonUtil.formatDuration(this.playValue)) + Text(CommonUtil.formatDuration(this.playBarModel.playValue)) .fontColor($r("app.color.music_card_color")) .fontSize($r('app.float.dialog_singer')) - .margin({ right: CommonConstants.PROGRESS_VIEW.TEXT_MARGIN_RIGHT }) + .margin({ right: CommonConstants.PROGRESS_MARGIN_RIGHT }) Slider({ - value: this.playValue, - min: CommonConstants.PROGRESS_VIEW.PROGRESS_MIN, - max: this.totalValue, + value: this.playBarModel.playValue, + min: CommonConstants.PROGRESS_MIN, + max: this.playBarModel.totalValue, style: SliderStyle.OutSet }) .enabled(false) .selectedColor($r("app.color.music_card_color")) .layoutWeight(1) - Text(CommonUtil.formatDuration(this.totalValue)) + Text(CommonUtil.formatDuration(this.playBarModel.totalValue)) .fontColor($r("app.color.music_card_color")) .fontSize($r('app.float.dialog_singer')) - .margin({ left: CommonConstants.PROGRESS_VIEW.TEXT_MARGIN_LEFT }) + .margin({ left: CommonConstants.PROGRESS_MARGIN_LEFT }) } - .margin({ top: CommonConstants.PROGRESS_VIEW.VIEW_MARGIN_TOP }) + .margin({ top: CommonConstants.VIEW_MARGIN_TOP }) } } \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/viewmodel/MusicItem.ets b/Media/AudioPlayer/entry/src/main/ets/viewmodel/MusicItem.ets new file mode 100644 index 0000000000000000000000000000000000000000..7dd0971ca037f8475f9acdf4acf352fdf3bff286 --- /dev/null +++ b/Media/AudioPlayer/entry/src/main/ets/viewmodel/MusicItem.ets @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import resourceManager from '@ohos.resourceManager'; + +/** + * Song entity class. + */ +export class MusicItem { + /** + * Identifier. + */ + id: number = 0; + /** + * Music name. + */ + name: string = ''; + /** + * Singer. + */ + singer: string = ''; + /** + * Lyricist. + */ + lyrics: string = ''; + /** + * Resource Path. + */ + path: string = ''; + /** + * Member song or not. + */ + isVip: boolean = false; + /** + * Song icon. + */ + image: Resource = $r('app.media.icon'); + /** + * Resource descriptor. + */ + rawFileDescriptor: resourceManager.RawFileDescriptor = {} as resourceManager.RawFileDescriptor; +} \ No newline at end of file diff --git a/Media/AudioPlayer/entry/src/main/ets/viewmodel/MusicViewModel.ets b/Media/AudioPlayer/entry/src/main/ets/viewmodel/MusicViewModel.ets index 3870b7c6afd98ab1b36bb311752022fe6aa1a604..b6a310cf1f14d7f306dce7a456ba45ea6666fa70 100644 --- a/Media/AudioPlayer/entry/src/main/ets/viewmodel/MusicViewModel.ets +++ b/Media/AudioPlayer/entry/src/main/ets/viewmodel/MusicViewModel.ets @@ -13,10 +13,10 @@ * limitations under the License. */ +import resourceManager from '@ohos.resourceManager'; import Logger from '../common/utils/Logger'; -import { MusicItem, MusicItemProperties } from '../common/bean/MusicItem'; +import { MusicItem } from './MusicItem'; import { ResourceManagerUtil } from '../common/utils/ResourceManagerUtil'; -import { CommonUtil } from '../common/utils/CommonUtil'; /** * Log tag. @@ -26,60 +26,66 @@ const TAG = '[MusicViewModel]'; /** * Music data. */ -const MUSIC_DATA: MusicItemProperties[] = [ +const MUSIC_DATA: MusicItem[] = [ { - 'id': 0, - 'name': 'CLASSIC', - 'singer': 'classic', - 'lyrics': 'cl_lyrics', - 'path': 'classic.wav', - 'isVip': false, - 'image': $r('app.media.ic_music_icon') + id: 0, + name: 'CLASSIC', + singer: 'classic', + lyrics: 'cl_lyrics', + path: 'classic.wav', + isVip: false, + image: $r('app.media.ic_music_icon'), + rawFileDescriptor: {} as resourceManager.RawFileDescriptor }, { - 'id': 1, - 'name': 'DYNAMIC', - 'singer': 'dynamic', - 'lyrics': 'cl_dynamic', - 'path': 'dynamic.wav', - 'isVip': false, - 'image': $r('app.media.ic_music_icon') + id: 1, + name: 'DYNAMIC', + singer: 'dynamic', + lyrics: 'cl_dynamic', + path: 'dynamic.wav', + isVip: false, + image: $r('app.media.ic_music_icon'), + rawFileDescriptor: {} as resourceManager.RawFileDescriptor }, { - 'id': 2, - 'name': 'FRESHNESS', - 'singer': 'freshness', - 'lyrics': 'cl_freshness', - 'path': 'freshness.wav', - 'isVip': true, - 'image': $r('app.media.ic_music_icon') + id: 2, + name: 'FRESHNESS', + singer: 'freshness', + lyrics: 'cl_freshness', + path: 'freshness.wav', + isVip: true, + image: $r('app.media.ic_music_icon'), + rawFileDescriptor: {} as resourceManager.RawFileDescriptor }, { - 'id': 3, - 'name': 'LIVELY', - 'singer': 'lively', - 'lyrics': 'cl_lively', - 'path': 'lively.mp3', - 'isVip': false, - 'image': $r('app.media.ic_music_icon') + id: 3, + name: 'LIVELY', + singer: 'lively', + lyrics: 'cl_lively', + path: 'lively.mp3', + isVip: false, + image: $r('app.media.ic_music_icon'), + rawFileDescriptor: {} as resourceManager.RawFileDescriptor }, { - 'id': 4, - 'name': 'NATURE', - 'singer': 'nature', - 'lyrics': 'cl_nature', - 'path': 'nature.mp3', - 'isVip': false, - 'image': $r('app.media.ic_music_icon') + id: 4, + name: 'NATURE', + singer: 'nature', + lyrics: 'cl_nature', + path: 'nature.mp3', + isVip: false, + image: $r('app.media.ic_music_icon'), + rawFileDescriptor: {} as resourceManager.RawFileDescriptor }, { - 'id': 5, - 'name': 'ROMANTIC', - 'singer': 'romantic', - 'lyrics': 'cl_romantic', - 'path': 'romantic.wav', - 'isVip': false, - 'image': $r('app.media.ic_music_icon') + id: 5, + name: 'ROMANTIC', + singer: 'romantic', + lyrics: 'cl_romantic', + path: 'romantic.wav', + isVip: false, + image: $r('app.media.ic_music_icon'), + rawFileDescriptor: {} as resourceManager.RawFileDescriptor } ]; @@ -90,13 +96,14 @@ const MUSIC_DATA: MusicItemProperties[] = [ * @param musicDataArray Music data array. */ export function initializeMusic(musicDataArray: Array) { - if (CommonUtil.isEmpty(musicDataArray)) { + if (musicDataArray === undefined) { Logger.error(TAG, 'getNextMusic fail,context is empty.'); return; } - MUSIC_DATA.forEach((item) => { - ResourceManagerUtil.getSrcPath(item.path, (value) => { - musicDataArray.push(new MusicItem(item, value)); + MUSIC_DATA.forEach((item: MusicItem) => { + ResourceManagerUtil.getSrcPath(item.path, (value: resourceManager.RawFileDescriptor) => { + item.rawFileDescriptor = value; + musicDataArray.push(item); Logger.info(TAG, 'ResourceManagerUtil: ' + musicDataArray.length); }) }) diff --git a/Media/AudioPlayer/hvigor/hvigor-config.json5 b/Media/AudioPlayer/hvigor/hvigor-config.json5 index dd6d7a66b580d1a50c108144878558f98ae6837f..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/Media/AudioPlayer/hvigor/hvigor-config.json5 +++ b/Media/AudioPlayer/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.1.1", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.1.1" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/Media/ImageEdit/README.md b/Media/ImageEdit/README.md index a4af18cd76e0b8defa88fb450b258f1898c14a83..b3290f14e6d36074eb91cc35de76029bfa8f9597 100644 --- a/Media/ImageEdit/README.md +++ b/Media/ImageEdit/README.md @@ -20,13 +20,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -53,16 +53,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ ├──CropType.ets // 按比例选取图片 -│ │ │ ├──ImageSizeItem.ets // 图片尺寸 -│ │ │ ├──Line.ets // 线封装类 -│ │ │ ├──MessageItem.ets // 多线程封装消息 -│ │ │ ├──PixelMapWrapper.ets // PixelMap封装类 -│ │ │ ├──Point.ets // 点封装类 -│ │ │ ├──Ratio.ets // 比例封装类 -│ │ │ ├──Rect.ets // 矩形封装类 -│ │ │ └──RegionItem.ets // 区域封装类 │ │ └──constant │ │ └──CommonConstant.ets // 常量类 │ ├──entryability @@ -81,12 +71,21 @@ │ ├──view │ │ ├──AdjustContentView.ets // 色域调整视图 │ │ └──ImageSelect.ets // Canvas选择框实现类 -│ │──viewmodel +│ ├──viewmodel │ │ ├──CropShow.ets // 选择框显示控制类 +│ │ ├──CropType.ets // 按比例选取图片 │ │ ├──IconListViewModel.ets // icon数据 │ │ ├──ImageEditCrop.ets // 图片编辑操作类 │ │ ├──ImageFilterCrop.ets // 图片操作收集类 +│ │ ├──ImageSizeItem.ets // 图片尺寸 +│ │ ├──Line.ets // 线封装类 +│ │ ├──MessageItem.ets // 多线程封装消息 │ │ ├──OptionViewModel.ets // 图片处理封装类 +│ │ ├──PixelMapWrapper.ets // PixelMap封装类 +│ │ ├──Point.ets // 点封装类 +│ │ ├──Ratio.ets // 比例封装类 +│ │ ├──Rect.ets // 矩形封装类 +│ │ ├──RegionItem.ets // 区域封装类 │ │ └──ScreenManager.ts // 屏幕尺寸计算工具类 │ └──workers │ ├──AdjustBrightnessWork.ts // 亮度异步调节 @@ -110,14 +109,39 @@ // HomePage.ets aboutToAppear() { this.pixelInit(); + ... } -// DecodeUtil.ets -async function getResourceFd(filename: string) { +build() { + Column() { + ... + Column() { + if (this.isCrop && this.showCanvas && this.statusBar > 0) { + if (this.isSaveFresh) { + ImageSelect({ + statusBar: this.statusBar + }) + } + ... + } else { + if (this.isPixelMapChange) { + Image(this.pixelMap) + .scale({ x: this.imageScale, y: this.imageScale, z: 1 }) + .objectFit(ImageFit.None) + } + ... + } + } + ... + } + ... +} + +async getResourceFd(filename: string) { const resourceMgr = getContext(this).resourceManager; const context = getContext(this); if (filename === CommonConstants.RAW_FILE_NAME) { - let imageBuffer = await resourceMgr.getMediaContent($r('app.media.ic_low')); + let imageBuffer = await resourceMgr.getMediaContent($r("app.media.ic_low")) let filePath = context.cacheDir + '/' + filename; let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); let writeLen = fs.writeSync(file.fd, imageBuffer.buffer); @@ -130,9 +154,8 @@ async function getResourceFd(filename: string) { } } -//DecodeUtil.ets -export async function getPixelMap(fileName: string) { - const fd = await getResourceFd(fileName); +async getPixelMap(fileName: string) { + const fd = await this.getResourceFd(fileName); const imageSourceApi = image.createImageSource(fd); if (!imageSourceApi) { Logger.error(TAG, 'imageSourceAPI created failed!'); @@ -143,26 +166,6 @@ export async function getPixelMap(fileName: string) { }); return pixelMap; } - -// HomePage.ets -build() { - Column() { - ... - Column() { - if (this.isCrop && this.showCanvas && this.statusBar > 0) { - ImageSelect({ - statusBar: this.statusBar - }) - } else { - Image(this.pixelMap) - .scale({ x: this.imageScale, y: this.imageScale, z: 1 }) - .objectFit(ImageFit.None) - } - } - ... - } - ... -} ``` ## 图片处理 @@ -270,7 +273,7 @@ function hsv2rgb(hue: number, saturation: number, value: number) { 2. 确定裁剪的方式,当前裁剪默认有自由选取、1:1选取、4:3选取、16:9选取。 3. 通过pixelMap调用接口crop\(\)进行裁剪操作。 ->![](public_sys-resources/icon-note.gif) **说明:** +>![](/public_sys-resources/icon-note.gif) **说明:** >当前裁剪功能采用pixelMap裁剪能力直接做切割,会有叠加效果,后续会通过增加选取框对当前功能进行优化。 ![](figures/zh-cn_image_0000001542044862.gif) @@ -291,6 +294,7 @@ cropImage(index: CropType) { break; case CropType.RECTANGLE: this.cropRatio = CropRatioType.RATIO_TYPE_16_9; + break; default: this.cropRatio = CropRatioType.RATIO_TYPE_FREE; break; @@ -298,14 +302,16 @@ cropImage(index: CropType) { } // ImageFilterCrop.ets -cropImage(pixelMap: PixelMapWrapper, realCropRect: RectF, callback) { +cropImage(pixelMap: PixelMapWrapper, realCropRect: RectF, callback: () => void) { let offWidth = realCropRect.getWidth(); let offHeight = realCropRect.getHeight(); - pixelMap.pixelMap.crop({ - size:{ height: vp2px(offHeight), width: vp2px(offWidth) }, - x: vp2px(realCropRect.left), - y: vp2px(realCropRect.top) - }, callback); + if (pixelMap.pixelMap!== undefined) { + pixelMap.pixelMap.crop({ + size:{ height: vp2px(offHeight), width: vp2px(offWidth) }, + x: vp2px(realCropRect.left), + y: vp2px(realCropRect.top) + }, callback); + } } ``` @@ -319,22 +325,26 @@ cropImage(pixelMap: PixelMapWrapper, realCropRect: RectF, callback) { ```typescript // HomePage.ets rotateImage(rotateType: RotateType) { - if (rotateType === RotateType.ClockWise) { + if (rotateType === RotateType.CLOCKWISE) { try { - this.pixelMap.rotate(commonConstant.CLOCK_WISE) - .then(() => { - this.flushPixelMap(); - }) + if (this.pixelMap !== undefined) { + this.pixelMap.rotate(CommonConstants.CLOCK_WISE) + .then(() => { + this.flushPixelMapNew(); + }) + } } catch (error) { Logger.error(TAG, `there is a error in rotate process with ${error?.code}`); } } - if (rotateType === RotateType.Anti_clock) { + if (rotateType === RotateType.ANTI_CLOCK) { try { - this.pixelMap.rotate(commonConstant.ANTI_CLOCK) - .then(() => { - this.flushPixelMap(); - }) + if (this.pixelMap !== undefined) { + this.pixelMap.rotate(CommonConstants.ANTI_CLOCK) + .then(() => { + this.flushPixelMapNew(); + }) + } } catch (error) { Logger.error(TAG, `there is a error in rotate process with ${error?.code}`); } @@ -350,37 +360,43 @@ rotateImage(rotateType: RotateType) { 4. 将计算好的ArrayBuffer发送回主线程。 5. 将ArrayBuffer写入pixelMap,刷新UI。 ->![](public_sys-resources/icon-note.gif) **说明:** +>![](/public_sys-resources/icon-note.gif) **说明:** >当前亮度调节是在UI层面实现的,未实现细节优化算法,只做简单示例。调节后的图片会有色彩上的失真。 ![](figures/zh-cn_image_0000001542044962.gif) ```typescript // AdjustContentView.ets -// 转化成pixelMap及发送buffer到worker,返回数据刷新UI +// 转化成pixelMap及发送buffer到worker,返回数据刷新ui postToWorker(type: AdjustId, value: number, workerName: string) { let sliderValue = type === AdjustId.BRIGHTNESS ? this.brightnessLastSlider : this.saturationLastSlider; - let workerInstance = new worker.ThreadWorker(workerName); - const bufferArray = new ArrayBuffer(this.pixelMap.getPixelBytesNumber()); - this.pixelMap.readPixelsToBuffer(bufferArray).then(() => { - let message = new MessageItem(bufferArray, sliderValue, value); - workerInstance.postMessage(message); - if (this.postState) { - this.deviceListDialogController.open(); - } - this.postState = false; - workerInstance.onmessage = this.updatePixelMap.bind(this); - if (type === AdjustId.BRIGHTNESS) { - this.brightnessLastSlider = Math.round(value); - } else { - this.saturationLastSlider = Math.round(value); - } - workerInstance.onexit = () => { - if (workerInstance !== undefined) { - workerInstance.terminate(); + try { + let workerInstance = new worker.ThreadWorker(workerName); + const bufferArray = new ArrayBuffer(this.pixelMap.getPixelBytesNumber()); + this.pixelMap.readPixelsToBuffer(bufferArray).then(() => { + let message = new MessageItem(bufferArray, sliderValue, value); + workerInstance.postMessage(message); + if (this.postState) { + this.deviceListDialogController.open(); } - } - }); + this.postState = false; + workerInstance.onmessage = (event: MessageEvents) => { + this.updatePixelMap(event) + }; + if (type === AdjustId.BRIGHTNESS) { + this.brightnessLastSlider = Math.round(value); + } else { + this.saturationLastSlider = Math.round(value); + } + workerInstance.onexit = () => { + if (workerInstance !== undefined) { + workerInstance.terminate(); + } + } + }); + } catch (error) { + Logger.error(`Create work instance fail, error message: ${JSON.stringify(error)}`) + } } // AdjustBrightnessWork.ts @@ -415,11 +431,7 @@ export async function adjustOpacity(pixelMap: PixelMap, value: number) { return; } const newPixelMap = pixelMap; - newPixelMap.opacity(value / CommonConstants.SLIDER_MAX, err => { - if (err) { - Logger.error(TAG, `Failed adjust opacity with ${err}`); - } - }) + await newPixelMap.opacity(value / CommonConstants.SLIDER_MAX); return newPixelMap; } ``` @@ -432,46 +444,52 @@ export async function adjustOpacity(pixelMap: PixelMap, value: number) { 4. 将计算好的ArrayBuffer发送回主线程。 5. 将ArrayBuffer写入pixelMap,刷新UI。 ->![](public_sys-resources/icon-note.gif) **说明:** +>![](/public_sys-resources/icon-note.gif) **说明:** > 当前饱和度调节是在UI层面实现的,未实现细节优化算法,只做简单示例。调节后的图片会有色彩上的失真。 ![](figures/zh-cn_image_0000001592604569.gif) ```typescript // AdjustContentView.ets -// 转化成pixelMap及发送buffer到worker,返回数据刷新UI +// 转化成pixelMap及发送buffer到worker,返回数据刷新ui postToWorker(type: AdjustId, value: number, workerName: string) { let sliderValue = type === AdjustId.BRIGHTNESS ? this.brightnessLastSlider : this.saturationLastSlider; - let workerInstance = new worker.ThreadWorker(workerName); - const bufferArray = new ArrayBuffer(this.pixelMap.getPixelBytesNumber()); - this.pixelMap.readPixelsToBuffer(bufferArray).then(() => { - let message = new MessageItem(bufferArray, sliderValue, value); - workerInstance.postMessage(message); - if (this.postState) { - this.deviceListDialogController.open(); - } - this.postState = false; - workerInstance.onmessage = this.updatePixelMap.bind(this); - if (type === AdjustId.BRIGHTNESS) { - this.brightnessLastSlider = Math.round(value); - } else { - this.saturationLastSlider = Math.round(value); - } - workerInstance.onexit = () => { - if (workerInstance !== undefined) { - workerInstance.terminate(); + try { + let workerInstance = new worker.ThreadWorker(workerName); + const bufferArray = new ArrayBuffer(this.pixelMap.getPixelBytesNumber()); + this.pixelMap.readPixelsToBuffer(bufferArray).then(() => { + let message = new MessageItem(bufferArray, sliderValue, value); + workerInstance.postMessage(message); + if (this.postState) { + this.deviceListDialogController.open(); } - } - }); + this.postState = false; + workerInstance.onmessage = (event: MessageEvents) => { + this.updatePixelMap(event) + }; + if (type === AdjustId.BRIGHTNESS) { + this.brightnessLastSlider = Math.round(value); + } else { + this.saturationLastSlider = Math.round(value); + } + workerInstance.onexit = () => { + if (workerInstance !== undefined) { + workerInstance.terminate(); + } + } + }); + } catch (error) { + Logger.error(`Create work instance fail, error message: ${JSON.stringify(error)}`); + } } -// AdjustBrightnessWork.ts +// AdjustSaturationWork.ts // worker线程处理部分 workerPort.onmessage = function(event : MessageEvents) { let bufferArray = event.data.buf; let last = event.data.last; let cur = event.data.cur; - let buffer = adjustImageValue(bufferArray, last, cur); + let buffer = adjustSaturation(bufferArray, last, cur) workerPort.postMessage(buffer); workerPort.close(); } @@ -495,10 +513,14 @@ export function adjustSaturation(bufferArray: ArrayBuffer, last: number, cur: nu 6. 使用fs将打包好的图片数据写入到媒体文件asset中。 ```typescript -// EncodeUtil.ets -export async function encode(pixelMap: PixelMap) { +// ImageSelect.ets +async encode(pixelMap: PixelMap | undefined) { + if (pixelMap === undefined) { + return; + } + const newPixelMap = pixelMap; - // packing image. + // 打包图片 const imagePackerApi = image.createImagePacker(); const packOptions: image.PackingOption = { format: CommonConstants.ENCODE_FORMAT, @@ -506,12 +528,12 @@ export async function encode(pixelMap: PixelMap) { } const imageData = await imagePackerApi.packing(newPixelMap, packOptions); Logger.info(TAG, `imageData's length is ${imageData.byteLength}`); - // get album's path. + // 获取相册路径 const context = getContext(this); const media = mediaLibrary.getMediaLibrary(context); const publicPath = await media.getPublicDirectory(mediaLibrary.DirectoryType.DIR_IMAGE); const currentTime = new Date().getTime(); - // create image asset. + // 创建图片资源 const imageAssetInfo = await media.createAsset( mediaLibrary.MediaType.IMAGE, `${CommonConstants.IMAGE_PREFIX}_${currentTime}${CommonConstants.IMAGE_FORMAT}`, @@ -519,7 +541,7 @@ export async function encode(pixelMap: PixelMap) { ); const imageFd = await imageAssetInfo.open(CommonConstants.ENCODE_FILE_PERMISSION); await fs.write(imageFd, imageData); - // image resource release. + // 释放资源 await imageAssetInfo.close(imageFd); imagePackerApi.release(); await media.release(); diff --git a/Media/ImageEdit/entry/src/main/ets/entryability/EntryAbility.ts b/Media/ImageEdit/entry/src/main/ets/entryability/EntryAbility.ts index 5dfb84bcb4f07694887f77902f60d0b5769b108d..d085be2c509cf943780eb8a41ce8a51e92c430d3 100644 --- a/Media/ImageEdit/entry/src/main/ets/entryability/EntryAbility.ts +++ b/Media/ImageEdit/entry/src/main/ets/entryability/EntryAbility.ts @@ -24,9 +24,11 @@ export default class EntryAbility extends UIAbility { hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); window.getLastWindow(this.context, (err, window) => { if (err) { - hilog.error(0x0000, 'testTag', '%{public}s',`window loading has error: ${JSON.stringify(err)}`); + hilog.error(0x0000, 'testTag', '%{public}s', `window loading has error: ${JSON.stringify(err)}`); } - globalThis.statusBar = window.getWindowProperties().windowRect?.top; + // AppStorage.SetOrCreate('statusBar', window.getWindowProperties().windowRect?.top); + // AppStorage.SetOrCreate('statusBar', 72); + AppStorage.SetOrCreate('statusBar', 56); }); } diff --git a/Media/ImageEdit/entry/src/main/ets/pages/HomePage.ets b/Media/ImageEdit/entry/src/main/ets/pages/HomePage.ets index d80c5fa1788878e8267392cd13443725bde3fd27..24e01dfc72f463e149ccd65d1089d6d0a754ec1d 100644 --- a/Media/ImageEdit/entry/src/main/ets/pages/HomePage.ets +++ b/Media/ImageEdit/entry/src/main/ets/pages/HomePage.ets @@ -14,18 +14,16 @@ */ import image from '@ohos.multimedia.image'; -import window from '@ohos.window'; +import fs from '@ohos.file.fs'; import { IconStatus } from '../viewModel/IconListViewModel'; import AdjustContentView from '../view/AdjustContentView'; import { cropIconChangeList, menuIconList } from '../viewModel/IconListViewModel'; import Logger from '../utils/LoggerUtil'; import { RotateType, CropType, MainTabId } from '../viewModel/OptionViewModel'; -import { encode } from '../utils/EncodeUtil'; -import { getPixelMap } from '../utils/DecodeUtil'; import { CommonConstants } from '../common/constant/CommonConstants'; import { ImageSelect } from '../view/ImageSelect'; -import { ImageSizeItem } from '../common/bean/ImageSizeItem'; -import { CropRatioType } from '../common/bean/CropType'; +import { ImageSizeItem } from '../viewmodel/ImageSizeItem'; +import { CropRatioType } from '../viewmodel/CropType'; const TAG: string = 'imageEdit'; @@ -34,8 +32,8 @@ const TAG: string = 'imageEdit'; struct HomePage { @State @Watch('listenCropChange') currentIndex: number = 0; @State currentCropIndex: number = 0; - @Provide pixelMap: image.PixelMap = undefined; - @Provide imageInfo: image.ImageInfo = undefined; + @Provide pixelMap: image.PixelMap | undefined = undefined; + @Provide imageInfo: image.ImageInfo | undefined = undefined; @Provide currentAdjustData: Array = CommonConstants.ADJUST_SLIDER_VALUE.map((item) => item); @Provide resetShow: boolean = true; @Provide showCanvas: boolean = false; @@ -56,13 +54,8 @@ struct HomePage { @Provide isSaveFresh: boolean = false; aboutToAppear() { + this.statusBar = AppStorage.Get('statusBar') as number; this.pixelInit(); - window.getLastWindow(getContext(this), (err, window) => { - if (err) { - Logger.error(0x0000, 'testTag', '%{public}s',`window loading has error: ${JSON.stringify(err)}`); - } - this.statusBar = window.getWindowProperties().windowRect?.top; - }); } build() { @@ -167,7 +160,7 @@ struct HomePage { .onClick(() => { this.cropImage(index); }) - }, index => index) + }, (item: IconStatus) => JSON.stringify(item)) } .width(CommonConstants.LAYOUT_FULL_SCREEN) .height(CommonConstants.LAYOUT_FULL_SCREEN) @@ -217,7 +210,8 @@ struct HomePage { .backgroundColor(Color.Black) } - @Builder TabBuilderMenu(index: number, name: string | Resource) { + @Builder + TabBuilderMenu(index: number, name: string | Resource) { Column() { Image(this.currentIndex === index ? this.menuIconChangeList[index]?.chosen : this.menuIconChangeList[index]?.normal) @@ -256,20 +250,25 @@ struct HomePage { rotateImage(rotateType: RotateType) { if (rotateType === RotateType.CLOCKWISE) { try { - this.pixelMap.rotate(CommonConstants.CLOCK_WISE) - .then(() => { - this.flushPixelMapNew(); - }) + if (this.pixelMap !== undefined) { + this.pixelMap.rotate(CommonConstants.CLOCK_WISE) + .then(() => { + this.flushPixelMapNew(); + }) + } } catch (error) { Logger.error(TAG, `there is a error in rotate process with ${error?.code}`); } } if (rotateType === RotateType.ANTI_CLOCK) { try { - this.pixelMap.rotate(CommonConstants.ANTI_CLOCK) - .then(() => { - this.flushPixelMapNew(); - }) + if (this.pixelMap !== undefined) { + + this.pixelMap.rotate(CommonConstants.ANTI_CLOCK) + .then(() => { + this.flushPixelMapNew(); + }) + } } catch (error) { Logger.error(TAG, `there is a error in rotate process with ${error?.code}`); } @@ -288,18 +287,20 @@ struct HomePage { this.updateImageInfo(); } - updateImageInfo() { - this.pixelMap.getImageInfo().then((imageInfo) => { - this.imageInfo = imageInfo; - this.imageWidth = px2vp(this.imageInfo.size.width); - this.imageHeight = px2vp(this.imageInfo.size.height); - this.imageOldSize = { - width: this.imageWidth, - height: this.imageHeight - } - this.showCanvas = true; - this.calcScale(); - }); + async updateImageInfo() { + if (this.pixelMap !== undefined) { + await this.pixelMap.getImageInfo().then((imageInfo) => { + this.imageInfo = imageInfo; + this.imageWidth = px2vp(this.imageInfo.size.width); + this.imageHeight = px2vp(this.imageInfo.size.height); + this.imageOldSize = { + width: this.imageWidth, + height: this.imageHeight + } + this.showCanvas = true; + this.calcScale(); + }); + } } calcScale() { @@ -312,7 +313,7 @@ struct HomePage { pixelInit() { this.showCanvas = false; - getPixelMap(CommonConstants.RAW_FILE_NAME).then(pixelMap => { + this.getPixelMap(CommonConstants.RAW_FILE_NAME).then(pixelMap => { this.pixelMap = pixelMap; this.currentCropIndex = 0; this.currentAdjustData = CommonConstants.ADJUST_SLIDER_VALUE.map((item) => item); @@ -329,4 +330,45 @@ struct HomePage { this.resetShow = false; } } -} \ No newline at end of file + + /** + * Async get resource fd. + * + * @return file fd. + */ + async getResourceFd(filename: string) { + const resourceMgr = getContext(this).resourceManager; + const context = getContext(this); + if (filename === CommonConstants.RAW_FILE_NAME) { + let imageBuffer = await resourceMgr.getMediaContent($r("app.media.ic_low")) + let filePath = context.cacheDir + '/' + filename; + let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + let writeLen = fs.writeSync(file.fd, imageBuffer.buffer); + fs.copyFileSync(filePath, context.cacheDir + '/' + CommonConstants.RAW_FILE_NAME_TEST); + return file.fd; + } else { + let filePath = context.cacheDir + '/' + filename; + let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + return file.fd; + } + } + + /** + * Async create pixel map. + * + * @return pixelMa. + */ + async getPixelMap(fileName: string) { + const fd = await this.getResourceFd(fileName); + const imageSourceApi = image.createImageSource(fd); + if (!imageSourceApi) { + Logger.error(TAG, 'imageSourceAPI created failed!'); + return; + } + const pixelMap = await imageSourceApi.createPixelMap({ + editable: true + }); + return pixelMap; + } +} + diff --git a/Media/ImageEdit/entry/src/main/ets/utils/CropUtil.ets b/Media/ImageEdit/entry/src/main/ets/utils/CropUtil.ets index 3b247296412a005b9aa06350e9d5dea54fb6ac0d..da3c9582d78bfa3dad4aedd3e14392b5b5ce3c8a 100644 --- a/Media/ImageEdit/entry/src/main/ets/utils/CropUtil.ets +++ b/Media/ImageEdit/entry/src/main/ets/utils/CropUtil.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { RegionItem } from '../common/bean/RegionItem'; +import { RegionItem } from '../viewmodel/RegionItem'; import { CommonConstants } from '../common/constant/CommonConstants'; /** @@ -59,7 +59,8 @@ export async function cropCommon(pixelMap: PixelMap, cropWidth: number, cropHeig width: cropWidth, height: cropHeight }, - ...cropPosition + x: cropPosition.x, + y: cropPosition.y }); } @@ -74,7 +75,7 @@ export async function banner(pixelMap: PixelMap, width: number, height: number) if (width <= height) { const cropWidth = width; const cropHeight = Math.floor(width * CommonConstants.CROP_RATE_4_3); - const cropPosition = { + const cropPosition: RegionItem = { x: 0, y: Math.floor((height - cropHeight) / CommonConstants.AVERAGE_WEIGHT_WIDTH) }; @@ -84,7 +85,7 @@ export async function banner(pixelMap: PixelMap, width: number, height: number) if (width * CommonConstants.CROP_RATE_4_3 >= height) { const cropWidth = Math.floor(height / CommonConstants.CROP_RATE_4_3); const cropHeight = height; - const cropPosition = { + const cropPosition: RegionItem = { x: Math.floor((width - cropWidth) / CommonConstants.AVERAGE_WEIGHT_WIDTH), y: 0 }; @@ -94,7 +95,7 @@ export async function banner(pixelMap: PixelMap, width: number, height: number) const cropWidth = width; const cropHeight = Math.floor(width * CommonConstants.CROP_RATE_4_3); - const cropPosition = { + const cropPosition: RegionItem = { x: 0, y: Math.floor((height - cropHeight) / CommonConstants.AVERAGE_WEIGHT_WIDTH) } @@ -112,7 +113,7 @@ export async function rectangle(pixelMap: PixelMap, width: number, height: numbe if (width <= height) { const cropWidth = width; const cropHeight = Math.floor(width * (CommonConstants.CROP_RATE_9_16)); - const cropPosition = { + const cropPosition: RegionItem = { x: 0, y: Math.floor((height - cropHeight) / CommonConstants.AVERAGE_WEIGHT_WIDTH) }; @@ -122,7 +123,7 @@ export async function rectangle(pixelMap: PixelMap, width: number, height: numbe if (width * (CommonConstants.CROP_RATE_9_16) >= height) { const cropWidth = Math.floor(height / (CommonConstants.CROP_RATE_9_16)); const cropHeight = height; - const cropPosition = { + const cropPosition: RegionItem = { x: Math.floor((width - cropWidth) / CommonConstants.AVERAGE_WEIGHT_WIDTH), y: 0 }; @@ -132,7 +133,7 @@ export async function rectangle(pixelMap: PixelMap, width: number, height: numbe const cropWidth = width; const cropHeight = Math.floor(width * (CommonConstants.CROP_RATE_9_16)); - const cropPosition = { + const cropPosition: RegionItem = { x: 0, y: Math.floor((height - cropHeight) / CommonConstants.AVERAGE_WEIGHT_WIDTH) }; diff --git a/Media/ImageEdit/entry/src/main/ets/utils/DecodeUtil.ets b/Media/ImageEdit/entry/src/main/ets/utils/DecodeUtil.ets deleted file mode 100644 index e0d9c2fda453b099159c14879ae12409f05fa092..0000000000000000000000000000000000000000 --- a/Media/ImageEdit/entry/src/main/ets/utils/DecodeUtil.ets +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License,Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import fs from '@ohos.file.fs'; -import image from '@ohos.multimedia.image'; -import Logger from './LoggerUtil'; -import { CommonConstants } from '../common/constant/CommonConstants'; - -const TAG: string = 'imageEdit_Decode'; - -/** - * Async get resource fd. - * - * @return file fd. - */ -async function getResourceFd(filename: string) { - const resourceMgr = getContext(this).resourceManager; - const context = getContext(this); - if (filename === CommonConstants.RAW_FILE_NAME) { - let imageBuffer = await resourceMgr.getMediaContent($r("app.media.ic_low")) - let filePath = context.cacheDir + '/' + filename; - let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); - let writeLen = fs.writeSync(file.fd, imageBuffer.buffer); - fs.copyFileSync(filePath, context.cacheDir + '/' + CommonConstants.RAW_FILE_NAME_TEST); - return file.fd; - } else { - let filePath = context.cacheDir + '/' + filename; - let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); - return file.fd; - } -} - -/** - * Async create pixel map. - * - * @return pixelMa. - */ -export async function getPixelMap(fileName: string) { - const fd = await getResourceFd(fileName); - const imageSourceApi = image.createImageSource(fd); - if (!imageSourceApi) { - Logger.error(TAG, 'imageSourceAPI created failed!'); - return; - } - const pixelMap = await imageSourceApi.createPixelMap({ - editable: true - }); - return pixelMap; -} \ No newline at end of file diff --git a/Media/ImageEdit/entry/src/main/ets/utils/DrawingUtils.ets b/Media/ImageEdit/entry/src/main/ets/utils/DrawingUtils.ets index a4d8b85f60441b234034342f14d598ef553c32bc..9d91768fd727a3ceff7d5451c5aded98c9c0669c 100644 --- a/Media/ImageEdit/entry/src/main/ets/utils/DrawingUtils.ets +++ b/Media/ImageEdit/entry/src/main/ets/utils/DrawingUtils.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { RectF } from '../common/bean/Rect'; +import { RectF } from '../viewmodel/Rect'; import { MathUtils } from './MathUtils'; import { CommonConstants } from '../common/constant/CommonConstants'; @@ -76,7 +76,7 @@ export abstract class DrawingUtils { * @param split * @param isShow */ - static drawSplitLine(ctx: CanvasRenderingContext2D, crop: RectF, split, isShow: boolean) { + static drawSplitLine(ctx: CanvasRenderingContext2D, crop: RectF, split: number, isShow: boolean) { if (!isShow) { return; } diff --git a/Media/ImageEdit/entry/src/main/ets/utils/EncodeUtil.ets b/Media/ImageEdit/entry/src/main/ets/utils/EncodeUtil.ets deleted file mode 100644 index d8e193a2a34960008a7e617750e5e3458893e23e..0000000000000000000000000000000000000000 --- a/Media/ImageEdit/entry/src/main/ets/utils/EncodeUtil.ets +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License,Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import mediaLibrary from '@ohos.multimedia.mediaLibrary'; -import fs from '@ohos.file.fs'; -import image from '@ohos.multimedia.image'; -import Logger from './LoggerUtil'; -import { CommonConstants } from '../common/constant/CommonConstants'; - -const TAG: string = 'imageEdit_Encode'; - -/** - * Pack the image. - * - * @param pixelMap. - */ -export async function encode(pixelMap: PixelMap) { - const newPixelMap = pixelMap; - // Packing image. - const imagePackerApi = image.createImagePacker(); - const packOptions: image.PackingOption = { - format: CommonConstants.ENCODE_FORMAT, - quality: CommonConstants.ENCODE_QUALITY - } - const imageData = await imagePackerApi.packing(newPixelMap, packOptions); - Logger.info(TAG, `imageData's length is ${imageData.byteLength}`); - // Get album's path. - const context = getContext(this); - const media = mediaLibrary.getMediaLibrary(context); - const publicPath = await media.getPublicDirectory(mediaLibrary.DirectoryType.DIR_IMAGE); - const currentTime = new Date().getTime(); - // Create image asset. - const imageAssetInfo = await media.createAsset( - mediaLibrary.MediaType.IMAGE, - `${CommonConstants.IMAGE_PREFIX}_${currentTime}${CommonConstants.IMAGE_FORMAT}`, - publicPath - ); - const imageFd = await imageAssetInfo.open(CommonConstants.ENCODE_FILE_PERMISSION); - await fs.write(imageFd, imageData); - // Image resource release. - await imageAssetInfo.close(imageFd); - imagePackerApi.release(); - await media.release(); -} - - diff --git a/Media/ImageEdit/entry/src/main/ets/utils/MathUtils.ets b/Media/ImageEdit/entry/src/main/ets/utils/MathUtils.ets index 6ae50ca224d2a37aad13be06c1fcbc779d940ac4..7effd10f9696dad57d118596748fec22b4fc4a5d 100644 --- a/Media/ImageEdit/entry/src/main/ets/utils/MathUtils.ets +++ b/Media/ImageEdit/entry/src/main/ets/utils/MathUtils.ets @@ -13,10 +13,10 @@ * limitations under the License. */ -import { LineSegment } from '../common/bean/Line'; -import { Point } from '../common/bean/Point'; -import { RectF } from '../common/bean/Rect'; -import { CropAngle } from '../common/bean/CropType'; +import { LineSegment } from '../viewmodel/Line'; +import { Point } from '../viewmodel/Point'; +import { RectF } from '../viewmodel/Rect'; +import { CropAngle } from '../viewmodel/CropType'; import { CommonConstants } from '../common/constant/CommonConstants'; export abstract class MathUtils { @@ -25,8 +25,7 @@ export abstract class MathUtils { * @param rect */ static roundOutRect(rect: RectF): void { - let copy = { ...rect }; - rect.set(Math.round(copy.left), Math.round(copy.top), Math.round(copy.right), Math.round(copy.bottom)); + rect.set(Math.round(rect.left), Math.round(rect.top), Math.round(rect.right), Math.round(rect.bottom)); } /** @@ -61,7 +60,7 @@ export abstract class MathUtils { * @returns */ static rectToPoints(rect: RectF): Array { - let points = []; + let points: Array = []; points.push(new Point(rect.left, rect.top)); points.push(new Point(rect.right, rect.top)); points.push(new Point(rect.right, rect.bottom)); @@ -93,7 +92,7 @@ export abstract class MathUtils { */ static rotatePoints(inputs: Array, angle: number, origin: Point): Array { let alpha = MathUtils.formulaAngle(-angle); - let outputs = []; + let outputs: Array = []; for (let input of inputs) { let dx = input.x - origin.x; let dy = input.y - origin.y; @@ -136,7 +135,7 @@ export abstract class MathUtils { * @param scale */ static scaleRectBasedOnPoint(rect: RectF, p: Point, scale: number): void { - let operate = { ...rect }; + let operate: RectF = rect; operate.left = (rect.left - p.x) * scale + p.x; operate.right = (rect.right - p.x) * scale + p.x; operate.top = (rect.top - p.y) * scale + p.y; @@ -156,14 +155,14 @@ export abstract class MathUtils { let p3 = line2.start; let p4 = line2.end; if (Math.max(p1.x, p2.x) < Math.min(p3.x, p4.x) || Math.max(p1.y, p2.y) < Math.min(p3.y, p4.y) - || Math.max(p3.x, p4.x) < Math.min(p1.x, p2.x) || Math.max(p3.y, p4.y) < Math.min(p1.y, p2.y)) { + || Math.max(p3.x, p4.x) < Math.min(p1.x, p2.x) || Math.max(p3.y, p4.y) < Math.min(p1.y, p2.y)) { return false; } if ((((p1.x - p3.x) * (p4.y - p3.y) - (p1.y - p3.y) * (p4.x - p3.x)) - * ((p2.x - p3.x) * (p4.y - p3.y) - (p2.y - p3.y) * (p4.x - p3.x))) >= 0 - || (((p3.x - p1.x) * (p2.y - p1.y) - (p3.y - p1.y) * (p2.x - p1.x)) - * ((p4.x - p1.x) * (p2.y - p1.y) - (p4.y - p1.y) * (p2.x - p1.x))) >= 0) { + * ((p2.x - p3.x) * (p4.y - p3.y) - (p2.y - p3.y) * (p4.x - p3.x))) >= 0 + || (((p3.x - p1.x) * (p2.y - p1.y) - (p3.y - p1.y) * (p2.x - p1.x)) + * ((p4.x - p1.x) * (p2.y - p1.y) - (p4.y - p1.y) * (p2.x - p1.x))) >= 0) { return false; } return true; @@ -175,7 +174,7 @@ export abstract class MathUtils { * @param line2 * @returns Intersection coordinates. */ - static getIntersection(line1: LineSegment, line2: LineSegment): Point { + static getIntersection(line1: LineSegment, line2: LineSegment): Point | undefined { let yStartSpacing1 = line1.start.y - line1.end.y; let yEndSpacing1 = line1.end.x - line1.start.x; let resultLine1 = yStartSpacing1 * line1.start.x + yEndSpacing1 * line1.start.y; @@ -385,7 +384,7 @@ export abstract class MathUtils { */ static areRectsSame(rect1: RectF, rect2: RectF): boolean { if (rect1.left == rect2.left && rect1.top == rect2.top - && rect1.right == rect2.right && rect1.bottom == rect2.bottom) { + && rect1.right == rect2.right && rect1.bottom == rect2.bottom) { return true; } return false; diff --git a/Media/ImageEdit/entry/src/main/ets/view/AdjustContentView.ets b/Media/ImageEdit/entry/src/main/ets/view/AdjustContentView.ets index 98372b25fa0a9f7058cc3d1aa2cc2b51db52d15b..b8465304d4afeaee0b4dd977eee719846fa45c4b 100644 --- a/Media/ImageEdit/entry/src/main/ets/view/AdjustContentView.ets +++ b/Media/ImageEdit/entry/src/main/ets/view/AdjustContentView.ets @@ -13,17 +13,18 @@ * limitations under the License. */ -import worker, { MessageEvents} from '@ohos.worker'; +import worker, { MessageEvents } from '@ohos.worker'; import { adjustIconList, IconStatus } from '../viewModel/IconListViewModel'; import { adjustOpacity } from '../utils/OpacityUtil'; import { CommonConstants } from '../common/constant/CommonConstants'; import { AdjustId } from '../viewModel/OptionViewModel'; -import { MessageItem } from '../common/bean/MessageItem' +import { MessageItem } from '../viewmodel/MessageItem' import Logger from '../utils/LoggerUtil'; @Component export default struct AdjustContentView { - @Builder TabBuilder(index: number, name: string | Resource) { + @Builder + TabBuilder(index: number, name: string | Resource) { Column() { Image(this.currentAdjustIndex === index ? this.AdjustIconList[index]?.chosen : this.AdjustIconList[index]?.normal) .width($r('app.float.adjust_icon_width')) @@ -89,7 +90,6 @@ struct SliderCustom { @Consume pixelMap: PixelMap; @Consume isPixelMapChange: boolean; private postState: boolean = true; - workerInstance: worker.ThreadWorker = undefined; saturationLastSlider: number = CommonConstants.SLIDER_MAX; brightnessLastSlider: number = CommonConstants.SLIDER_MAX; deviceListDialogController: CustomDialogController = new CustomDialogController({ @@ -115,7 +115,9 @@ struct SliderCustom { .trackColor(Color.White) .width(CommonConstants.SLIDER_WIDTH) .showSteps(true) - .onChange(this.sliderChange.bind(this)) + .onChange((value: number, mode: SliderChangeMode) => { + this.sliderChange(value, mode); + }) } .width(CommonConstants.LAYOUT_FULL_SCREEN) .justifyContent(FlexAlign.Center) @@ -158,7 +160,9 @@ struct SliderCustom { this.deviceListDialogController.open(); } this.postState = false; - workerInstance.onmessage = this.updatePixelMap.bind(this); + workerInstance.onmessage = (event: MessageEvents) => { + this.updatePixelMap(event) + }; if (type === AdjustId.BRIGHTNESS) { this.brightnessLastSlider = Math.round(value); } else { @@ -171,7 +175,7 @@ struct SliderCustom { } }); } catch (error) { - Logger.error(`Create work instance fail, error message: ${JSON.stringify(error)}`) + Logger.error(`Create work instance fail, error message: ${JSON.stringify(error)}`); } } diff --git a/Media/ImageEdit/entry/src/main/ets/view/ImageSelect.ets b/Media/ImageEdit/entry/src/main/ets/view/ImageSelect.ets index 319650c990ba930ee17f97a0b2a96f20fa2cd740..b5f422dcc3cfc3735db6d7fbcf8d7592ff060faa 100644 --- a/Media/ImageEdit/entry/src/main/ets/view/ImageSelect.ets +++ b/Media/ImageEdit/entry/src/main/ets/view/ImageSelect.ets @@ -15,28 +15,28 @@ import display from '@ohos.display'; import image from '@ohos.multimedia.image'; +import mediaLibrary from '@ohos.multimedia.mediaLibrary'; +import fs from '@ohos.file.fs'; import Logger from '../utils/LoggerUtil'; import { CommonConstants } from '../common/constant/CommonConstants'; -import { ImageSizeItem } from '../common/bean/ImageSizeItem'; +import { ImageSizeItem } from '../viewmodel/ImageSizeItem'; import { ImageEditCrop } from '../viewModel/ImageEditCrop'; -import { PixelMapWrapper } from '../common/bean/PixelMapWrapper'; +import { PixelMapWrapper } from '../viewmodel/PixelMapWrapper'; import Log from '../utils/LoggerUtil'; import { ScreenManager } from '../viewModel/ScreenManager'; -import { CropRatioType } from '../common/bean/CropType'; -import { encode } from '../utils/EncodeUtil'; +import { CropRatioType } from '../viewmodel/CropType'; const TAG = 'ImageSelect'; @Component export struct ImageSelect { - @State cropEdit: ImageEditCrop = undefined; + @State cropEdit: ImageEditCrop | undefined = undefined; @State pinchValue: number = 1; @State isVerticalScreen: boolean = true; - @Consume imageInfo: image.ImageInfo; @Consume imageWidth: number; @Consume imageHeight: number; - @Consume pixelMap: image.PixelMap; + @Consume pixelMap: image.PixelMap | undefined; @Consume showCanvas: boolean; @Consume imageOldSize: ImageSizeItem; @Consume @Watch('listenCrop') isCrop: boolean; @@ -47,20 +47,19 @@ export struct ImageSelect { @Consume resetShow: boolean; @Consume @Watch('listenSave') isSave: boolean; @Consume isSaveFresh: boolean; - private statusBar: number = 0; private titleHeight: number = CommonConstants.TITLE_HEIGHT; private prePinch: number = 0; private settings: RenderingContextSettings = new RenderingContextSettings(true); private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); private stateMenuSize: number = ScreenManager.getInstance().getStatusBarHeight(); - private defaultDisplay: display.Display = undefined; + private defaultDisplay: display.Display = {} as display.Display; listenSave() { - if (this.isSave) { + if (this.isSave && this.cropEdit !== undefined && this.pixelMap !== undefined) { let filter = this.cropEdit.exit(); if (filter === undefined) { - encode(this.pixelMap); + this.encode(this.pixelMap); this.isSaveFresh = !this.isSaveFresh; this.isSave = false; return; @@ -69,8 +68,10 @@ export struct ImageSelect { let temp = this.pixelMap; this.pixelMap = undefined; this.pixelMap = temp; - encode(this.pixelMap); - this.cropEdit.setCanvasContext(this.context); + this.encode(this.pixelMap); + if (this.cropEdit !== undefined) { + this.cropEdit.setCanvasContext(this.context); + } this.updateImageInfo(); this.isSaveFresh = !this.isSaveFresh; }); @@ -88,8 +89,10 @@ export struct ImageSelect { .width(CommonConstants.LAYOUT_FULL_SCREEN) .height(CommonConstants.LAYOUT_FULL_SCREEN) .onReady(() => { - this.cropEdit.setCanvasReady(true); - this.cropEdit.setCanvasContext(this.context); + if (this.cropEdit !== undefined) { + this.cropEdit.setCanvasReady(true); + this.cropEdit.setCanvasContext(this.context); + } }) } .width(CommonConstants.LAYOUT_FULL_SCREEN) @@ -112,7 +115,7 @@ export struct ImageSelect { } async listenCrop() { - if (!this.isCrop) { + if (!this.isCrop && this.cropEdit !== undefined && this.pixelMap !== undefined) { let filter = this.cropEdit.exit(); if (filter === undefined) { return; @@ -127,29 +130,33 @@ export struct ImageSelect { } updateImageInfo() { - this.pixelMap.getImageInfo().then((imageInfo) => { - this.imageInfo = imageInfo; - this.imageWidth = px2vp(this.imageInfo.size.width); - this.imageHeight = px2vp(this.imageInfo.size.height); - this.imageOldSize = { - width: this.imageWidth, - height: this.imageHeight - }; - this.showCanvas = true; - this.calcScale(); - Logger.info('update image width height: ' + this.imageWidth + " " + this.imageHeight); - }); + if (this.pixelMap !== undefined) { + this.pixelMap.getImageInfo().then((imageInfo) => { + this.imageInfo = imageInfo; + this.imageWidth = px2vp(this.imageInfo.size.width); + this.imageHeight = px2vp(this.imageInfo.size.height); + this.imageOldSize = { + width: this.imageWidth, + height: this.imageHeight + }; + this.showCanvas = true; + this.calcScale(); + Logger.info('update image width height: ' + this.imageWidth + " " + this.imageHeight); + }); + } } listenRatio() { - this.cropEdit.onFixedRatioChange(this.cropRatio); + if (this.cropEdit !== undefined) { + this.cropEdit.onFixedRatioChange(this.cropRatio); + } } calcScale() { let imageWidthScale = (this.screenWidth - CommonConstants.DOUBLE * CommonConstants.SCREEN_DISPLAY_MARGIN) / - this.imageOldSize.width; + this.imageOldSize.width; let imageHeightScale = (this.screenHeight - CommonConstants.DOUBLE * CommonConstants.SCREEN_DISPLAY_MARGIN) / - this.imageOldSize.height; + this.imageOldSize.height; this.imageScale = imageWidthScale > imageHeightScale ? imageHeightScale : imageWidthScale; } @@ -157,11 +164,12 @@ export struct ImageSelect { try { this.defaultDisplay = display.getDefaultDisplaySync(); this.screenWidth = px2vp(this.defaultDisplay.width); - this.screenHeight = px2vp((this.defaultDisplay.height - this.statusBar * 2) * - CommonConstants.EDIT_SCREEN_USAGE); + this.screenHeight = px2vp((this.defaultDisplay.height - this.statusBar * 2) * CommonConstants.EDIT_SCREEN_USAGE); this.calcScale(); this.cropEdit = new ImageEditCrop(); - this.cropEdit.entry(new PixelMapWrapper(this.pixelMap, this.imageOldSize.width, this.imageOldSize.height)); + if (this.pixelMap !== undefined) { + this.cropEdit.entry(new PixelMapWrapper(this.pixelMap, this.imageOldSize.width, this.imageOldSize.height)); + } this.cropEdit.setCanvasSize(this.screenWidth, this.screenHeight); } catch (exception) { Logger.error(`Failed to obtain the default display object. Code: ${JSON.stringify(this.defaultDisplay)}`); @@ -169,16 +177,18 @@ export struct ImageSelect { } onTouchStart(event: TouchEvent): void { - let x = event.touches[0].x; - let y = event.touches[0].y; - if (event.type === TouchType.Down) { - this.cropEdit.onTouchStart(x, y); - } else if (event.type === TouchType.Move) { - this.cropEdit.onTouchMove(x, y); - } else if (event.type === TouchType.Up || event.type === TouchType.Cancel) { - this.cropEdit.onTouchEnd(); - } else { - Logger.info('touch other event'); + if (this.cropEdit !== undefined) { + let x = event.touches[0].x; + let y = event.touches[0].y; + if (event.type === TouchType.Down) { + this.cropEdit.onTouchStart(x, y); + } else if (event.type === TouchType.Move) { + this.cropEdit.onTouchMove(x, y); + } else if (event.type === TouchType.Up || event.type === TouchType.Cancel) { + this.cropEdit.onTouchEnd(); + } else { + Logger.info('touch other event'); + } } } @@ -194,19 +204,58 @@ export struct ImageSelect { x = event.pinchCenterX - CommonConstants.TOOL_BAR_SIZE; y = event.pinchCenterY - CommonConstants.TOP_BAR_SIZE - this.stateMenuSize; } - this.cropEdit.onPinchStart(x, y, event.scale); + if (this.cropEdit !== undefined) { + this.cropEdit.onPinchStart(x, y, event.scale); + } } onPinchGestureUpdate(event: GestureEvent): void { let now = new Date().getTime(); if (now - this.prePinch >= CommonConstants.TIMEOUT) { this.prePinch = now; - this.cropEdit.onPinchUpdate(event.scale); + if (this.cropEdit !== undefined) { + this.cropEdit.onPinchUpdate(event.scale); + } } } onPinchGestureEnd(): void { Log.debug(TAG, 'cropMode onPinchGestureEnd called'); - this.cropEdit.onPinchEnd(); + if (this.cropEdit !== undefined) { + this.cropEdit.onPinchEnd(); + } + } + + async encode(pixelMap: PixelMap | undefined) { + if (pixelMap === undefined) { + return; + } + + const newPixelMap = pixelMap; + // Packing image. + const imagePackerApi = image.createImagePacker(); + const packOptions: image.PackingOption = { + format: CommonConstants.ENCODE_FORMAT, + quality: CommonConstants.ENCODE_QUALITY + } + const imageData = await imagePackerApi.packing(newPixelMap, packOptions); + Logger.info(TAG, `imageData's length is ${imageData.byteLength}`); + // Get album's path. + const context = getContext(this); + const media = mediaLibrary.getMediaLibrary(context); + const publicPath = await media.getPublicDirectory(mediaLibrary.DirectoryType.DIR_IMAGE); + const currentTime = new Date().getTime(); + // Create image asset. + const imageAssetInfo = await media.createAsset( + mediaLibrary.MediaType.IMAGE, + `${CommonConstants.IMAGE_PREFIX}_${currentTime}${CommonConstants.IMAGE_FORMAT}`, + publicPath + ); + const imageFd = await imageAssetInfo.open(CommonConstants.ENCODE_FILE_PERMISSION); + await fs.write(imageFd, imageData); + // Image resource release. + await imageAssetInfo.close(imageFd); + imagePackerApi.release(); + await media.release(); } } \ No newline at end of file diff --git a/Media/ImageEdit/entry/src/main/ets/viewModel/CropShow.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/CropShow.ets index 8486a1cd4f372b036270b43c9303097a9a058ebb..aecbe5ccd4c8eeb8e3a113ddb20ba783ef13fde2 100644 --- a/Media/ImageEdit/entry/src/main/ets/viewModel/CropShow.ets +++ b/Media/ImageEdit/entry/src/main/ets/viewModel/CropShow.ets @@ -13,11 +13,11 @@ * limitations under the License. */ -import { LineSegment } from '../common/bean/Line'; -import { Point } from '../common/bean/Point'; -import { RectF } from '../common/bean/Rect'; -import { Ratio } from '../common/bean/Ratio'; -import { CropAngle, CropRatioType } from '../common/bean/CropType'; +import { LineSegment } from './Line'; +import { Point } from './Point'; +import { RectF } from './Rect'; +import { Ratio } from './Ratio'; +import { CropAngle, CropRatioType } from './CropType'; import { MathUtils } from '../utils/MathUtils'; import Log from '../utils/LoggerUtil'; import { ScreenManager } from './ScreenManager'; @@ -26,10 +26,10 @@ import { CommonConstants } from '../common/constant/CommonConstants'; const TAG: string = 'editor_CropShow'; export class CropShow { - private limitRect: RectF = undefined; - private cropRect: RectF = undefined; - private imageRect: RectF = undefined; - private ratio: Ratio = undefined; + private limitRect: RectF; + private cropRect: RectF; + private imageRect: RectF; + private ratio: Ratio; private screenMaxSide: number = 0; private screenMinSide: number = 0; private minSideLength: number = CommonConstants.DEFAULT_MIN_SIDE_LENGTH; @@ -278,7 +278,7 @@ export class CropShow { isCropRectTouch(x: number, y: number): boolean { let w = this.touchBound; let h = this.touchBound; - let crop = { ...this.cropRect }; + let crop = this.cropRect; let outer = new RectF(); outer.set(crop.left - w, crop.top - h, crop.right + w, crop.bottom + h); let inner = new RectF(); @@ -311,7 +311,7 @@ export class CropShow { */ getCurrentFlipImage(): RectF { let center = this.getDisplayCenter(); - let image = { ...this.imageRect }; + let image = this.imageRect; let flipImage = new RectF(); flipImage.left = this.isFlipHorizontal ? (2 * center.x - image.right) : image.left; flipImage.top = this.isFlipVertically ? (2 * center.y - image.bottom) : image.top; @@ -433,7 +433,7 @@ export class CropShow { let angle = this.rotationAngle * tX * tY + this.horizontalAngle; let rotated = MathUtils.rotatePoints(imagePoints, angle, origin); - let imageLines = []; + let imageLines: LineSegment[] = []; for (let i = 0; i < rotated.length; i++) { let j = (i + 1) % rotated.length; imageLines.push( @@ -494,7 +494,7 @@ export class CropShow { let rate = this.ratio.getRate(); let rect = new RectF(); if (isEnlarge) { - let limit = { ...this.limitRect }; + let limit = this.limitRect; let size = MathUtils.getMaxFixedRectSize(rate, crop.right - limit.left, crop.bottom - limit.top); rect.set(crop.right - size[0], crop.bottom - size[1], crop.right, crop.bottom); let imageLines = this.getCurrentImageLines(); @@ -524,7 +524,7 @@ export class CropShow { let rate = this.ratio.getRate(); let rect = new RectF(); if (isEnlarge) { - let limit = { ...this.limitRect }; + let limit = this.limitRect; let size = MathUtils.getMaxFixedRectSize(rate, crop.right - limit.left, limit.bottom - crop.top); rect.set(crop.right - size[0], crop.top, crop.right, crop.top + size[1]); let imageLines = this.getCurrentImageLines(); @@ -554,7 +554,7 @@ export class CropShow { let rate = this.ratio.getRate(); let rect = new RectF(); if (isEnlarge) { - let limit = { ...this.limitRect }; + let limit = this.limitRect; let size = MathUtils.getMaxFixedRectSize(rate, limit.right - crop.left, crop.bottom - limit.top); rect.set(crop.left, crop.bottom - size[1], crop.left + size[0], crop.bottom); let imageLines = this.getCurrentImageLines(); @@ -584,7 +584,7 @@ export class CropShow { let rate = this.ratio.getRate(); let rect = new RectF(); if (isEnlarge) { - let limit = { ...this.limitRect }; + let limit = this.limitRect; let size = MathUtils.getMaxFixedRectSize(rate, limit.right - crop.left, limit.bottom - crop.top); rect.set(crop.left, crop.top, crop.left + size[0], crop.top + size[1]); let imageLines = this.getCurrentImageLines(); @@ -611,7 +611,7 @@ export class CropShow { */ private moveInFreeMode(offsetX: number, offsetY: number) { let crop = this.getCropRect(); - let limit = { ...this.limitRect }; + let limit = this.limitRect; let image = this.getCurrentRotatedImage(); let minLength = this.minSideLength; let imageLines = this.getCurrentImageLines(); @@ -654,7 +654,7 @@ export class CropShow { */ private fixLeftInFreeMode(left: number, crop: RectF, imageLines: Array): number { let leftLine = new LineSegment(new Point(left, crop.top), new Point(left, crop.bottom)); - let adjacentLines = []; + let adjacentLines: LineSegment[] = []; adjacentLines.push(new LineSegment(new Point(left, crop.top), new Point(crop.right, crop.top))); adjacentLines.push(new LineSegment(new Point(left, crop.bottom), new Point(crop.right, crop.bottom))); let fixedLeft = left; @@ -676,7 +676,7 @@ export class CropShow { */ private fixRightInFreeMode(right: number, crop: RectF, imageLines: Array): number { let rightLine = new LineSegment(new Point(right, crop.top), new Point(right, crop.bottom)); - let adjacentLines = []; + let adjacentLines: LineSegment[] = []; adjacentLines.push(new LineSegment(new Point(crop.left, crop.top), new Point(right, crop.top))); adjacentLines.push(new LineSegment(new Point(crop.left, crop.bottom), new Point(right, crop.bottom))); let fixedRight = right; @@ -698,7 +698,7 @@ export class CropShow { */ private fixTopInFreeMode(top: number, crop: RectF, imageLines: Array): number { let topLine = new LineSegment(new Point(crop.left, top), new Point(crop.right, top)); - let adjacentLines = []; + let adjacentLines: LineSegment[] = []; adjacentLines.push(new LineSegment(new Point(crop.left, top), new Point(crop.left, crop.bottom))); adjacentLines.push(new LineSegment(new Point(crop.right, top), new Point(crop.right, crop.bottom))); let fixedTop = top; @@ -720,7 +720,7 @@ export class CropShow { */ private fixBottomInFreeMode(bottom: number, crop: RectF, imageLines: Array): number { let bottomLine = new LineSegment(new Point(crop.left, bottom), new Point(crop.right, bottom)); - let adjacentLines = []; + let adjacentLines: LineSegment[] = []; adjacentLines.push(new LineSegment(new Point(crop.left, crop.top), new Point(crop.left, bottom))); adjacentLines.push(new LineSegment(new Point(crop.right, crop.top), new Point(crop.right, bottom))); let fixedBottom = bottom; diff --git a/Media/ImageEdit/entry/src/main/ets/common/bean/CropType.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/CropType.ets similarity index 100% rename from Media/ImageEdit/entry/src/main/ets/common/bean/CropType.ets rename to Media/ImageEdit/entry/src/main/ets/viewModel/CropType.ets diff --git a/Media/ImageEdit/entry/src/main/ets/viewModel/ImageEditCrop.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/ImageEditCrop.ets index 9dec4f449a09e799c8a17744de35258eec8abb70..37c98af9ab9fcfe3774acedfde5411671340ee74 100644 --- a/Media/ImageEdit/entry/src/main/ets/viewModel/ImageEditCrop.ets +++ b/Media/ImageEdit/entry/src/main/ets/viewModel/ImageEditCrop.ets @@ -13,30 +13,30 @@ * limitations under the License. */ -import { Point } from '../common/bean/Point'; -import { RectF } from '../common/bean/Rect'; -import { CropAngle, CropRatioType, CropTouchState } from '../common/bean/CropType'; +import { Point } from './Point'; +import { RectF } from './Rect'; +import { CropAngle, CropRatioType, CropTouchState } from './CropType'; import { ImageFilterCrop } from './ImageFilterCrop'; import { CropShow } from './CropShow'; import { MathUtils } from '../utils/MathUtils'; import { DrawingUtils } from '../utils/DrawingUtils'; -import type { PixelMapWrapper } from '../common/bean/PixelMapWrapper'; +import { PixelMapWrapper } from './PixelMapWrapper'; import Logger from '../utils/LoggerUtil'; import { CommonConstants } from '../common/constant/CommonConstants'; const TAG: string = 'editor_ImageEditCrop'; export class ImageEditCrop { - private filter: ImageFilterCrop = undefined; - private input: PixelMapWrapper = undefined; + private filter: ImageFilterCrop | undefined = undefined; + private input: PixelMapWrapper | undefined = undefined; private isFlipHorizontal: boolean = false; private isFlipVertically: boolean = false; private rotationAngle: number = 0; private sliderAngle: number = 0; private cropRatio: CropRatioType = CropRatioType.RATIO_TYPE_FREE; - private cropShow: CropShow = undefined; + private cropShow: CropShow; private isCropShowInitialized: boolean = false; - private ctx: CanvasRenderingContext2D = undefined; + private ctx: CanvasRenderingContext2D | undefined = undefined; private displayWidth: number = 0; private displayHeight: number = 0; private marginW: number = CommonConstants.DEFAULT_MARGIN_LENGTH; @@ -46,8 +46,8 @@ export class ImageEditCrop { private timeoutId: number = 0; private timeout: number = CommonConstants.DEFAULT_TIMEOUT_MILLISECOND_1000; private isWaitingRefresh: boolean = false; - private touchPoint: Point = undefined; - private pinchPoint: Point = undefined; + private touchPoint: Point; + private pinchPoint: Point; private state: CropTouchState = CropTouchState.NONE; private splitFraction: number = CommonConstants.DEFAULT_SPLIT_FRACTION; private canvasReady: boolean = false; @@ -79,7 +79,7 @@ export class ImageEditCrop { * Image edit model exit. * @returns */ - exit(): ImageFilterCrop { + exit(): ImageFilterCrop | undefined { Logger.info(TAG, 'exit'); this.saveFinalOperation(); this.isCropShowInitialized = false; @@ -134,7 +134,9 @@ export class ImageEditCrop { * Clear canvas content. */ clearCanvas(): void { - this.ctx.clearRect(0, 0, this.displayWidth, this.displayHeight); + if (this.ctx !== undefined) { + this.ctx.clearRect(0, 0, this.displayWidth, this.displayHeight); + } } /** @@ -345,10 +347,10 @@ export class ImageEditCrop { MathUtils.roundOutRect(image); if ( this.isFlipHorizontal !== false || - this.isFlipVertically !== false || - this.rotationAngle !== 0 || this.sliderAngle !== 0 || - this.cropRatio !== CropRatioType.RATIO_TYPE_FREE || - !MathUtils.areRectsSame(crop, image) + this.isFlipVertically !== false || + this.rotationAngle !== 0 || this.sliderAngle !== 0 || + this.cropRatio !== CropRatioType.RATIO_TYPE_FREE || + !MathUtils.areRectsSame(crop, image) ) { return true; } @@ -370,7 +372,9 @@ export class ImageEditCrop { * Init and clear old content. */ private initialize(): void { - this.imageRatio = this.input.width / this.input.height; + if (this.input !== undefined) { + this.imageRatio = this.input.width / this.input.height; + } this.determineMaxScaleFactor(); this.clear(); } @@ -389,7 +393,7 @@ export class ImageEditCrop { * Calc max scale factor. */ private determineMaxScaleFactor(): void { - if (this.input == null) { + if (this.input == undefined) { return; } let scaleFactorW = this.input.width / px2vp(CommonConstants.DEFAULT_MIN_SIDE_LENGTH_EDIT); @@ -405,7 +409,9 @@ export class ImageEditCrop { let image = this.cropShow.getImageRect(); crop.move(-image.left, -image.top); MathUtils.normalizeRect(crop, image.getWidth(), image.getHeight()); - this.filter.setCropRect(crop); + if (this.filter !== undefined) { + this.filter.setCropRect(crop); + } } /** @@ -455,25 +461,29 @@ export class ImageEditCrop { * Draw image. */ private drawImage(): void { - this.ctx.save(); - this.clearCanvas(); + if (this.ctx !== undefined) { + this.ctx.save(); + this.clearCanvas(); - let x = this.displayWidth / 2; - let y = this.displayHeight / 2; - this.ctx.translate(this.isFlipHorizontal ? 2 * x : 0, this.isFlipVertically ? 2 * y : 0); + let x = this.displayWidth / 2; + let y = this.displayHeight / 2; + this.ctx.translate(this.isFlipHorizontal ? 2 * x : 0, this.isFlipVertically ? 2 * y : 0); - let tX = this.isFlipHorizontal ? -1 : 1; - let tY = this.isFlipVertically ? -1 : 1; - this.ctx.scale(tX, tY); + let tX = this.isFlipHorizontal ? -1 : 1; + let tY = this.isFlipVertically ? -1 : 1; + this.ctx.scale(tX, tY); - this.ctx.translate(x, y); - this.ctx.rotate(MathUtils.formulaAngle(this.rotationAngle * tX * tY + this.sliderAngle)); - this.ctx.translate(-x, -y); + this.ctx.translate(x, y); + this.ctx.rotate(MathUtils.formulaAngle(this.rotationAngle * tX * tY + this.sliderAngle)); + this.ctx.translate(-x, -y); - let image = this.cropShow.getImageRect(); - MathUtils.roundOutRect(image); - this.ctx.drawImage(this.input.pixelMap, image.left, image.top, image.getWidth(), image.getHeight()); - this.ctx.restore(); + let image = this.cropShow.getImageRect(); + MathUtils.roundOutRect(image); + if (this.input !== undefined) { + this.ctx.drawImage(this.input.pixelMap, image.left, image.top, image.getWidth(), image.getHeight()); + } + this.ctx.restore(); + } } /** @@ -484,12 +494,14 @@ export class ImageEditCrop { MathUtils.roundOutRect(crop); let display = new RectF(); display.set(0, 0, this.displayWidth, this.displayHeight); - DrawingUtils.drawMask(this.ctx, display, crop, this.splitLineShow); - if (this.splitLineShow) { - DrawingUtils.drawSplitLine(this.ctx, crop, this.splitFraction, this.splitLineShow); + if (this.ctx !== undefined) { + DrawingUtils.drawMask(this.ctx, display, crop, this.splitLineShow); + if (this.splitLineShow) { + DrawingUtils.drawSplitLine(this.ctx, crop, this.splitFraction, this.splitLineShow); + } + DrawingUtils.drawRect(this.ctx, crop); + DrawingUtils.drawCropButton(this.ctx, crop); } - DrawingUtils.drawRect(this.ctx, crop); - DrawingUtils.drawCropButton(this.ctx, crop); } /** diff --git a/Media/ImageEdit/entry/src/main/ets/viewModel/ImageFilterCrop.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/ImageFilterCrop.ets index 8d8ee4abd1a65afa01fc46ebd0fc1e9bd77270dc..ebb40d0be24c6389579a1ca9a1b93302d22f4818 100644 --- a/Media/ImageEdit/entry/src/main/ets/viewModel/ImageFilterCrop.ets +++ b/Media/ImageEdit/entry/src/main/ets/viewModel/ImageFilterCrop.ets @@ -13,28 +13,26 @@ * limitations under the License. */ -import { RectF } from '../common/bean/Rect'; -import { PixelMapWrapper } from '../common/bean/PixelMapWrapper'; +import { RectF } from './Rect'; +import { PixelMapWrapper } from './PixelMapWrapper'; import { MathUtils } from '../utils/MathUtils'; export class ImageFilterCrop { - private cropRect: RectF = undefined; + private cropRect: RectF = new RectF(); - constructor() { - this.cropRect = new RectF(); - } - - cropImage(pixelMap: PixelMapWrapper, realCropRect: RectF, callback) { + cropImage(pixelMap: PixelMapWrapper, realCropRect: RectF, callback: () => void) { let offWidth = realCropRect.getWidth(); let offHeight = realCropRect.getHeight(); - pixelMap.pixelMap.crop({ - size:{ height: vp2px(offHeight), width: vp2px(offWidth) }, - x: vp2px(realCropRect.left), - y: vp2px(realCropRect.top) - }, callback); + if (pixelMap.pixelMap!== undefined) { + pixelMap.pixelMap.crop({ + size: { height: vp2px(offHeight), width: vp2px(offWidth) }, + x: vp2px(realCropRect.left), + y: vp2px(realCropRect.top) + }, callback); + } } - readerNew(pixelMap: PixelMapWrapper, callback) { + readerNew(pixelMap: PixelMapWrapper, callback: () => void) { let width = pixelMap.width; let height = pixelMap.height; let realCropRect = new RectF(); diff --git a/Media/ImageEdit/entry/src/main/ets/common/bean/ImageSizeItem.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/ImageSizeItem.ets similarity index 100% rename from Media/ImageEdit/entry/src/main/ets/common/bean/ImageSizeItem.ets rename to Media/ImageEdit/entry/src/main/ets/viewModel/ImageSizeItem.ets diff --git a/Media/ImageEdit/entry/src/main/ets/common/bean/Line.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/Line.ets similarity index 100% rename from Media/ImageEdit/entry/src/main/ets/common/bean/Line.ets rename to Media/ImageEdit/entry/src/main/ets/viewModel/Line.ets diff --git a/Media/ImageEdit/entry/src/main/ets/common/bean/MessageItem.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/MessageItem.ets similarity index 93% rename from Media/ImageEdit/entry/src/main/ets/common/bean/MessageItem.ets rename to Media/ImageEdit/entry/src/main/ets/viewModel/MessageItem.ets index b18f3783c412c10a2fc536f0d83c2c8f10203d68..d5d30e7d553f3972c176e1850cef75806b6ffc24 100644 --- a/Media/ImageEdit/entry/src/main/ets/common/bean/MessageItem.ets +++ b/Media/ImageEdit/entry/src/main/ets/viewModel/MessageItem.ets @@ -17,7 +17,7 @@ * Multithreading transmission message. */ export class MessageItem { - constructor(buf, last, cur) { + constructor(buf: ArrayBuffer, last: number, cur: number) { this.buf = buf; this.last = last; this.cur = cur; diff --git a/Media/ImageEdit/entry/src/main/ets/common/bean/PixelMapWrapper.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/PixelMapWrapper.ets similarity index 90% rename from Media/ImageEdit/entry/src/main/ets/common/bean/PixelMapWrapper.ets rename to Media/ImageEdit/entry/src/main/ets/viewModel/PixelMapWrapper.ets index 9f22195519aa16f1b3081d581a56a5a42adb1231..71f3760c6e1d4fb88732c632da8f452a78ef5910 100644 --- a/Media/ImageEdit/entry/src/main/ets/common/bean/PixelMapWrapper.ets +++ b/Media/ImageEdit/entry/src/main/ets/viewModel/PixelMapWrapper.ets @@ -15,7 +15,7 @@ export class PixelMapWrapper { - pixelMap: PixelMap = undefined; + pixelMap?: PixelMap; width: number = 0; height: number = 0; @@ -26,7 +26,7 @@ export class PixelMapWrapper { } release() { - if (this.pixelMap != null && this.pixelMap != undefined) { + if (this.pixelMap != undefined) { this.pixelMap.release(); } this.width = 0; diff --git a/Media/ImageEdit/entry/src/main/ets/common/bean/Point.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/Point.ets similarity index 100% rename from Media/ImageEdit/entry/src/main/ets/common/bean/Point.ets rename to Media/ImageEdit/entry/src/main/ets/viewModel/Point.ets diff --git a/Media/ImageEdit/entry/src/main/ets/common/bean/Ratio.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/Ratio.ets similarity index 100% rename from Media/ImageEdit/entry/src/main/ets/common/bean/Ratio.ets rename to Media/ImageEdit/entry/src/main/ets/viewModel/Ratio.ets diff --git a/Media/ImageEdit/entry/src/main/ets/common/bean/Rect.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/Rect.ets similarity index 100% rename from Media/ImageEdit/entry/src/main/ets/common/bean/Rect.ets rename to Media/ImageEdit/entry/src/main/ets/viewModel/Rect.ets diff --git a/Media/ImageEdit/entry/src/main/ets/common/bean/RegionItem.ets b/Media/ImageEdit/entry/src/main/ets/viewModel/RegionItem.ets similarity index 100% rename from Media/ImageEdit/entry/src/main/ets/common/bean/RegionItem.ets rename to Media/ImageEdit/entry/src/main/ets/viewModel/RegionItem.ets diff --git a/Media/ImageEdit/entry/src/main/ets/workers/AdjustBrightnessWork.ts b/Media/ImageEdit/entry/src/main/ets/workers/AdjustBrightnessWork.ts index 0df731694cc2d402c907760fd87bb69d2bdc4be9..8f5b94b6d2bc470840e38b98d40cdf0d77182217 100644 --- a/Media/ImageEdit/entry/src/main/ets/workers/AdjustBrightnessWork.ts +++ b/Media/ImageEdit/entry/src/main/ets/workers/AdjustBrightnessWork.ts @@ -17,39 +17,39 @@ import hilog from '@ohos.hilog'; import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker'; import { adjustImageValue } from '../utils/AdjustUtil'; -let workerPort : ThreadWorkerGlobalScope = worker.workerPort; +let workerPort: ThreadWorkerGlobalScope = worker.workerPort; /** -* Defines the event handler to be called when the worker thread receives a message sent by the host thread. -* The event handler is executed in the worker thread. -* -* @param e message data -*/ -workerPort.onmessage = function(event : MessageEvents) { - let bufferArray = event.data.buf; - let last = event.data.last; - let cur = event.data.cur; - let buffer = adjustImageValue(bufferArray, last, cur) - workerPort.postMessage(buffer); - workerPort.close(); + * Defines the event handler to be called when the worker thread receives a message sent by the host thread. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessage = function (event: MessageEvents) { + let bufferArray = event.data.buf; + let last = event.data.last; + let cur = event.data.cur; + let buffer = adjustImageValue(bufferArray, last, cur) + workerPort.postMessage(buffer); + workerPort.close(); } /** -* Defines the event handler to be called when the worker receives a message that cannot be deserialized. -* The event handler is executed in the worker thread. -* -* @param e message data -*/ -workerPort.onmessageerror = function(event : MessageEvents) { - hilog.error(0x0000, 'AdjustBrightnessWork', 'Failed to load the content. Cause: %{public}s', `on message error ${JSON.stringify(event)}`); + * Defines the event handler to be called when the worker receives a message that cannot be deserialized. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessageerror = function (event: MessageEvents) { + hilog.error(0x0000, 'AdjustBrightnessWork', 'Failed to load the content. Cause: %{public}s', `on message error ${JSON.stringify(event)}`); } /** -* Defines the event handler to be called when an exception occurs during worker execution. -* The event handler is executed in the worker thread. -* -* @param e error message -*/ -workerPort.onerror = function(error : ErrorEvent) { - hilog.error(0x0000, 'AdjustBrightnessWork', 'Failed to load the content. Cause: %{public}s', `on worker error ${JSON.stringify(error)}`); + * Defines the event handler to be called when an exception occurs during worker execution. + * The event handler is executed in the worker thread. + * + * @param e error message + */ +workerPort.onerror = function (error: ErrorEvent) { + hilog.error(0x0000, 'AdjustBrightnessWork', 'Failed to load the content. Cause: %{public}s', `on worker error ${JSON.stringify(error)}`); } \ No newline at end of file diff --git a/Media/ImageEdit/entry/src/main/ets/workers/AdjustSaturationWork.ts b/Media/ImageEdit/entry/src/main/ets/workers/AdjustSaturationWork.ts index 2e1a884b1b89a2d4adf9bffedacdaee7a8038393..310fd1db94c00227dc8e353b574bc372f28f654d 100644 --- a/Media/ImageEdit/entry/src/main/ets/workers/AdjustSaturationWork.ts +++ b/Media/ImageEdit/entry/src/main/ets/workers/AdjustSaturationWork.ts @@ -17,39 +17,39 @@ import hilog from '@ohos.hilog'; import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker'; import { adjustSaturation } from '../utils/AdjustUtil'; -let workerPort : ThreadWorkerGlobalScope = worker.workerPort; +let workerPort: ThreadWorkerGlobalScope = worker.workerPort; /** -* Defines the event handler to be called when the worker thread receives a message sent by the host thread. -* The event handler is executed in the worker thread. -* -* @param e message data -*/ -workerPort.onmessage = function(event : MessageEvents) { - let bufferArray = event.data.buf; - let last = event.data.last; - let cur = event.data.cur; - let buffer = adjustSaturation(bufferArray, last, cur) - workerPort.postMessage(buffer); - workerPort.close(); + * Defines the event handler to be called when the worker thread receives a message sent by the host thread. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessage = function (event: MessageEvents) { + let bufferArray = event.data.buf; + let last = event.data.last; + let cur = event.data.cur; + let buffer = adjustSaturation(bufferArray, last, cur) + workerPort.postMessage(buffer); + workerPort.close(); } /** -* Defines the event handler to be called when the worker receives a message that cannot be deserialized. -* The event handler is executed in the worker thread. -* -* @param e message data -*/ -workerPort.onmessageerror = function(event : MessageEvents) { - hilog.error(0x0000, 'AdjustSaturationWork', 'Failed to load the content. Cause: %{public}s', `on message error ${JSON.stringify(event)}`); + * Defines the event handler to be called when the worker receives a message that cannot be deserialized. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessageerror = function (event: MessageEvents) { + hilog.error(0x0000, 'AdjustSaturationWork', 'Failed to load the content. Cause: %{public}s', `on message error ${JSON.stringify(event)}`); } /** -* Defines the event handler to be called when an exception occurs during worker execution. -* The event handler is executed in the worker thread. -* -* @param e error message -*/ -workerPort.onerror = function(error : ErrorEvent) { - hilog.error(0x0000, 'AdjustSaturationWork', 'Failed to load the content. Cause: %{public}s', `on worker error ${JSON.stringify(error)}`); + * Defines the event handler to be called when an exception occurs during worker execution. + * The event handler is executed in the worker thread. + * + * @param e error message + */ +workerPort.onerror = function (error: ErrorEvent) { + hilog.error(0x0000, 'AdjustSaturationWork', 'Failed to load the content. Cause: %{public}s', `on worker error ${JSON.stringify(error)}`); } \ No newline at end of file diff --git a/Media/ImageEdit/hvigor/hvigor-config.json5 b/Media/ImageEdit/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/Media/ImageEdit/hvigor/hvigor-config.json5 +++ b/Media/ImageEdit/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/Media/ImageEdit/oh-package.json5 b/Media/ImageEdit/oh-package.json5 index 7e61fa36adfc7651f7fb011ee866bb303bde3160..4136be00e745b56fe17e3976db1f92921cf89f07 100644 --- a/Media/ImageEdit/oh-package.json5 +++ b/Media/ImageEdit/oh-package.json5 @@ -9,4 +9,4 @@ "main": "", "version": "1.0.0", "dependencies": {} -} +} \ No newline at end of file diff --git a/Media/ImageEdit/public_sys-resources/icon-caution.gif b/Media/ImageEdit/public_sys-resources/icon-caution.gif deleted file mode 100644 index 81fb2aba954177efa588e675927082b1f6bed41f..0000000000000000000000000000000000000000 Binary files a/Media/ImageEdit/public_sys-resources/icon-caution.gif and /dev/null differ diff --git a/Media/ImageEdit/public_sys-resources/icon-danger.gif b/Media/ImageEdit/public_sys-resources/icon-danger.gif deleted file mode 100644 index 81fb2aba954177efa588e675927082b1f6bed41f..0000000000000000000000000000000000000000 Binary files a/Media/ImageEdit/public_sys-resources/icon-danger.gif and /dev/null differ diff --git a/Media/ImageEdit/public_sys-resources/icon-note.gif b/Media/ImageEdit/public_sys-resources/icon-note.gif deleted file mode 100644 index db3995e34b6644fc11c916ffe69c7cb5512610d8..0000000000000000000000000000000000000000 Binary files a/Media/ImageEdit/public_sys-resources/icon-note.gif and /dev/null differ diff --git a/Media/ImageEdit/public_sys-resources/icon-notice.gif b/Media/ImageEdit/public_sys-resources/icon-notice.gif deleted file mode 100644 index 75397a3efc5c345922fd37f551d7d28675ab6c5f..0000000000000000000000000000000000000000 Binary files a/Media/ImageEdit/public_sys-resources/icon-notice.gif and /dev/null differ diff --git a/Media/ImageEdit/public_sys-resources/icon-tip.gif b/Media/ImageEdit/public_sys-resources/icon-tip.gif deleted file mode 100644 index 110cd67cefa9f6b2800a2b8076a7a0dcc00b783c..0000000000000000000000000000000000000000 Binary files a/Media/ImageEdit/public_sys-resources/icon-tip.gif and /dev/null differ diff --git a/Media/ImageEdit/public_sys-resources/icon-warning.gif b/Media/ImageEdit/public_sys-resources/icon-warning.gif deleted file mode 100644 index 81fb2aba954177efa588e675927082b1f6bed41f..0000000000000000000000000000000000000000 Binary files a/Media/ImageEdit/public_sys-resources/icon-warning.gif and /dev/null differ diff --git a/Media/SimpleVideo/README.md b/Media/SimpleVideo/README.md index d0b571541e4ef32e4c7090ce113a2d8e4ef5ad7e..dbcbbf9ba51f67ff4216b9b40caa838410342227 100644 --- a/Media/SimpleVideo/README.md +++ b/Media/SimpleVideo/README.md @@ -16,23 +16,23 @@ ### 相关概念 -- [Swiper](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-swiper.md)组件:滑动容器,提供切换子组件显示的能力。 -- [List](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)组件:列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。 -- [Video](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-media-components-video.md)组件:用于播放视频文件并控制其播放状态的组件。 -- [Navigator](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-navigator.md)组件:路由容器组件,提供路由跳转能力。 -- [ForEach](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-rendering-control-foreach.md)组件:基于数组类型数据执行循环渲染。 +- [Swiper](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-swiper.md)组件:滑动容器,提供切换子组件显示的能力。 +- [List](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)组件:列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。 +- [Video](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-media-components-video.md)组件:用于播放视频文件并控制其播放状态的组件。 +- [Navigator](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-navigator.md)组件:路由容器组件,提供路由跳转能力。 +- [ForEach](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/arkts-rendering-control-foreach.md)组件:基于数组类型数据执行循环渲染。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 -- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -44,39 +44,42 @@ 2. 搭建烧录环境。 - 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) - 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) 3. 搭建开发环境。 - 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 - 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 - 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 ## 代码结构解读 本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 ``` -├──entry/src/main/ets // 代码区 +├──entry/src/main/ets // 代码区 │ ├──common │ │ └──constants -│ │ └──CommonConstants.ets // 样式常量类 +│ │ └──CommonConstants.ets // 样式常量类 │ ├──entryability -│ │ └──EntryAbility.ts // 程序入口类 +│ │ └──EntryAbility.ts // 程序入口类 │ ├──model -│ │ └──VideoControll.ets // 视频播放控制相关方法类 +│ │ └──VideoControll.ets // 视频播放控制相关方法类 │ ├──pages -│ │ ├──SimpleVideoIndex.ets // 主界面 -│ │ └──SimpleVideoPlay.ets // 视频播放界面 +│ │ ├──SimpleVideoIndex.ets // 主界面 +│ │ └──SimpleVideoPlay.ets // 视频播放界面 │ ├──view -│ │ ├──IndexModule.ets // 自定义首页List模块组件文件 -│ │ ├──IndexSwiper.ets // 自定义首页Swiper组件文件 -│ │ ├──VideoPlayer.ets // 自定义播放界面视频组件文件 -│ │ └──VideoPlaySlider.ets // 自定义播放界面视频进度条组件文件 +│ │ ├──IndexModule.ets // 自定义首页List模块组件文件 +│ │ ├──IndexSwiper.ets // 自定义首页Swiper组件文件 +│ │ ├──VideoPlayer.ets // 自定义播放界面视频组件文件 +│ │ └──VideoPlaySlider.ets // 自定义播放界面视频进度条组件文件 │ └──viewmodel -│ └──VideoData.ets // 首页相关数据 -└──entry/src/main/resource // 应用静态资源目录 +│ ├──HorizontalVideoItem.ets // 水平视频类 +│ ├──ParamItem.ets // 参数类 +│ ├──SwiperVideoItem.ets // 自定义播放界面视频组件文件 +│ └──VideoData.ets // 首页相关数据 +└──entry/src/main/resource // 应用静态资源目录 ``` ## 构建主界面 @@ -89,34 +92,19 @@ VideoData.ets中定义的视频轮播图数组SWIPER_VIDEOS和视频列表图片 ```typescript // VideoData.ets -export const SWIPER_VIDEOS: object[] = [ - { - "image": $r("app.media.ic_banner1") - }, - { - "image": $r("app.media.ic_banner2") - }, - { - "image": $r("app.media.ic_banner3") - } +import { HorizontalVideoItem } from './HorizontalVideoItem'; +import { SwiperVideoItem } from './SwiperVideoItem'; + +export const SWIPER_VIDEOS: SwiperVideoItem[] = [ + new SwiperVideoItem($r('app.media.ic_banner1')), + new SwiperVideoItem($r('app.media.ic_banner2')), + new SwiperVideoItem($r('app.media.ic_banner3')) ]; -export const HORIZONTAL_VIDEOS: object[] = [ - { - "id": 1, - "image": $r("app.media.ic_video_list0"), - "name": '视频1' - }, - { - "id": 2, - "image": $r("app.media.ic_video_list1"), - "name": '视频2' - }, - { - "id": 3, - "image": $r("app.media.ic_video_list2"), - "name": '视频3' - } +export const HORIZONTAL_VIDEOS: HorizontalVideoItem[] = [ + new HorizontalVideoItem(1, $r('app.media.ic_video_list0'), '视频1'), + new HorizontalVideoItem(2, $r('app.media.ic_video_list1'), '视频2'), + new HorizontalVideoItem(3, $r('app.media.ic_video_list2'), '视频3') ]; ``` @@ -125,16 +113,15 @@ IndexSwiper.ets文件中定义的轮播图子组件SwiperVideo,点击轮播图 ![](figures/3.png) ```typescript -//IndexSwiper.ets +// IndexSwiper.ets @Component export struct SwiperVideo { - build() { Column() { Swiper() { - ForEach(SWIPER_VIDEOS, item => { + ForEach(SWIPER_VIDEOS, (item: SwiperVideoItem) => { SwiperItem({ imageSrc: item.image, source: $rawfile('videoTest.mp4') }) - }, item => JSON.stringify(item)) + }, (item: SwiperVideoItem) => JSON.stringify(item)) } .autoPlay(true) } @@ -145,16 +132,17 @@ export struct SwiperVideo { @Component struct SwiperItem { - private imageSrc: Resource; - private source: Resource; - + private imageSrc: Resource = $r('app.string.empty'); + private source: Resource = $r('app.string.empty'); + private paramItem: ParamItem = new ParamItem(); + ... build() { // 跳转一:使用Navigator组件跳转到视频播放界面 Navigator({ target: SECOND_PAGE, type: NavigationType.Push }) { Image(this.imageSrc) .borderRadius(MARGIN_FONT_SIZE.FIRST_MARGIN) } - .params({ source: this.source }) + .params(this.paramItem) } } ``` @@ -167,7 +155,7 @@ IndexModule.ets文件中定义的视频列表图片子组件VideoModule,点击 // IndexModule.ets @Component export struct VideoModule { - private moduleName: string; + private moduleName: string = ''; build() { Column() { @@ -175,7 +163,7 @@ export struct VideoModule { ... // 视频列表组件 List({ space: MARGIN_FONT_SIZE.FIRST_MARGIN }) { - ForEach(HORIZONTAL_VIDEOS, item => { + ForEach(HORIZONTAL_VIDEOS, (item: HorizontalVideoItem) => { ListItem() { HorizontalItem({ imageSrc: item.image, @@ -183,7 +171,7 @@ export struct VideoModule { videoName: item.name }) } - }, item => JSON.stringify(item)) + }, (item: HorizontalVideoItem) => JSON.stringify(item)) } // 设置列表横向排列 .listDirection(Axis.Horizontal) @@ -195,9 +183,9 @@ export struct VideoModule { @Component struct HorizontalItem { - private imageSrc: Resource; - private source: string; - private videoName: string; + private imageSrc: Resource = $r('app.string.empty'); + private source: string = ''; + private videoName: string = ''; build() { // 跳转二:使用route跳转到视频播放界面 @@ -230,12 +218,12 @@ struct SimpleVideoIndex { // 视频轮播组件 SwiperVideo() List() { - ForEach(LIST, (item) => { + ForEach(LIST, (item: string) => { ListItem() { VideoModule({ moduleName: item }) .margin({ top: MARGIN_FONT_SIZE.FIRST_MARGIN }) } - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } .listDirection(Axis.Vertical) .margin({ top: MARGIN_FONT_SIZE.THIRD_MARGIN }) @@ -253,15 +241,15 @@ VideoPlayer.ets其中定义了视频播放子组件VideoPlayer ,onPrepared回 // VideoPlayer.ets @Component export struct VideoPlayer { - private source: String | Resource; - private controller: VideoController; - private previewUris: Resource = $r('app.media.ic_preview'); + private source: string | Resource = ''; + private controller: VideoController = new VideoController(); + private previewUris: Resource = $r('app.media.preview'); @Provide currentTime: number = 0; @Provide durationTime: number = 0; @Provide durationStringTime: string = START_TIME; @Provide currentStringTime: string = START_TIME; @Consume isPlay: boolean; - @Consume isOpacity: boolean ; + @Consume isOpacity: boolean; @Consume flag: boolean; @Consume isLoading: boolean; @Consume progressVal: number; @@ -280,14 +268,16 @@ export struct VideoPlayer { .objectFit(ImageFit.Contain) .loop(false) .onUpdate((event) => { - this.currentTime = event.time; - this.currentStringTime = changeSliderTime(this.currentTime); - }) + if (event) { + this.currentTime = event.time; + this.currentStringTime = changeSliderTime(this.currentTime); + } + }) .onPrepared((event) => { - prepared.call(this, event); + this.prepared(event?.duration); }) .onFinish(() => { - finish.call(this); + this.finish(); }) .onError(() => { prompt.showToast({ @@ -298,6 +288,7 @@ export struct VideoPlayer { VideoSlider({ controller: this.controller }) } } + ... } ``` @@ -310,9 +301,9 @@ export struct VideoPlayer { @Component export struct VideoSlider { @Consume isOpacity: boolean; - private controller: VideoController; - @Consume currentStringTime: string; - @Consume currentTime: number; + private controller: VideoController = new VideoController(); + @Consume currentStringTime: string; + @Consume currentTime: number; @Consume durationTime: number; @Consume durationStringTime: string; @Consume isPlay: boolean; @@ -330,7 +321,7 @@ export struct VideoSlider { step: 1, style: SliderStyle.OutSet }) - .blockColor($r("app.color.white")) + .blockColor($r('app.color.white')) .width(STRING_PERCENT.SLIDER_WITH) .trackColor(Color.Gray) .selectedColor($r("app.color.white")) @@ -338,14 +329,14 @@ export struct VideoSlider { .showTips(true) .trackThickness(this.isOpacity ? SMALL_TRACK_THICK_NESS : BIG_TRACK_THICK_NESS) .onChange((value: number, mode: SliderChangeMode) => { - sliderOnchange.call(this, value, mode); + this.sliderOnchange(value, mode); }) ... - } .opacity(this.isOpacity ? DEFAULT_OPACITY : 1) - .width(ALL_PERCENT) - } + ... + } + ... } ``` @@ -353,82 +344,14 @@ export struct VideoSlider { ```typescript // VideoControll.ets -export function prepared(event) { - // 获取视频资源时长,单位(秒) - this.durationTime = event.duration; - // 转成mm:ss类型,计算其mm 和 ss - let second: number = event.duration % COMMON_NUM_MINUTE; - let min: number = parseInt((event.duration / COMMON_NUM_MINUTE).toString()); - let head = min < COMMON_NUM_DOUBLE ? `${ZERO_STR}${min}` : min; - let end = second < COMMON_NUM_DOUBLE ? `${ZERO_STR}${second}` : second; - this.durationStringTime = `${head}${SPLIT}${end}`; - this.flag = true; -} - -export function finish() { - // 结束播放后修改isPlay 重新渲染控制图标,控制图标显形 - this.isPlay = false; - this.isOpacity = false; -} - -export function sliderOnchange(value: number, mode: SliderChangeMode) { - this.currentTime = parseInt(value.toString()); - this.controller.setCurrentTime(parseInt(value.toString()), SeekMode.Accurate); - if (mode === SliderChangeMode.Begin) { - this.isOpacity = false; - } - if (mode === SliderChangeMode.Moving) { - this.isOpacity = false; - } - if (mode === SliderChangeMode.End) { - this.isOpacity = true; - } -}; - export function changeSliderTime(value: number): string { let second: number = value % COMMON_NUM_MINUTE; - let min: number = parseInt((value / COMMON_NUM_MINUTE).toString()); + let min: number = Number.parseInt((value / COMMON_NUM_MINUTE).toString()); let head = min < COMMON_NUM_DOUBLE ? `${ZERO_STR}${min}` : min; let end = second < COMMON_NUM_DOUBLE ? `${ZERO_STR}${second}` : second; let nowTime = `${head}${SPLIT}${end}`; return nowTime; } - -export function iconOnclick() { - if (this.isPlay) { - this.controller.pause() - this.isPlay = false; - this.isOpacity = false; - return; - } - if(this.flag) { - this.controller.start(); - this.isPlay = true; - this.isOpacity = true; - } else { - let that = this; - that.isLoading = true; - // 视频加载未完成。显示加载动作 - let intervalLoading = setInterval(function() { - if (that.progressVal >= STACK_STYLE.PROGRESS_TOTAL) { - that.progressVal = 0; - } else { - that.progressVal += STACK_STYLE.PROGRESS_STEP; - } - }, STACK_STYLE.MILLI_SECONDS) - // 定时任务判断视频加载是否完成 - let intervalFlag = setInterval(function() { - if (that.flag) { - that.controller.start(); - that.isPlay = true; - that.isOpacity = true; - that.isLoading = false; - clearInterval(intervalFlag); - clearInterval(intervalLoading); - } - }, STACK_STYLE.MILLI_SECONDS); - } -} ``` 在SimpleVideoPlay.ets播放界面,引用VideoPlayer子组件,并在视频播放页面使用堆叠容器,在视频播放画面中心堆叠控制、视频加载图标,效果如图所示: @@ -441,16 +364,17 @@ export function iconOnclick() { @Component struct Play { // 取到Index页面跳转来时携带的source对应的数据。 - private source: string = router.getParams()['source']; + private source: string = (router.getParams() as Record).source as string; private startIconResource: Resource = $r('app.media.ic_public_play'); private backIconResource: Resource = $r('app.media.ic_back'); @Provide isPlay: boolean = false; - @Provide isOpacity: boolean = false ; + @Provide isOpacity: boolean = false; controller: VideoController = new VideoController(); @Provide isLoading: boolean = false; @Provide progressVal: number = 0; @Provide flag: boolean = false; + ... onPageHide() { this.controller.pause(); } @@ -473,17 +397,17 @@ struct Play { value: STACK_STYLE.PROGRESS_VALUE, total: STACK_STYLE.PROGRESS_TOTAL, type: ProgressType.ScaleRing - }) - .color(Color.Grey) - .value(this.progressVal) - .width(STACK_STYLE.PROGRESS_WIDTH) - .style({ - strokeWidth: STACK_STYLE.PROGRESS_STROKE_WIDTH, - scaleCount: STACK_STYLE.PROGRESS_SCALE_COUNT, - scaleWidth: STACK_STYLE.PROGRESS_SCALE_WIDTH }) - .zIndex(STACK_STYLE.PROGRESS_Z_INDEX) - } + .color(Color.Grey) + .value(this.progressVal) + .width(STACK_STYLE.PROGRESS_WIDTH) + .style({ + strokeWidth: STACK_STYLE.PROGRESS_STROKE_WIDTH, + scaleCount: STACK_STYLE.PROGRESS_SCALE_COUNT, + scaleWidth: STACK_STYLE.PROGRESS_SCALE_WIDTH + }) + .zIndex(STACK_STYLE.PROGRESS_Z_INDEX) + } VideoPlayer({ source: this.source, controller: this.controller @@ -501,11 +425,10 @@ struct Play { 您已经完成了本次Codelab的学习,并了解到以下知识点: -1. Swiper组件的使用。 -2. List组件的使用。 -3. Video组件的使用。 -4. Slider组件的使用。 -5. 如何实现自定义视频控制器。 - +1. Swiper组件的使用。 +2. List组件的使用。 +3. Video组件的使用。 +4. Slider组件的使用。 +5. 如何实现自定义视频控制器。 ![](figures/彩带动效.gif) diff --git a/Media/SimpleVideo/entry/src/main/ets/common/constants/CommonConstants.ets b/Media/SimpleVideo/entry/src/main/ets/common/constants/CommonConstants.ets index fcd90dae518ac6b5c3ac17a1193cb0a4873521fb..9d1deb67f1963b7227d23ecc1947ef89c0a85f4c 100644 --- a/Media/SimpleVideo/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/Media/SimpleVideo/entry/src/main/ets/common/constants/CommonConstants.ets @@ -51,7 +51,7 @@ export const SPLIT: string = ':'; /** * default opacity */ -export const DEFAULT_OPACITY: number = parseFloat('0.2'); +export const DEFAULT_OPACITY: number = Number.parseFloat('0.2'); /** * slider small track thick ness @@ -108,7 +108,7 @@ export const enum STRING_PERCENT { INDEX_SWIPER_HEIGHT_PERCENT = '24.1%', INDEX_MODULE_HEIGHT_PERCENT = '25.8%', INDEX_SWIPER_LEFT_RIGHT_MARGIN = '3.3%' -}; +} /** * margin or font size @@ -121,7 +121,7 @@ export const enum MARGIN_FONT_SIZE { FIFTH_MARGIN = 50, SIXTH_MARGIN = 94, SEVENTH_MARGIN = 132 -}; +} /** * video resource type @@ -129,20 +129,20 @@ export const enum MARGIN_FONT_SIZE { export const enum VIDEO_TYPE { INNER = 'inner', NET = 'net' -}; +} /** * Attribute Styles in a Stack Layout */ -export const STACK_STYLE = { - IMAGE_Z_INDEX: 2, - PROGRESS_VALUE: 0, - PROGRESS_TOTAL: 100, - PROGRESS_STROKE_WIDTH: 15, - PROGRESS_SCALE_COUNT: 15, - PROGRESS_SCALE_WIDTH: 5, - PROGRESS_Z_INDEX: 1, - PROGRESS_WIDTH: 80, - PROGRESS_STEP: 10, - MILLI_SECONDS: 100 +export const enum STACK_STYLE { + IMAGE_Z_INDEX = 2, + PROGRESS_VALUE = 0, + PROGRESS_TOTAL = 100, + PROGRESS_STROKE_WIDTH = 15, + PROGRESS_SCALE_COUNT = 15, + PROGRESS_SCALE_WIDTH = 5, + PROGRESS_Z_INDEX = 1, + PROGRESS_WIDTH = 80, + PROGRESS_STEP = 10, + MILLI_SECONDS = 100 } diff --git a/Media/SimpleVideo/entry/src/main/ets/model/VideoControll.ets b/Media/SimpleVideo/entry/src/main/ets/model/VideoControll.ets index 4b8b6a525faa0e45817c8027dd7331a7994d6d70..79b3a604432554dcdf6b6e106eb0e37385eb195a 100644 --- a/Media/SimpleVideo/entry/src/main/ets/model/VideoControll.ets +++ b/Media/SimpleVideo/entry/src/main/ets/model/VideoControll.ets @@ -16,92 +16,15 @@ import { COMMON_NUM_MINUTE, COMMON_NUM_DOUBLE, ZERO_STR, SPLIT, STACK_STYLE } from '../common/constants/CommonConstants'; /** - * video component prepared callback - */ -export function prepared(event) { - this.durationTime = event.duration; - let second: number = event.duration % COMMON_NUM_MINUTE; - let min: number = parseInt((event.duration / COMMON_NUM_MINUTE).toString()); - let head = min < COMMON_NUM_DOUBLE ? `${ZERO_STR}${min}` : min; - let end = second < COMMON_NUM_DOUBLE ? `${ZERO_STR}${second}` : second; - this.durationStringTime = `${head}${SPLIT}${end}`; - this.flag = true; -}; - -/** - * video component finish callback - */ -export function finish() { - this.isPlay = false; - this.isOpacity = false; -}; - -/** - * video slider component onchange callback - */ -export function sliderOnchange(value: number, mode: SliderChangeMode) { - this.currentTime = parseInt(value.toString()); - this.controller.setCurrentTime(parseInt(value.toString()), SeekMode.Accurate); - if (mode === SliderChangeMode.Begin) { - this.isOpacity = false; - } - if (mode === SliderChangeMode.Moving) { - this.isOpacity = false; - } - if (mode === SliderChangeMode.End) { - this.isOpacity = true; - } -}; - -/** - * get video string of current time + * Get video string of current time. * @param the number of current time * @return the string of current time */ export function changeSliderTime(value: number): string { let second: number = value % COMMON_NUM_MINUTE; - let min: number = parseInt((value / COMMON_NUM_MINUTE).toString()); + let min: number = Number.parseInt((value / COMMON_NUM_MINUTE).toString()); let head = min < COMMON_NUM_DOUBLE ? `${ZERO_STR}${min}` : min; let end = second < COMMON_NUM_DOUBLE ? `${ZERO_STR}${second}` : second; let nowTime = `${head}${SPLIT}${end}`; return nowTime; -}; - -/** - * icon onclick callback - */ -export function iconOnclick() { - if (this.isPlay) { - this.controller.pause() - this.isPlay = false; - this.isOpacity = false; - return; - } - if(this.flag) { - this.controller.start(); - this.isPlay = true; - this.isOpacity = true; - } else { - let that = this; - that.isLoading = true; - // The video loading is not complete. The loading action is displayed. - let intervalLoading = setInterval(function() { - if (that.progressVal >= STACK_STYLE.PROGRESS_TOTAL) { - that.progressVal = 0; - } else { - that.progressVal += STACK_STYLE.PROGRESS_STEP; - } - }, STACK_STYLE.MILLI_SECONDS) - // The scheduled task determines whether the video loading is complete. - let intervalFlag = setInterval(function() { - if (that.flag) { - that.controller.start(); - that.isPlay = true; - that.isOpacity = true; - that.isLoading = false; - clearInterval(intervalFlag); - clearInterval(intervalLoading); - } - }, STACK_STYLE.MILLI_SECONDS); - } -}; \ No newline at end of file +} \ No newline at end of file diff --git a/Media/SimpleVideo/entry/src/main/ets/pages/SimpleVideoIndex.ets b/Media/SimpleVideo/entry/src/main/ets/pages/SimpleVideoIndex.ets index e4f4664dcee5daba082d7e855da0df8a5fd99e66..da4c268a5e4ebc548556567c45324d0d5148abb5 100644 --- a/Media/SimpleVideo/entry/src/main/ets/pages/SimpleVideoIndex.ets +++ b/Media/SimpleVideo/entry/src/main/ets/pages/SimpleVideoIndex.ets @@ -28,11 +28,12 @@ struct SimpleVideoIndex { Column({ space: MARGIN_FONT_SIZE.FOURTH_MARGIN }) { SwiperVideo() List() { - ForEach(LIST, (item) => { + ForEach(LIST, (item: string) => { ListItem() { - VideoModule({ moduleName: item }).margin({ top: MARGIN_FONT_SIZE.FIRST_MARGIN }) + VideoModule({ moduleName: item }) + .margin({ top: MARGIN_FONT_SIZE.FIRST_MARGIN }) } - }, item => JSON.stringify(item)) + }, (item: string) => JSON.stringify(item)) } .listDirection(Axis.Vertical) .margin({ top: MARGIN_FONT_SIZE.THIRD_MARGIN }) @@ -42,4 +43,3 @@ struct SimpleVideoIndex { .backgroundColor($r("app.color.index_backgroundColor")) } } - diff --git a/Media/SimpleVideo/entry/src/main/ets/pages/SimpleVideoPlay.ets b/Media/SimpleVideo/entry/src/main/ets/pages/SimpleVideoPlay.ets index 535675cdf541f98e4c660d1d4b5ad4d5d74f4e5c..6da023339c68e8bb51b082ea52041b30916fdbc1 100644 --- a/Media/SimpleVideo/entry/src/main/ets/pages/SimpleVideoPlay.ets +++ b/Media/SimpleVideo/entry/src/main/ets/pages/SimpleVideoPlay.ets @@ -28,7 +28,7 @@ import { @Entry @Component struct Play { - private source: string = router.getParams()['source']; + private source: string = (router.getParams() as Record).source as string; private startIconResource: Resource = $r('app.media.ic_public_play'); private backIconResource: Resource = $r('app.media.ic_back'); @Provide isPlay: boolean = false; @@ -60,7 +60,10 @@ struct Play { .margin({ left: MARGIN_FONT_SIZE.FIRST_MARGIN }) } .width(ALL_PERCENT) - .margin({ left: MARGIN_FONT_SIZE.FIRST_MARGIN, top: MARGIN_FONT_SIZE.FIRST_MARGIN }) + .margin({ + left: MARGIN_FONT_SIZE.FIRST_MARGIN, + top: MARGIN_FONT_SIZE.FIRST_MARGIN + }) .justifyContent(FlexAlign.Start) Stack() { @@ -91,13 +94,9 @@ struct Play { controller: this.controller }) .zIndex(0) - } } .height(ALL_PERCENT) .backgroundColor(Color.Black) } } - - - diff --git a/Media/SimpleVideo/entry/src/main/ets/view/IndexModule.ets b/Media/SimpleVideo/entry/src/main/ets/view/IndexModule.ets index 3387a886cc55c61363a3ba7f40ae875162fd9599..c0b04ecf4e372ee692895398ed63ed1df77b327b 100644 --- a/Media/SimpleVideo/entry/src/main/ets/view/IndexModule.ets +++ b/Media/SimpleVideo/entry/src/main/ets/view/IndexModule.ets @@ -21,13 +21,15 @@ import { SECOND_PAGE, NET } from '../common/constants/CommonConstants'; +import { HorizontalVideoItem } from '../viewmodel/HorizontalVideoItem'; + /** * The modules in index */ @Component export struct VideoModule { - private moduleName: string; + private moduleName: string = ''; build() { Column() { @@ -36,12 +38,14 @@ export struct VideoModule { .fontSize(MARGIN_FONT_SIZE.THIRD_MARGIN) .fontWeight(FontWeight.Bolder) } - .margin({ left: STRING_PERCENT.INDEX_SWIPER_LEFT_RIGHT_MARGIN, + .margin({ + left: STRING_PERCENT.INDEX_SWIPER_LEFT_RIGHT_MARGIN, bottom: MARGIN_FONT_SIZE.FIRST_MARGIN, - top: MARGIN_FONT_SIZE.FIRST_MARGIN }) + top: MARGIN_FONT_SIZE.FIRST_MARGIN + }) List({ space: MARGIN_FONT_SIZE.FIRST_MARGIN }) { - ForEach(HORIZONTAL_VIDEOS, item => { + ForEach(HORIZONTAL_VIDEOS, (item: HorizontalVideoItem) => { ListItem() { HorizontalItem({ imageSrc: item.image, @@ -49,7 +53,7 @@ export struct VideoModule { videoName: item.name }) } - }, item => JSON.stringify(item)) + }, (item: HorizontalVideoItem) => JSON.stringify(item)) } .listDirection(Axis.Horizontal) } @@ -69,9 +73,9 @@ export struct VideoModule { @Component struct HorizontalItem { - private imageSrc: Resource; - private source: string; - private videoName: string; + private imageSrc: Resource = $r('app.string.empty'); + private source: string = ''; + private videoName: string = ''; build() { Column() { diff --git a/Media/SimpleVideo/entry/src/main/ets/view/IndexSwiper.ets b/Media/SimpleVideo/entry/src/main/ets/view/IndexSwiper.ets index 95a15e6b32b527bff5e704035fe798ce0ac7d2cb..97c1a7c52cfc794148452a346bd1dea509dce320 100644 --- a/Media/SimpleVideo/entry/src/main/ets/view/IndexSwiper.ets +++ b/Media/SimpleVideo/entry/src/main/ets/view/IndexSwiper.ets @@ -15,44 +15,49 @@ import { SWIPER_VIDEOS } from '../viewmodel/VideoData'; import { STRING_PERCENT, MARGIN_FONT_SIZE, SECOND_PAGE } from '../common/constants/CommonConstants'; +import { SwiperVideoItem } from '../viewmodel/SwiperVideoItem'; +import { ParamItem } from '../viewmodel/ParamItem'; /** * Picture carousel component */ @Component export struct SwiperVideo { - build() { Column() { Swiper() { - ForEach(SWIPER_VIDEOS, item => { + ForEach(SWIPER_VIDEOS, (item: SwiperVideoItem) => { SwiperItem({ imageSrc: item.image, source: $rawfile('videoTest.mp4') }) - }, item => JSON.stringify(item)) + }, (item: SwiperVideoItem) => JSON.stringify(item)) } .autoPlay(true) } .height(STRING_PERCENT.INDEX_SWIPER_HEIGHT_PERCENT) .width(STRING_PERCENT.INDEX_COMPONENT_WITH_PERCENT) .backgroundColor($r('app.color.white')) - .margin({ - left: STRING_PERCENT.INDEX_SWIPER_LEFT_RIGHT_MARGIN, + .margin({ + left: STRING_PERCENT.INDEX_SWIPER_LEFT_RIGHT_MARGIN, right: STRING_PERCENT.INDEX_SWIPER_LEFT_RIGHT_MARGIN, top: MARGIN_FONT_SIZE.FOURTH_MARGIN - }) + }) } } @Component struct SwiperItem { - private imageSrc: Resource; - private source: Resource; + private imageSrc: Resource = $r('app.string.empty'); + private source: Resource = $r('app.string.empty'); + private paramItem: ParamItem = new ParamItem(); + + aboutToAppear() { + this.paramItem.source = this.source; + } build() { Navigator({ target: SECOND_PAGE, type: NavigationType.Push }) { Image(this.imageSrc) .borderRadius(MARGIN_FONT_SIZE.FIRST_MARGIN) } - .params({ source: this.source }) + .params(this.paramItem) } -} - +} \ No newline at end of file diff --git a/Media/SimpleVideo/entry/src/main/ets/view/VideoPlaySlider.ets b/Media/SimpleVideo/entry/src/main/ets/view/VideoPlaySlider.ets index 6f8ff45c819199e25b11616a590b3d168b9e589d..05927ddf96d91e9f254c4c90bc289e2f938797d3 100644 --- a/Media/SimpleVideo/entry/src/main/ets/view/VideoPlaySlider.ets +++ b/Media/SimpleVideo/entry/src/main/ets/view/VideoPlaySlider.ets @@ -13,7 +13,6 @@ * limitations under the License. */ -import { iconOnclick, sliderOnchange } from '../model/VideoControll'; import { ALL_PERCENT, MARGIN_FONT_SIZE, @@ -21,7 +20,8 @@ import { DEFAULT_OPACITY, STRING_PERCENT, BIG_TRACK_THICK_NESS, - IMAGE_SIZE + IMAGE_SIZE, + STACK_STYLE } from '../common/constants/CommonConstants'; /** @@ -30,15 +30,15 @@ import { @Component export struct VideoSlider { @Consume isOpacity: boolean; - private controller: VideoController; - @Consume currentStringTime: string; - @Consume currentTime: number; - @Consume durationTime: number ; - @Consume durationStringTime: string ; + @Consume currentStringTime: string; + @Consume currentTime: number; + @Consume durationTime: number; + @Consume durationStringTime: string; @Consume isPlay: boolean; @Consume flag: boolean; @Consume isLoading: boolean; @Consume progressVal: number; + private controller: VideoController = new VideoController(); build() { Row({ space: MARGIN_FONT_SIZE.FIRST_MARGIN }) { @@ -47,7 +47,7 @@ export struct VideoSlider { .height(IMAGE_SIZE) .margin({ left: MARGIN_FONT_SIZE.FIRST_MARGIN }) .onClick(() => { - iconOnclick.call(this); + this.iconOnclick(); }) Text(this.currentStringTime) .fontSize(MARGIN_FONT_SIZE.SECOND_MARGIN) @@ -68,7 +68,7 @@ export struct VideoSlider { .showTips(true) .trackThickness(this.isOpacity ? SMALL_TRACK_THICK_NESS : BIG_TRACK_THICK_NESS) .onChange((value: number, mode: SliderChangeMode) => { - sliderOnchange.call(this, value, mode); + this.sliderOnchange(value, mode); }) Text(this.durationStringTime) .fontSize(MARGIN_FONT_SIZE.SECOND_MARGIN) @@ -78,4 +78,56 @@ export struct VideoSlider { .opacity(this.isOpacity ? DEFAULT_OPACITY : 1) .width(ALL_PERCENT) } + + /** + * icon onclick callback + */ + iconOnclick() { + if (this.isPlay === true) { + this.controller.pause() + this.isPlay = false; + this.isOpacity = false; + return; + } + if (this.flag === true) { + this.controller.start(); + this.isPlay = true; + this.isOpacity = true; + } else { + this.isLoading = true; + // The video loading is not complete. The loading action is displayed. + let intervalLoading = setInterval(() => { + if (this.progressVal >= STACK_STYLE.PROGRESS_TOTAL) { + this.progressVal = 0; + } else { + this.progressVal += STACK_STYLE.PROGRESS_STEP; + } + }, STACK_STYLE.MILLI_SECONDS) + // The scheduled task determines whether the video loading is complete. + let intervalFlag = setInterval(() => { + if (this.flag === true) { + this.controller.start(); + this.isPlay = true; + this.isOpacity = true; + this.isLoading = false; + clearInterval(intervalFlag); + clearInterval(intervalLoading); + } + }, STACK_STYLE.MILLI_SECONDS); + } + } + + /** + * video slider component onchange callback + */ + sliderOnchange(value: number, mode: SliderChangeMode) { + this.currentTime = Number.parseInt(value.toString()); + this.controller.setCurrentTime(Number.parseInt(value.toString()), SeekMode.Accurate); + if (mode === SliderChangeMode.Begin || mode === SliderChangeMode.Moving) { + this.isOpacity = false; + } + if (mode === SliderChangeMode.End) { + this.isOpacity = true; + } + } } \ No newline at end of file diff --git a/Media/SimpleVideo/entry/src/main/ets/view/VideoPlayer.ets b/Media/SimpleVideo/entry/src/main/ets/view/VideoPlayer.ets index 72a4e36ae6d93637c87a11c2dbcd83293c74a343..3c1db9d29ef8c98f4e79fbe6d3694b92c68901ae 100644 --- a/Media/SimpleVideo/entry/src/main/ets/view/VideoPlayer.ets +++ b/Media/SimpleVideo/entry/src/main/ets/view/VideoPlayer.ets @@ -15,13 +15,17 @@ import prompt from '@ohos.promptAction'; import { VideoSlider } from '../view/VideoPlaySlider'; -import { prepared, finish, changeSliderTime } from '../model/VideoControll'; +import { changeSliderTime } from '../model/VideoControll'; import { START_TIME, STRING_PERCENT, COMMON_NUM_DURATION, MESSAGE, - ALL_PERCENT + ALL_PERCENT, + COMMON_NUM_MINUTE, + COMMON_NUM_DOUBLE, + ZERO_STR, + SPLIT } from '../common/constants/CommonConstants'; /** @@ -29,9 +33,9 @@ import { */ @Component export struct VideoPlayer { - private source: string | Resource; - private controller: VideoController; - private previewUris: Resource = $r("app.media.ic_preview"); + private source: string | Resource = ''; + private controller: VideoController = new VideoController(); + private previewUris: Resource = $r('app.media.ic_preview'); @Provide currentTime: number = 0; @Provide durationTime: number = 0; @Provide durationStringTime: string = START_TIME; @@ -56,14 +60,16 @@ export struct VideoPlayer { .objectFit(ImageFit.Contain) .loop(false) .onUpdate((event) => { - this.currentTime = event.time; - this.currentStringTime = changeSliderTime(this.currentTime); + if (event) { + this.currentTime = event.time; + this.currentStringTime = changeSliderTime(this.currentTime); + } }) .onPrepared((event) => { - prepared.call(this, event); + this.prepared(event?.duration); }) .onFinish(() => { - finish.call(this); + this.finish(); }) .onError(() => { prompt.showToast({ @@ -74,4 +80,25 @@ export struct VideoPlayer { VideoSlider({ controller: this.controller }) } } + + /** + * video component prepared callback + */ + prepared(duration: number) { + this.durationTime = duration; + let second: number = duration % COMMON_NUM_MINUTE; + let min: number = Number.parseInt((duration / COMMON_NUM_MINUTE).toString()); + let head = min < COMMON_NUM_DOUBLE ? `${ZERO_STR}${min}` : min; + let end = second < COMMON_NUM_DOUBLE ? `${ZERO_STR}${second}` : second; + this.durationStringTime = `${head}${SPLIT}${end}`; + this.flag = true; + } + + /** + * video component finish callback + */ + finish() { + this.isPlay = false; + this.isOpacity = false; + } } \ No newline at end of file diff --git a/Ability/StageAbilityDemo/entry/src/main/ets/common/bean/GoodsData.ets b/Media/SimpleVideo/entry/src/main/ets/viewmodel/HorizontalVideoItem.ets similarity index 65% rename from Ability/StageAbilityDemo/entry/src/main/ets/common/bean/GoodsData.ets rename to Media/SimpleVideo/entry/src/main/ets/viewmodel/HorizontalVideoItem.ets index 6dc78dd45fe50c78f2412387f06a837e3069b706..733bfa218dec389e374dd5f77187a957362c96bc 100644 --- a/Ability/StageAbilityDemo/entry/src/main/ets/common/bean/GoodsData.ets +++ b/Media/SimpleVideo/entry/src/main/ets/viewmodel/HorizontalVideoItem.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,14 +14,17 @@ */ /** - * GoodsData is used to initialize the GoodsComponent. + * Horizontal picture class. */ -export default class GoodsData { - goodsName: Resource; - price: string; - originalPrice: string; - discounts: Resource; - label: Resource; - goodsImg: Resource; - goodsDescription: Resource; +@Observed +export class HorizontalVideoItem { + id: number; + image: Resource; + name: string; + + constructor(id: number, image: Resource, name: string) { + this.id = id; + this.image = image; + this.name = name; + } } \ No newline at end of file diff --git a/ETSUI/RankingDemo/entry/src/main/ets/common/bean/RankData.ets b/Media/SimpleVideo/entry/src/main/ets/viewmodel/ParamItem.ets similarity index 77% rename from ETSUI/RankingDemo/entry/src/main/ets/common/bean/RankData.ets rename to Media/SimpleVideo/entry/src/main/ets/viewmodel/ParamItem.ets index 53d904e78d68fc3617ddd5be625456bb76bd3ecf..319a4180d655f258af698c86c936a1d727f5d0ff 100644 --- a/ETSUI/RankingDemo/entry/src/main/ets/common/bean/RankData.ets +++ b/Media/SimpleVideo/entry/src/main/ets/viewmodel/ParamItem.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,8 +13,10 @@ * limitations under the License. */ -export class RankData { - public fruitName: Resource; - private vote: string; // Number of votes - private id: string; +/** + * Navigator params class. + */ +@Observed +export class ParamItem { + source: Resource = $r('app.string.empty'); } \ No newline at end of file diff --git a/Media/SimpleVideo/entry/src/main/ets/viewmodel/SwiperVideoItem.ets b/Media/SimpleVideo/entry/src/main/ets/viewmodel/SwiperVideoItem.ets new file mode 100644 index 0000000000000000000000000000000000000000..3d00b203f005aabd847f824c8d71caee242328a9 --- /dev/null +++ b/Media/SimpleVideo/entry/src/main/ets/viewmodel/SwiperVideoItem.ets @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Horizontal picture class. + */ +@Observed +export class SwiperVideoItem { + image: Resource; + + constructor(image: Resource) { + this.image = image; + } +} \ No newline at end of file diff --git a/Media/SimpleVideo/entry/src/main/ets/viewmodel/VideoData.ets b/Media/SimpleVideo/entry/src/main/ets/viewmodel/VideoData.ets index 977a48a7ef74c4ad8e8ab4df252d77a39885c836..e72ac8628495182b343e673cbd24dedfd0cf2667 100644 --- a/Media/SimpleVideo/entry/src/main/ets/viewmodel/VideoData.ets +++ b/Media/SimpleVideo/entry/src/main/ets/viewmodel/VideoData.ets @@ -13,32 +13,17 @@ * limitations under the License. */ -export const SWIPER_VIDEOS: object[] = [ - { - "image": $r("app.media.ic_banner1") - }, - { - "image": $r("app.media.ic_banner2") - }, - { - "image": $r("app.media.ic_banner3") - } +import { HorizontalVideoItem } from './HorizontalVideoItem'; +import { SwiperVideoItem } from './SwiperVideoItem'; + +export const SWIPER_VIDEOS: SwiperVideoItem[] = [ + new SwiperVideoItem($r('app.media.ic_banner1')), + new SwiperVideoItem($r('app.media.ic_banner2')), + new SwiperVideoItem($r('app.media.ic_banner3')) ]; -export const HORIZONTAL_VIDEOS: object[] = [ - { - "id": 1, - "image": $r("app.media.ic_video_list0"), - "name": '视频1' - }, - { - "id": 2, - "image": $r("app.media.ic_video_list1"), - "name": '视频2' - }, - { - "id": 3, - "image": $r("app.media.ic_video_list2"), - "name": '视频3' - } +export const HORIZONTAL_VIDEOS: HorizontalVideoItem[] = [ + new HorizontalVideoItem(1, $r('app.media.ic_video_list0'), '视频1'), + new HorizontalVideoItem(2, $r('app.media.ic_video_list1'), '视频2'), + new HorizontalVideoItem(3, $r('app.media.ic_video_list2'), '视频3') ]; \ No newline at end of file diff --git a/Media/SimpleVideo/entry/src/main/resources/base/element/string.json b/Media/SimpleVideo/entry/src/main/resources/base/element/string.json index e1d5bf6555f794a262c0d3e498ea2a396be4281c..7c5651be25657a9a3edda50840b6c7b0471ef903 100644 --- a/Media/SimpleVideo/entry/src/main/resources/base/element/string.json +++ b/Media/SimpleVideo/entry/src/main/resources/base/element/string.json @@ -22,7 +22,11 @@ }, { "name": "back", - "value": "视频" + "value": "video" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/Media/SimpleVideo/entry/src/main/resources/en_US/element/string.json b/Media/SimpleVideo/entry/src/main/resources/en_US/element/string.json index 57d9d0d577fac28035bae9e68ae3a14ca7dd2133..7c5651be25657a9a3edda50840b6c7b0471ef903 100644 --- a/Media/SimpleVideo/entry/src/main/resources/en_US/element/string.json +++ b/Media/SimpleVideo/entry/src/main/resources/en_US/element/string.json @@ -23,6 +23,10 @@ { "name": "back", "value": "video" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/Media/SimpleVideo/entry/src/main/resources/zh_CN/element/string.json b/Media/SimpleVideo/entry/src/main/resources/zh_CN/element/string.json index 973329adc9d56ae99e0ce7fd7bb3304f535e0023..e26431eace942819b3ded5107331cbc97a3780f0 100644 --- a/Media/SimpleVideo/entry/src/main/resources/zh_CN/element/string.json +++ b/Media/SimpleVideo/entry/src/main/resources/zh_CN/element/string.json @@ -23,6 +23,10 @@ { "name": "back", "value": "视频" + }, + { + "name": "empty", + "value": "empty" } ] } \ No newline at end of file diff --git a/Media/SimpleVideo/hvigor/hvigor-config.json5 b/Media/SimpleVideo/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/Media/SimpleVideo/hvigor/hvigor-config.json5 +++ b/Media/SimpleVideo/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/Media/VideoPlayer/README.md b/Media/VideoPlayer/README.md index 2152b2caadfa0452014d74259f1698879790373d..c1250031404a659e7521ccab2b10e4e850c2966b 100644 --- a/Media/VideoPlayer/README.md +++ b/Media/VideoPlayer/README.md @@ -24,13 +24,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -58,20 +58,22 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ └──VideoBean.ets // 视频bean对象 │ │ ├──constants │ │ │ ├──CommonConstants.ets // 公共常量类 │ │ │ ├──HomeConstants.ets // 首页常量类 │ │ │ └──PlayConstants.ets // 视频播放页面常量类 +│ │ ├──constants +│ │ │ ├──HomeTabModel.ets // 首页参数模型 +│ │ │ └──PlayerModel.ets // 播放参数模型 │ │ └──util │ │ ├──DateFormatUtil.ets // 日期工具类 +│ │ ├──GlobalContext.ets // 全局工具类 │ │ ├──Logger.ets // 日志工具类 -│ │ └──ScreenUtil.ets // 屏幕工具类 +│ │ └──ScreenUtil.ets // 屏幕工具类 │ ├──controller -│ │ └──VideoController // 视频控制类 +│ │ └──VideoController.ets // 视频控制类 │ ├──entryability -│ │ └──EntryAbility.ts // 程序入口类 +│ │ └──EntryAbility.ts // 程序入口类 │ ├──pages │ │ ├──HomePage.ets // 首页页面 │ │ └──PlayPage.ets // 视频播放页面 @@ -88,7 +90,9 @@ │ │ └──PlayTitleDialog.ets // 播放速度设置子组件 │ └──viewmodel │ ├──HomeDialogModel.ets // 添加网络视频弹框类 -│ └──HomeVideoListModel.ets // 获取视频列表数据类 +│ ├──HomeVideoListModel.ets // 获取视频列表数据类 +│ ├──VideoItem.ets // 视频对象 +│ └──VideoSpeed.ets // 播放速度类 └──entry/src/main/resource // 应用静态资源目录 ``` @@ -98,7 +102,7 @@ ![](figures/2.gif) -获取本地视频,通过resourceManager.ResourceManager对象获取rawfile文件夹中的视频对象videoBean,再通过“fd://${videoBean.fd}”组装视频地址。 +获取本地视频,通过resourceManager.getRawFd方法获取rawfile文件夹中的视频资源文件描述符,构造本地视频对象。 ```typescript // HomeVideoListModel.ets @@ -106,17 +110,17 @@ async getLocalVideo() { this.videoLocalList = []; await this.assemblingVideoBean(); - globalThis.videoLocalList = this.videoLocalList; + GlobalContext.getContext().setObject('videoLocalList', this.videoLocalList); return this.videoLocalList; } // HomeVideoListModel.ets // 组装本地视频对象 -async assemblingVideoBean () { - VIDEO_DATA.forEach(async (item: VideoBean) => { - let videoBean = await globalThis.resourceManager.getRawFd(item.src); - let uri = `fd://${videoBean.fd}`; - this.videoLocalList.push(new VideoBean(item.name, uri)); +async assemblingVideoBean() { + VIDEO_DATA.forEach(async (item: VideoItem) => { + let videoBean = await getContext().resourceManager.getRawFd(item.iSrc); + let uri = videoBean; + this.videoLocalList.push(new VideoItem(item.name, uri, '')); }); } ``` @@ -131,8 +135,8 @@ async checkSrcValidity(checkFlag: number) { return; } this.isLoading = true; - this.context.linkCheck = $r('app.string.link_checking'); - this.context.loadColor = $r('app.color.index_tab_unselected_font_color'); + this.homeTabModel.linkCheck = $r('app.string.link_checking'); + this.homeTabModel.loadColor = $r('app.color.index_tab_unselected_font_color'); this.checkFlag = checkFlag; this.createAvPlayer(); } @@ -140,24 +144,24 @@ async checkSrcValidity(checkFlag: number) { // 校验链接有效性 checkUrlValidity() { this.isLoading = false; - this.context.linkCheck = $r('app.string.link_check'); - this.context.loadColor = $r('app.color.index_tab_selected_font_color'); - this.avPlayer.release(); - if (this.duration === HomeConstants.INTERNET_ADD_DIALOG.DURATION_TWO) { - // 链接校验失败 + this.homeTabModel.linkCheck = $r('app.string.link_check'); + this.homeTabModel.loadColor = $r('app.color.index_tab_selected_font_color'); + if (this.avPlayer !== null) { + this.avPlayer.release(); + } + if (this.duration === HomeConstants.DURATION_TWO) { + // Failed to verify the link this.showPrompt($r('app.string.link_check_fail')); - this.context.result = false; - } else if (this.duration === HomeConstants.INTERNET_ADD_DIALOG.DURATION_ONE) { - // 地址不正确或无网络可用 + } else if (this.duration === HomeConstants.DURATION_ONE) { + // The address is incorrect or no network is available this.showPrompt($r('app.string.link_check_address_internet')); - this.context.result = false; } else { this.duration = 0; if (this.checkFlag === 0) { this.showPrompt($r('app.string.link_check_success')); } else { - this.context.confirm(); - this.context.controller.close(); + this.homeTabModel!.confirm(); + this.homeTabModel!.controller!.close(); } } } @@ -193,21 +197,23 @@ XComponent({ ```typescript // VideoController.ets -createAVPlayer() { - media.createAVPlayer().then((avPlayer) => { - if (avPlayer) { - this.avPlayer = avPlayer; - this.bindState(); - } else { - ... - } - }); +async createAVPlayer() { + let avPlayer: media.AVPlayer = await media.createAVPlayer(); + this.avPlayer = avPlayer; + this.bindState(); } // VideoController.ets -bindState() { - this.avPlayer.on(Events.STATE_CHANGE, async (state) => { - switch (state) { +async bindState() { + if (this.avPlayer === null) { + return; + } + this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => { + let avplayerStatus: string = state; + if (this.avPlayer === null) { + return; + } + switch (avplayerStatus) { case AvplayerStatus.IDLE: ... case AvplayerStatus.INITIALIZED: @@ -220,10 +226,8 @@ bindState() { ... case AvplayerStatus.COMPLETED: ... - case AvplayerStatus.STOPPED: - ... case AvplayerStatus.RELEASED: - ... + ... default: ... } @@ -231,7 +235,7 @@ bindState() { this.avPlayer.on(Events.TIME_UPDATE, (time: number) => { this.initProgress(time); }); - this.avPlayer.on(Events.ERROR, (error) => { + this.avPlayer.on(Events.ERROR, () => { this.playError(); }) } @@ -241,22 +245,36 @@ AVPlayer实例需设置播放路径和XComponent中获取的surfaceID,设置 ```typescript // VideoController.ets -firstPlay(index: number, url: string, surfaceId: number) { +async firstPlay(index: number, url: resourceManager.RawFileDescriptor, iUrl: string, surfaceId: string) { this.index = index; this.url = url; + this.iUrl = iUrl; this.surfaceId = surfaceId; - this.avPlayer.url = this.url; + if (this.avPlayer === null) { + await this.createAVPlayer(); + } + if (this.avPlayer !== null) { + if (this.iUrl) { + this.avPlayer.url = this.iUrl; + } else { + this.avPlayer.fdSrc = this.url; + } + } } // VideoController.ets -bindState() { - this.avPlayer.on(Events.STATE_CHANGE, async (state) => { - switch (state) { - ... +async bindState() { + ... + this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => { + let avplayerStatus: string = state; + if (this.avPlayer === null) { + return; + } + switch (avplayerStatus) { + case AvplayerStatus.IDLE: + ... case AvplayerStatus.INITIALIZED: - if (!this.avPlayer.surfaceId) { - this.avPlayer.surfaceId = this.surfaceId; - } + this.avPlayer.surfaceId = this.surfaceId; this.avPlayer.prepare(); break; ... @@ -270,9 +288,11 @@ bindState() { ```typescript // VideoController.ets -bindState() { - this.avPlayer.on(Events.STATE_CHANGE, async (state) => { - switch (state) { +async bindState() { + ... + this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => { + ... + switch (avplayerStatus) { ... case AvplayerStatus.PREPARED: this.avPlayer.videoScaleType = 0; @@ -292,6 +312,9 @@ bindState() { ```typescript // VideoController.ets switchPlayOrPause() { + if (this.avPlayer === null) { + return; + } if (this.status === CommonConstants.STATUS_START) { this.avPlayer.pause(); } else { @@ -300,20 +323,18 @@ switchPlayOrPause() { } // VideoController.ets -bindState() { - this.avPlayer.on(Events.STATE_CHANGE, async (state) => { - switch (state) { +async bindState() { + ... + this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => { + ... + switch (avplayerStatus) { ... case AvplayerStatus.PLAYING: - this.avPlayer.setVolume(this.playerThis.volume); + this.avPlayer.setVolume(this.playerModel.volume); this.setBright(); this.status = CommonConstants.STATUS_START; this.watchStatus(); break; - case AvplayerStatus.PAUSED: - this.status = CommonConstants.STATUS_PAUSE; - this.watchStatus(); - break; ... } }); @@ -327,29 +348,42 @@ bindState() { // VideoController.ets // 设置当前播放位置 setSeekTime(value: number, mode: SliderChangeMode) { - if (mode === SliderChangeMode.Moving) { - this.progressThis.progressVal = value; - this.progressThis.currentTime = DateFormatUtil.secondToTime(Math.floor(value * this.duration / - CommonConstants.ONE_HUNDRED / CommonConstants.A_THOUSAND)); + if (mode === Number(SliderMode.MOVING)) { + this.playerModel.progressVal = value; + this.playerModel.currentTime = DateFormatUtil.secondToTime(Math.floor(value * this.duration / + CommonConstants.ONE_HUNDRED / CommonConstants.A_THOUSAND)); } - if (mode === SliderChangeMode.End) { + if (mode === Number(SliderMode.END) || mode === Number(SliderMode.CLICK)) { this.seekTime = value * this.duration / CommonConstants.ONE_HUNDRED; - this.avPlayer.seek(this.seekTime, media.SeekMode.SEEK_PREV_SYNC); + if (this.avPlayer !== null) { + this.avPlayer.seek(this.seekTime, media.SeekMode.SEEK_PREV_SYNC); + } } } // VideoController.ets // 设置播放音量 -onVolumeActionUpdate(event: GestureEvent) { - if (!this.playerThis.brightShow) { - this.playerThis.volumeShow = true; - let changeVolume = (event.offsetX - this.positionX) / globalThis.screenWidth; - let currentVolume = this.playerThis.volume + changeVolume; - let volumeMinFlag = currentVolume <= PlayConstants.PLAY_PAGE.MIN_VALUE; - let volumeMaxFlag = currentVolume > PlayConstants.PLAY_PAGE.MAX_VALUE; - this.playerThis.volume = volumeMinFlag ? PlayConstants.PLAY_PAGE.MIN_VALUE : - (volumeMaxFlag ? PlayConstants.PLAY_PAGE.MAX_VALUE : currentVolume); - this.avPlayer.setVolume(this.playerThis.volume); +onVolumeActionUpdate(event?: GestureEvent) { + if (!event) { + return; + } + if (this.avPlayer === null) { + return; + } + if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) { + return; + } + if (this.playerModel.brightShow === false) { + this.playerModel.volumeShow = true; + let screenWidth = GlobalContext.getContext().getObject('screenWidth') as number; + let changeVolume = (event.offsetX - this.positionX) / screenWidth; + let volume: number = this.playerModel.volume; + let currentVolume = volume + changeVolume; + let volumeMinFlag = currentVolume <= PlayConstants.MIN_VALUE; + let volumeMaxFlag = currentVolume > PlayConstants.MAX_VALUE; + this.playerModel.volume = volumeMinFlag ? PlayConstants.MIN_VALUE : + (volumeMaxFlag ? PlayConstants.MAX_VALUE : currentVolume); + this.avPlayer.setVolume(this.playerModel.volume); this.positionX = event.offsetX; } } @@ -357,24 +391,37 @@ onVolumeActionUpdate(event: GestureEvent) { // VideoController.ets // 设置播放速度 setSpeed(playSpeed: number) { - this.playSpeed = playSpeed; - this.avPlayer.setSpeed(this.playSpeed); + if (this.avPlayer === null) { + return; + } + if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) { + return; + } + this.playerModel.playSpeed = playSpeed; + this.avPlayer.setSpeed(this.playerModel.playSpeed); } ``` 视频播放完成之后,进入completed状态,需调用reset\(\)对视频进行重置,此时变为idle转态,在idle状态下设置下一个视频的播放地址,又会进入initialized状态。 ```typescript -// VideoController.ets -bindState() { - this.avPlayer.on(Events.STATE_CHANGE, async (state) => { - switch (state) { +// VideoController.ets +sync bindState() { + ... + this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => { + let avplayerStatus: string = state; + ... + switch (avplayerStatus) { case AvplayerStatus.IDLE: - ... - this.avPlayer.url = this.url; + this.resetProgress(); + if (this.iUrl) { + this.avPlayer.url = this.iUrl; + } else { + this.avPlayer.fdSrc = this.url; + } break; case AvplayerStatus.INITIALIZED: - ... + this.avPlayer.surfaceId = this.surfaceId; this.avPlayer.prepare(); break; ... @@ -403,10 +450,10 @@ Column() { ... .gesture( PanGesture(this.panOptionBright) - .onActionStart((event: GestureEvent) => { + .onActionStart((event?: GestureEvent) => { this.playVideoModel.onBrightActionStart(event); }) - .onActionUpdate((event: GestureEvent) => { + .onActionUpdate((event?: GestureEvent) => { this.playVideoModel.onBrightActionUpdate(event); }) .onActionEnd(() => { @@ -418,10 +465,10 @@ Column() { ... .gesture( PanGesture(this.panOptionVolume) - .onActionStart((event: GestureEvent) => { + .onActionStart((event?: GestureEvent) => { this.playVideoModel.onVolumeActionStart(event); }) - .onActionUpdate((event: GestureEvent) => { + .onActionUpdate((event?: GestureEvent) => { this.playVideoModel.onVolumeActionUpdate(event); }) .onActionEnd(() => { @@ -437,30 +484,39 @@ Column() { ```typescript // VideoController.ets -... // 手指触摸到音量调节区域 -onVolumeActionStart(event: GestureEvent) { +onVolumeActionStart(event?: GestureEvent) { + if (!event) { + return; + } this.positionX = event.offsetX; } -... + // 手指在音量调节区域水平滑动 -onVolumeActionUpdate(event: GestureEvent) { +onVolumeActionUpdate(event?: GestureEvent) { + if (!event) { + return; + } + if (this.avPlayer === null) { + return; + } if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) { return; } - if (!this.playerThis.brightShow) { - this.playerThis.volumeShow = true; - let changeVolume = (event.offsetX - this.positionX) / globalThis.screenWidth; - let currentVolume = this.playerThis.volume + changeVolume; - let volumeMinFlag = currentVolume <= PlayConstants.PLAY_PAGE.MIN_VALUE; - let volumeMaxFlag = currentVolume > PlayConstants.PLAY_PAGE.MAX_VALUE; - this.playerThis.volume = volumeMinFlag ? PlayConstants.PLAY_PAGE.MIN_VALUE : - (volumeMaxFlag ? PlayConstants.PLAY_PAGE.MAX_VALUE : currentVolume); - this.avPlayer.setVolume(this.playerThis.volume); + if (this.playerModel.brightShow === false) { + this.playerModel.volumeShow = true; + let screenWidth = GlobalContext.getContext().getObject('screenWidth') as number; + let changeVolume = (event.offsetX - this.positionX) / screenWidth; + let volume: number = this.playerModel.volume; + let currentVolume = volume + changeVolume; + let volumeMinFlag = currentVolume <= PlayConstants.MIN_VALUE; + let volumeMaxFlag = currentVolume > PlayConstants.MAX_VALUE; + this.playerModel.volume = volumeMinFlag ? PlayConstants.MIN_VALUE : + (volumeMaxFlag ? PlayConstants.MAX_VALUE : currentVolume); + this.avPlayer.setVolume(this.playerModel.volume); this.positionX = event.offsetX; } } -... ``` ## 总结 diff --git a/Media/VideoPlayer/entry/src/main/ets/common/constants/CommonConstants.ets b/Media/VideoPlayer/entry/src/main/ets/common/constants/CommonConstants.ets index 7148944a4e3394c4146a4746e18a4e256fa3df1b..b34fff0357f6100cf11eafdde1f4c1c6f971a68f 100644 --- a/Media/VideoPlayer/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/Media/VideoPlayer/entry/src/main/ets/common/constants/CommonConstants.ets @@ -12,7 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { VideoBean } from '../bean/VideoBean'; + +import { VideoItem } from '../../viewmodel/VideoItem'; +import { VideoSpeed } from '../../viewmodel/VideoSpeed'; +import resourceManager from '@ohos.resourceManager'; /** * Common constants for all features. @@ -22,97 +25,84 @@ export class CommonConstants { * Full percent. */ static readonly FULL_PERCENT: string = '100%'; - /** * Ninety percent. */ static readonly NINETY_PERCENT: string = '90%'; - /** * Fifty percent. */ static readonly FIFTY_PERCENT: string = '50%'; - /** * Playback page path. */ static readonly PAGE: string = 'pages/PlayPage'; - /** * Local video ID. */ static readonly TYPE_LOCAL: number = 0; - /** * Network video ID. */ static readonly TYPE_INTERNET: number = 1; - /** * Start playing. */ static readonly STATUS_START: number = 1; - /** * Playing Pause. */ static readonly STATUS_PAUSE: number = 2; - /** * Stop Playing. */ static readonly STATUS_STOP: number = 3; - /** * Width-height ratio. */ static readonly ASPECT_RATIO: number = 1; - /** * One hundred. */ static readonly ONE_HUNDRED: number = 100; - /** * A thousand. */ static readonly A_THOUSAND: number = 1000; - /** * Speed set. */ - static readonly SPEED_ARRAY = [ - { text: '0.75X', value: 0 }, - { text: '1.0X', value: 1 }, - { text: '1.25X', value: 2 }, - { text: '1.75X', value: 3 }, - { text: '2.0X', value: 4 } + static readonly SPEED_ARRAY: VideoSpeed[] = [ + new VideoSpeed('0.75X', 0), + new VideoSpeed('1.0X', 1), + new VideoSpeed('1.25X', 2), + new VideoSpeed('1.75X', 3), + new VideoSpeed('2.0X', 4) ]; - /** * time system, Hour-minute-second conversion. */ static readonly TIME_UNIT: number = 60; - /** * Initial Time UNIT. */ static readonly INITIAL_TIME_UNIT: string = '00'; - /** * Zero padding, 2 bits. */ static readonly PADDING_LENGTH: number = 2; - /** * String zero padding. */ static readonly PADDING_STR: string = '0'; - + /** + * Breath screen status. + */ + static readonly SCREEN_OFF: string = 'usual.event.SCREEN_OFF'; /** * Operation status of video player 4. */ - static readonly OPERATE_STATE: Array = ['prepared','playing', 'paused', 'completed']; + static readonly OPERATE_STATE: Array = ['prepared', 'playing', 'paused', 'completed']; } /** @@ -139,16 +129,19 @@ export enum Events { ERROR = 'error' } +/** + * Slider mode. + */ +export enum SliderMode { + MOVING = 1, + END = 2, + CLICK = 3 +} + /** * Video object collection. */ -export const VIDEO_DATA: VideoBean[] = [ - { - 'name': 'video1', - 'src': 'video1.mp4' - }, - { - 'name': 'video2', - 'src': 'video2.mp4' - } -] +export const VIDEO_DATA: VideoItem[] = [ + new VideoItem('video1', {} as resourceManager.RawFileDescriptor, 'video1.mp4',), + new VideoItem('video2', {} as resourceManager.RawFileDescriptor, 'video2.mp4',) +] \ No newline at end of file diff --git a/Media/VideoPlayer/entry/src/main/ets/common/constants/HomeConstants.ets b/Media/VideoPlayer/entry/src/main/ets/common/constants/HomeConstants.ets index 1750f47e6367b9d9eaf713cb4390f567428a2704..7abe9c93f412ec0b29eda7093d00d01a540fd8d1 100644 --- a/Media/VideoPlayer/entry/src/main/ets/common/constants/HomeConstants.ets +++ b/Media/VideoPlayer/entry/src/main/ets/common/constants/HomeConstants.ets @@ -20,64 +20,44 @@ export class HomeConstants { /** * Constants on the tab page of the main interface. */ - static readonly HOME_TAB = { - CURRENT_INDEX: 0, - TAB_BAR_FIRST: 0, - TAB_BAR_SECOND: 1, - BAR_WIDTH: 360, - BAR_HEIGHT: 60, - FONT_WEIGHT_SELECT: 500, - FONT_WEIGHT_UNSELECT: 400, - LINE_HEIGHT: 22, - MARGIN_TOP_TWO: 17, - MARGIN_BOTTOM: 7, - STROKE_WIDTH: 2 - } - + static readonly CURRENT_INDEX: number = 0; + static readonly TAB_BAR_FIRST: number = 0; + static readonly TAB_BAR_SECOND: number = 1; + static readonly BAR_WIDTH: number = 360; + static readonly BAR_HEIGHT: number = 60; + static readonly FONT_WEIGHT_SELECT: number = 500; + static readonly FONT_WEIGHT_UNSELECT: number = 400; + static readonly LINE_HEIGHT: number = 22; + static readonly MARGIN_TOP_TWO: number = 17; + static readonly MARGIN_BOTTOM: number = 7; + static readonly STROKE_WIDTH: number = 2; /** * Constant of the video list. */ - static readonly HOME_TAB_LIST = { - COLUMN_WIDTH: '86.7%', - LIST_SPACE: 20, - LIST_INITIAL_INDEX: 0, - IMAGE_HEIGHT: '84.8%', - IMAGE_WIDTH: '26.7%', - DIVIDER_STROKE_WIDTH: 1, - LIST_ITEM_ROW_COLUMN_WIDTH: '73.3%', - LIST_ITEM_ROW_HEIGHT: '12.3%', - WIDTH: 720, - HEIGHT: 720 - } - + static readonly COLUMN_WIDTH: string = '86.7%'; + static readonly LIST_SPACE: number = 20; + static readonly LIST_INITIAL_INDEX: number = 0; + static readonly IMAGE_HEIGHT: string = '84.8%'; + static readonly IMAGE_WIDTH: string = '26.7%'; + static readonly DIVIDER_STROKE_WIDTH: number = 1; + static readonly LIST_ITEM_ROW_COLUMN_WIDTH: string = '73.3%'; + static readonly LIST_ITEM_ROW_HEIGHT: string = '12.3%'; + static readonly WIDTH: number = 720; + static readonly HEIGHT: number = 720; /** * Scan local video and add network video buttons. */ - static readonly HOME_TAB_BUTTON = { - HEIGHT: '51%', - COLUMN_HEIGHT: '10%' - } - + static readonly TAB_BUTTON_HEIGHT: string = '51%'; + static readonly TAB_COLUMN_HEIGHT: string = '10%'; /** * Add Network Video dialog box. */ - static readonly INTERNET_ADD_DIALOG= { - OFFSET_DX: 0, - OFFSET_DY: -20, - GRID_COUNT: 4, - TEXT_HEIGHT: '6.7%', - TEXT_MARGIN_TOP: '3.1%', - DURATION: 1000, - DURATION_ONE: -1, - DURATION_TWO: 0 - } - - /** - * The video player is used to verify the video link. - */ - static readonly X_COMPONENT = { - ID: '', - TYPE: 'surface', - LIBRARY_NAME: '', - } + static readonly OFFSET_DX: number = 0; + static readonly OFFSET_DY: number = -20; + static readonly GRID_COUNT: number = 4; + static readonly TEXT_HEIGHT: string = '6.7%'; + static readonly TEXT_MARGIN_TOP: string = '3.1%'; + static readonly DURATION: number = 1000; + static readonly DURATION_ONE: number = -1; + static readonly DURATION_TWO: number = 0; } diff --git a/Media/VideoPlayer/entry/src/main/ets/common/constants/PlayConstants.ets b/Media/VideoPlayer/entry/src/main/ets/common/constants/PlayConstants.ets index 5cb7edac28289420b7672c4dbe58be96ebcbb9cf..188d2857b271a061b598f5c0a7b7a600a26b1d1d 100644 --- a/Media/VideoPlayer/entry/src/main/ets/common/constants/PlayConstants.ets +++ b/Media/VideoPlayer/entry/src/main/ets/common/constants/PlayConstants.ets @@ -20,106 +20,86 @@ export class PlayConstants { /** * Playback page constant. */ - static readonly PLAY_PAGE = { - PLAY_SPEED: 1, - VOLUME: 0.5, - VOLUME_SHOW: false, - BRIGHT: 0.5, - BRIGHT_SHOW: false, - POSITION_X: 0, - POSITION_Y: 0, - HEIGHT: '7.2%', - PLAY_PLAYER_HEIGHT: '25.6%', - PLAY_PLAYER_HEIGHT_FULL: '75.4%', - PLAY_PROGRESS_HEIGHT: '7.1%', - COLUMN_HEIGHT_ONE: '26.9%', - COLUMN_HEIGHT_TWO: '22.9%', - MIN_ANGLE: 0, - MAX_ANGLE: 30, - MIN_VALUE: 0, - MAX_VALUE: 1, - DISAPPEAR_TIME: 200, - MARGIN_ZERO: '0' - } - + static readonly PLAY_SPEED: number = 1; + static readonly VOLUME: number = 0.5; + static readonly VOLUME_SHOW: boolean = false; + static readonly BRIGHT: number = 0.5; + static readonly BRIGHT_SHOW: boolean = false; + static readonly POSITION_X: number = 0; + static readonly POSITION_Y: number = 0; + static readonly HEIGHT: string = '7.2%'; + static readonly PLAY_PLAYER_HEIGHT: string = '25.6%'; + static readonly PLAY_PLAYER_HEIGHT_FULL: string = '75.4%'; + static readonly PLAY_PROGRESS_HEIGHT: string = '7.1%'; + static readonly COLUMN_HEIGHT_ONE: string = '26.9%'; + static readonly COLUMN_HEIGHT_TWO: string = '22.9%'; + static readonly MIN_ANGLE: number = 0; + static readonly MAX_ANGLE: number = 30; + static readonly MIN_VALUE: number = 0; + static readonly MAX_VALUE: number = 1; + static readonly DISAPPEAR_TIME: number = 200; + static readonly MARGIN_ZERO: string = '0'; /** * Playback Page Header Constant. */ - static readonly PLAY_TITLE = { - DX: 0, - DY: -20, - GRID_COUNT: 4, - TEXT_MARGIN_LEFT: '4.4%', - ROW_WIDTH: '86.6%', - POPUP: { - ROW_HEIGHT: '45.3%', - ROW_MARGIN_TOP: '3.8%', - DIVIDER_STROKE_WIDTH: 1, - DIVIDER_MARGIN_RIGHT: '10.2%', - COLUMN_WIDTH: '43.3%', - COLUMN_HEIGHT: '13.5%', - CLOSE_TIME: 500 - }, - } - + static readonly DX: number = 0; + static readonly DY: number = -20; + static readonly GRID_COUNT: number = 4; + static readonly TEXT_MARGIN_LEFT: string = '4.4%'; + static readonly ROW_WIDTH: string = '86.6%'; + static readonly POPUP_ROW_HEIGHT: string = '45.3%'; + static readonly POPUP_ROW_MARGIN_TOP: string = '3.8%'; + static readonly POPUP_DIVIDER_STROKE_WIDTH: number = 1; + static readonly POPUP_DIVIDER_MARGIN_RIGHT: string = '10.2%'; + static readonly POPUP_COLUMN_WIDTH: string = '43.3%'; + static readonly POPUP_COLUMN_HEIGHT: string = '13.5%'; + static readonly POPUP_CLOSE_TIME: number = 500; /** * Constants for setting the playback speed. */ - static readonly PLAY_TITLE_DIALOG = { - ROW_HEIGHT: '25%', - ROW_WIDTH: '86.6%', - COLUMNS_TEMPLATE: '1fr 1fr 1fr', - ROWS_TEMPLATE: '1fr 1fr', - COLUMNS_GAP: 10, - ROWS_GAP: 10, - COLUMN_WIDTH: '39.2%' - } - + static readonly TITLE_DIALOG_ROW_HEIGHT: string = '25%'; + static readonly TITLE_DIALOG_ROW_WIDTH: string = '86.6%'; + static readonly TITLE_DIALOG_COLUMNS_TEMPLATE: string = '1fr 1fr 1fr'; + static readonly TITLE_DIALOG_ROWS_TEMPLATE: string = '1fr 1fr'; + static readonly TITLE_DIALOG_COLUMNS_GAP: number = 10; + static readonly TITLE_DIALOG_ROWS_GAP: number = 10; + static readonly TITLE_DIALOG_COLUMN_WIDTH: string = '39.2%'; /** * Video playback constant. */ - static readonly PLAY_PLAYER = { - ID: '', - TYPE: 'surface', - LIBRARY_NAME: '', - SURFACE_WIDTH: 1920, - SURFACE_HEIGHT: 1080, - STACK_WIDTH: '16.7%', - IMAGE_WIDTH: '95%', - FIRST: 0, - NEXT: 1, - DURATION: 0 - } - + static readonly PLAYER_ID: string = ''; + static readonly PLAYER_TYPE: string = 'surface'; + static readonly PLAYER_LIBRARY_NAME: string = ''; + static readonly PLAYER_SURFACE_WIDTH: number = 1920; + static readonly PLAYER_SURFACE_HEIGHT: number = 1080; + static readonly PLAYER_STACK_WIDTH: string = '16.7%'; + static readonly PLAYER_IMAGE_WIDTH: string = '95%'; + static readonly PLAYER_FIRST: number = 0; + static readonly PLAYER_NEXT: number = 1; + static readonly PLAYER_DURATION: number = 0; /** * Video playback control constant. */ - static readonly PLAY_CONTROL = { - ROW_WIDTH: '68.8%', - PLAY_START: 1, - PLAY_PAUSE: 2, - NEXT: 1, - FIRST: 0 - } - + static readonly CONTROL_ROW_WIDTH: string = '68.8%'; + static readonly CONTROL_PLAY_START: number = 1; + static readonly CONTROL_PLAY_PAUSE: number = 2; + static readonly CONTROL_NEXT: number = 1; + static readonly CONTROL_FIRST: number = 0; /** * Progress bar page constant. */ - static readonly PLAY_PROGRESS = { - CURRENT_TIME: '00:00', - TOTAL_TIME: '00:00', - PROGRESS_VAL: 0, - INTERVAL: -1, - STEP: 1, - TRACK_THICKNESS: 1, - SLIDER_WIDTH: '68.9%', - MARGIN_LEFT: '2.2%', - SEEK_TIME: 0, - ROW_WIDTH: '93.4%' - } - + static readonly PROGRESS_CURRENT_TIME: string = '00:00'; + static readonly PROGRESS_TOTAL_TIME: string = '00:00'; + static readonly PROGRESS_PROGRESS_VAL: number = 0; + static readonly PROGRESS_INTERVAL: number = -1; + static readonly PROGRESS_STEP: number = 1; + static readonly PROGRESS_TRACK_THICKNESS: number = 1; + static readonly PROGRESS_SLIDER_WIDTH: string = '68.9%'; + static readonly PROGRESS_MARGIN_LEFT: string = '2.2%'; + static readonly PROGRESS_SEEK_TIME: number = 0; + static readonly PROGRESS_ROW_WIDTH: string = '93.4%'; /** * Network video playback error notification duration */ - static readonly PLAY_ERROR_TIME = 3000; -} + static readonly PLAY_ERROR_TIME: number = 3000; +} \ No newline at end of file diff --git a/Media/VideoPlayer/entry/src/main/ets/common/model/HomeTabModel.ets b/Media/VideoPlayer/entry/src/main/ets/common/model/HomeTabModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..3fef544c103b8573d8f45fba14f6533b514e6318 --- /dev/null +++ b/Media/VideoPlayer/entry/src/main/ets/common/model/HomeTabModel.ets @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VideoItem } from '../../viewmodel/VideoItem' + +@Observed +export class HomeTabModel { + videoList: Array = []; + name: string = ''; + src: string = ''; + linkCheck: Resource = $r('app.string.link_check'); + confirmAdd: Resource = $r('app.string.confirm_add'); + loadColor: Resource = $r('app.color.index_tab_selected_font_color'); + confirm: () => void = () => { + }; + controller?: CustomDialogController; +} \ No newline at end of file diff --git a/Media/VideoPlayer/entry/src/main/ets/common/model/PlayerModel.ets b/Media/VideoPlayer/entry/src/main/ets/common/model/PlayerModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..fcb2b8ed34bb6241e566d76908976447054b1790 --- /dev/null +++ b/Media/VideoPlayer/entry/src/main/ets/common/model/PlayerModel.ets @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonConstants } from '../constants/CommonConstants'; +import { PlayConstants } from '../constants/PlayConstants'; + +@Observed +export class PlayerModel { + videoHeight: string = PlayConstants.PLAY_PLAYER_HEIGHT; + videoWidth: string = CommonConstants.FULL_PERCENT; + videoMargin: string = PlayConstants.MARGIN_ZERO; + videoPosition: FlexAlign = FlexAlign.Center; + playSpeed: number = PlayConstants.PLAY_SPEED; + volume: number = PlayConstants.VOLUME; + volumeShow: boolean = PlayConstants.VOLUME_SHOW; + bright: number = PlayConstants.BRIGHT; + brightShow: boolean = PlayConstants.BRIGHT_SHOW; + currentTime: string = PlayConstants.PROGRESS_CURRENT_TIME; + totalTime: string = PlayConstants.PROGRESS_TOTAL_TIME; + progressVal: number = PlayConstants.PROGRESS_PROGRESS_VAL; +} \ No newline at end of file diff --git a/Media/VideoPlayer/entry/src/main/ets/common/util/DateFormatUtil.ets b/Media/VideoPlayer/entry/src/main/ets/common/util/DateFormatUtil.ets index 1392f54f99c123d5971607091231a402534919ad..db7c3ff726e231592629098054272d63eb22644d 100644 --- a/Media/VideoPlayer/entry/src/main/ets/common/util/DateFormatUtil.ets +++ b/Media/VideoPlayer/entry/src/main/ets/common/util/DateFormatUtil.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { CommonConstants } from '../constants/CommonConstants' +import { CommonConstants } from '../constants/CommonConstants'; class DateFormatUtil { /** @@ -22,15 +22,11 @@ class DateFormatUtil { * @param seconds Maximum video duration (seconds). * @return Time after conversion. */ - secondToTime(seconds: number) { - let time = `${CommonConstants.INITIAL_TIME_UNIT}${':'}${CommonConstants.INITIAL_TIME_UNIT}`; + secondToTime(seconds: number): string { let hourUnit = CommonConstants.TIME_UNIT * CommonConstants.TIME_UNIT; let hour = Math.floor(seconds / hourUnit); let minute = Math.floor((seconds - hour * hourUnit) / CommonConstants.TIME_UNIT); let second = seconds - hour * hourUnit - minute * CommonConstants.TIME_UNIT; - if (isNaN(second)) { - second = 0; - } if (hour > 0) { return `${this.padding(hour.toString())}${':'} ${this.padding(minute.toString())}${':'}${this.padding(second.toString())}`; @@ -40,7 +36,6 @@ class DateFormatUtil { } else { return `${CommonConstants.INITIAL_TIME_UNIT}${':'}${this.padding(second.toString())}`; } - return time; } /** @@ -49,9 +44,9 @@ class DateFormatUtil { * @param num Number to be converted. * @return Result after zero padding. */ - padding(num: string) { + padding(num: string): string { let length = CommonConstants.PADDING_LENGTH; - for (var len = (num.toString()).length; len < length; len = num.length) { + for (let len = (num.toString()).length; len < length; len = num.length) { num = `${CommonConstants.PADDING_STR}${num}`; } return num; diff --git a/Media/VideoPlayer/entry/src/main/ets/common/util/GlobalContext.ets b/Media/VideoPlayer/entry/src/main/ets/common/util/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..23f5130a61c9e0ac09c5d885cdcaa2c878e0d522 --- /dev/null +++ b/Media/VideoPlayer/entry/src/main/ets/common/util/GlobalContext.ets @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class GlobalContext { + private constructor() { + } + + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} \ No newline at end of file diff --git a/Media/VideoPlayer/entry/src/main/ets/common/util/Logger.ets b/Media/VideoPlayer/entry/src/main/ets/common/util/Logger.ets index 1c9c8262e834f7b05b8180cb93f8be9c7c09ef52..9916f7b198fb39379948177df037f57740ed688e 100644 --- a/Media/VideoPlayer/entry/src/main/ets/common/util/Logger.ets +++ b/Media/VideoPlayer/entry/src/main/ets/common/util/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Media/VideoPlayer/entry/src/main/ets/common/util/ScreenUtil.ets b/Media/VideoPlayer/entry/src/main/ets/common/util/ScreenUtil.ets index e5a2b02280a8960e2b6cf768024a9fdaee79d4ea..96e5a6193e9f43c47999dd0a567ee0a7ff532e8e 100644 --- a/Media/VideoPlayer/entry/src/main/ets/common/util/ScreenUtil.ets +++ b/Media/VideoPlayer/entry/src/main/ets/common/util/ScreenUtil.ets @@ -15,16 +15,19 @@ import Window from '@ohos.window'; import Logger from '../util/Logger'; +import { GlobalContext } from './GlobalContext'; class ScreenUtil { setScreenSize(): void { Window.getLastWindow(getContext(this)) - .then((windowClass) => { - globalThis.screenWidth = px2fp(windowClass.getWindowProperties().windowRect.width); - globalThis.screenHeight = px2fp(windowClass.getWindowProperties().windowRect.height); - globalThis.windowClass = windowClass; + .then((windowClass: Window.Window) => { + let screenWidth = px2fp(windowClass.getWindowProperties().windowRect.width); + let screenHeight = px2fp(windowClass.getWindowProperties().windowRect.height); + GlobalContext.getContext().setObject('screenWidth', screenWidth); + GlobalContext.getContext().setObject('screenHeight', screenHeight); + GlobalContext.getContext().setObject('windowClass', windowClass); }) - .catch((error) => { + .catch((error: Error) => { Logger.error('[ScreenUtil] Failed to obtain the window size. Cause: ' + JSON.stringify(error)); }) } diff --git a/Media/VideoPlayer/entry/src/main/ets/controller/VideoController.ets b/Media/VideoPlayer/entry/src/main/ets/controller/VideoController.ets index 1078d90f56d58e873351c709f69fc45314588f94..cda1e70d10ab2aee8d3517c3e4db57058bca4bbc 100644 --- a/Media/VideoPlayer/entry/src/main/ets/controller/VideoController.ets +++ b/Media/VideoPlayer/entry/src/main/ets/controller/VideoController.ets @@ -17,58 +17,66 @@ import media from '@ohos.multimedia.media'; import prompt from '@ohos.promptAction'; import Logger from '../common/util/Logger'; import DateFormatUtil from '../common/util/DateFormatUtil'; -import { CommonConstants, AvplayerStatus, Events } from '../common/constants/CommonConstants'; +import { CommonConstants, AvplayerStatus, Events, SliderMode } from '../common/constants/CommonConstants'; import { PlayConstants } from '../common/constants/PlayConstants'; +import { GlobalContext } from '../common/util/GlobalContext'; +import window from '@ohos.window'; +import { VideoItem } from '../viewmodel/VideoItem'; +import resourceManager from '@ohos.resourceManager'; +import { PlayerModel } from '../common/model/PlayerModel'; @Observed export class VideoController { - private avPlayer; - private duration: number; - private status: number; + public playerModel: PlayerModel; + private avPlayer: media.AVPlayer | null = null; + private duration: number = 0; + private status: number = -1; private loop: boolean = false; - private index: number; - private url: string; - private surfaceId: number; - private playSpeed: number = PlayConstants.PLAY_PAGE.PLAY_SPEED; - private seekTime: number = PlayConstants.PLAY_PROGRESS.SEEK_TIME; - private progressThis; - private playerThis; - private playPageThis; - private positionX: number = PlayConstants.PLAY_PAGE.POSITION_X; - private positionY: number = PlayConstants.PLAY_PAGE.POSITION_Y; + private index: number = 0; + private url?: resourceManager.RawFileDescriptor = {} as resourceManager.RawFileDescriptor; + private iUrl: string = ''; + private surfaceId: string = ''; + private seekTime: number = PlayConstants.PROGRESS_SEEK_TIME; + private positionX: number = PlayConstants.POSITION_X; + private positionY: number = PlayConstants.POSITION_Y; - constructor() { + constructor(playerModel: PlayerModel) { + this.playerModel = playerModel; this.createAVPlayer(); } /** * Creates a videoPlayer object. */ - createAVPlayer() { - media.createAVPlayer().then((avPlayer) => { - if (avPlayer) { - this.avPlayer = avPlayer; - this.bindState(); - } else { - Logger.error('[PlayVideoModel] createAvPlayer fail!'); - } - }); + async createAVPlayer() { + let avPlayer: media.AVPlayer = await media.createAVPlayer(); + this.avPlayer = avPlayer; + this.bindState(); } /** * AVPlayer binding event. */ - bindState() { - this.avPlayer.on(Events.STATE_CHANGE, async (state) => { - switch (state) { + async bindState() { + if (this.avPlayer === null) { + return; + } + this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => { + let avplayerStatus: string = state; + if (this.avPlayer === null) { + return; + } + switch (avplayerStatus) { case AvplayerStatus.IDLE: this.resetProgress(); - this.avPlayer.url = this.url; + if (this.iUrl) { + this.avPlayer.url = this.iUrl; + } else { + this.avPlayer.fdSrc = this.url; + } break; case AvplayerStatus.INITIALIZED: - if (!this.avPlayer.surfaceId) { - this.avPlayer.surfaceId = this.surfaceId; - } + this.avPlayer.surfaceId = this.surfaceId; this.avPlayer.prepare(); break; case AvplayerStatus.PREPARED: @@ -78,7 +86,7 @@ export class VideoController { this.duration = this.avPlayer.duration; break; case AvplayerStatus.PLAYING: - this.avPlayer.setVolume(this.playerThis.volume); + this.avPlayer.setVolume(this.playerModel.volume); this.setBright(); this.status = CommonConstants.STATUS_START; this.watchStatus(); @@ -88,23 +96,25 @@ export class VideoController { this.watchStatus(); break; case AvplayerStatus.COMPLETED: - this.duration = PlayConstants.PLAY_PLAYER.DURATION; + this.playerModel.playSpeed = PlayConstants.PLAY_SPEED; + this.duration = PlayConstants.PLAYER_DURATION; if (!this.loop) { - let curIndex = this.index + PlayConstants.PLAY_PLAYER.NEXT; - this.index = (curIndex === globalThis.videoList.length) ? - PlayConstants.PLAY_PLAYER.FIRST : curIndex; - this.url = globalThis.videoList[this.index].src; - } else { - this.url = this.avPlayer.url; + let curIndex = this.index + PlayConstants.PLAYER_NEXT; + let globalVideoList = GlobalContext.getContext().getObject('globalVideoList') as VideoItem[]; + this.index = (curIndex === globalVideoList.length) ? + PlayConstants.PLAYER_FIRST : curIndex; + if (this.iUrl) { + this.iUrl = globalVideoList[this.index].iSrc; + } else { + this.url = globalVideoList[this.index].src; + } } this.avPlayer.reset(); break; - case AvplayerStatus.STOPPED: - this.avPlayer.released(); + case AvplayerStatus.RELEASED: + this.avPlayer.release(); this.status = CommonConstants.STATUS_STOP; this.watchStatus(); - break; - case AvplayerStatus.RELEASED: Logger.info('[PlayVideoModel] state released called') break; default: @@ -115,7 +125,7 @@ export class VideoController { this.avPlayer.on(Events.TIME_UPDATE, (time: number) => { this.initProgress(time); }); - this.avPlayer.on(Events.ERROR, (error) => { + this.avPlayer.on(Events.ERROR, () => { this.playError(); }) } @@ -127,22 +137,39 @@ export class VideoController { * @param url Playback Path. * @param surfaceId Indicates the surface ID of the surfaceId. */ - firstPlay(index: number, url: string, surfaceId: number) { + async firstPlay(index: number, url: resourceManager.RawFileDescriptor, iUrl: string, surfaceId: string) { this.index = index; this.url = url; + this.iUrl = iUrl; this.surfaceId = surfaceId; - this.avPlayer.url = this.url; + if (this.avPlayer === null) { + await this.createAVPlayer(); + } + if (this.avPlayer !== null) { + if (this.iUrl) { + this.avPlayer.url = this.iUrl; + } else { + this.avPlayer.fdSrc = this.url; + } + } } /** - * Stop Playing. + * Release the video player. */ - stop() { - if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) { + release() { + if (this.avPlayer !== null) { this.avPlayer.release(); - return; } - this.avPlayer.stop(); + } + + /** + * Pause Playing. + */ + pause() { + if (this.avPlayer !== null) { + this.avPlayer.pause(); + } } /** @@ -158,21 +185,36 @@ export class VideoController { * @param playSpeed Current playback speed. */ setSpeed(playSpeed: number) { - this.playSpeed = playSpeed; - this.avPlayer.setSpeed(this.playSpeed); + if (this.avPlayer === null) { + return; + } + if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) { + return; + } + this.playerModel.playSpeed = playSpeed; + this.avPlayer.setSpeed(this.playerModel.playSpeed); } /** * Previous video. */ previousVideo() { + if (this.avPlayer === null) { + return; + } if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) { return; } - let curIndex = this.index - PlayConstants.PLAY_CONTROL.NEXT; - this.index = (curIndex === -PlayConstants.PLAY_CONTROL.NEXT) ? - (globalThis.videoList.length - PlayConstants.PLAY_CONTROL.NEXT) : curIndex; - this.url = globalThis.videoList[this.index].src; + this.playerModel.playSpeed = PlayConstants.PLAY_SPEED; + let globalVideoList = GlobalContext.getContext().getObject('globalVideoList') as VideoItem[]; + let curIndex = this.index - PlayConstants.CONTROL_NEXT; + this.index = (curIndex === -PlayConstants.CONTROL_NEXT) ? + (globalVideoList.length - PlayConstants.CONTROL_NEXT) : curIndex; + if (this.iUrl) { + this.iUrl = globalVideoList[this.index].iSrc; + } else { + this.url = globalVideoList[this.index].src; + } this.avPlayer.reset(); } @@ -180,13 +222,22 @@ export class VideoController { * Next video. */ nextVideo() { + if (this.avPlayer === null) { + return; + } if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) { return; } - let curIndex = this.index + PlayConstants.PLAY_CONTROL.NEXT; - this.index = (curIndex === globalThis.videoList.length) ? - PlayConstants.PLAY_CONTROL.FIRST : curIndex; - this.url = globalThis.videoList[this.index].src; + this.playerModel.playSpeed = PlayConstants.PLAY_SPEED; + let globalVideoList = GlobalContext.getContext().getObject('globalVideoList') as VideoItem[]; + let curIndex = this.index + PlayConstants.CONTROL_NEXT; + this.index = (curIndex === globalVideoList.length) ? + PlayConstants.CONTROL_FIRST : curIndex; + if (this.iUrl) { + this.iUrl = globalVideoList[this.index].iSrc; + } else { + this.url = globalVideoList[this.index].src; + } this.avPlayer.reset(); } @@ -194,6 +245,9 @@ export class VideoController { * Switching Between Video Play and Pause. */ switchPlayOrPause() { + if (this.avPlayer === null) { + return; + } if (this.status === CommonConstants.STATUS_START) { this.avPlayer.pause(); } else { @@ -208,15 +262,16 @@ export class VideoController { * @param mode Slider component change event. */ setSeekTime(value: number, mode: SliderChangeMode) { - if (mode === SliderChangeMode.Moving) { - // The current time is changed during dragging, and other parameters remain unchanged. - this.progressThis.progressVal = value; - this.progressThis.currentTime = DateFormatUtil.secondToTime(Math.floor(value * this.duration / - CommonConstants.ONE_HUNDRED / CommonConstants.A_THOUSAND)); + if (mode === Number(SliderMode.MOVING)) { + this.playerModel.progressVal = value; + this.playerModel.currentTime = DateFormatUtil.secondToTime(Math.floor(value * this.duration / + CommonConstants.ONE_HUNDRED / CommonConstants.A_THOUSAND)); } - if (mode === SliderChangeMode.End) { + if (mode === Number(SliderMode.END) || mode === Number(SliderMode.CLICK)) { this.seekTime = value * this.duration / CommonConstants.ONE_HUNDRED; - this.avPlayer.seek(this.seekTime, media.SeekMode.SEEK_PREV_SYNC); + if (this.avPlayer !== null) { + this.avPlayer.seek(this.seekTime, media.SeekMode.SEEK_PREV_SYNC); + } } } @@ -224,7 +279,8 @@ export class VideoController { * Setting the brightness. */ setBright() { - globalThis.windowClass.setWindowBrightness(this.playerThis.bright) + let windowClass = GlobalContext.getContext().getObject('windowClass') as window.Window; + windowClass.setWindowBrightness(this.playerModel.bright); } /** @@ -234,24 +290,6 @@ export class VideoController { return this.status; } - /** - * Transfer this on the playProgress page. - * - * @param progressThis PlayProgress this object. - */ - initProgressThis(progressThis) { - this.progressThis = progressThis; - } - - /** - * Pass this on the playback page. - * - * @param playerThis PlayPlayer this object. - */ - initPlayerThis(playerThis) { - this.playerThis = playerThis; - } - /** * Initialization progress bar. * @@ -260,18 +298,18 @@ export class VideoController { initProgress(time: number) { let nowSeconds = Math.floor(time / CommonConstants.A_THOUSAND); let totalSeconds = Math.floor(this.duration / CommonConstants.A_THOUSAND); - this.progressThis.currentTime = DateFormatUtil.secondToTime(nowSeconds); - this.progressThis.totalTime = DateFormatUtil.secondToTime(totalSeconds); - this.progressThis.progressVal = Math.floor(nowSeconds * CommonConstants.ONE_HUNDRED / totalSeconds); + this.playerModel.currentTime = DateFormatUtil.secondToTime(nowSeconds); + this.playerModel.totalTime = DateFormatUtil.secondToTime(totalSeconds); + this.playerModel.progressVal = Math.floor(nowSeconds * CommonConstants.ONE_HUNDRED / totalSeconds); } /** * Reset progress bar data. */ resetProgress() { - this.seekTime = PlayConstants.PLAY_PROGRESS.SEEK_TIME; - this.progressThis.currentTime = PlayConstants.PLAY_PROGRESS.CURRENT_TIME; - this.progressThis.progressVal = PlayConstants.PLAY_PROGRESS.PROGRESS_VAL; + this.seekTime = PlayConstants.PROGRESS_SEEK_TIME; + this.playerModel.currentTime = PlayConstants.PROGRESS_CURRENT_TIME; + this.playerModel.progressVal = PlayConstants.PROGRESS_PROGRESS_VAL; } /** @@ -279,7 +317,10 @@ export class VideoController { * * @param event Gesture event. */ - onVolumeActionStart(event: GestureEvent) { + onVolumeActionStart(event?: GestureEvent) { + if (!event) { + return; + } this.positionX = event.offsetX; } @@ -288,7 +329,10 @@ export class VideoController { * * @param event Gesture event. */ - onBrightActionStart(event: GestureEvent) { + onBrightActionStart(event?: GestureEvent) { + if (!event) { + return; + } this.positionY = event.offsetY; } @@ -297,36 +341,50 @@ export class VideoController { * * @param event Gesture event. */ - onVolumeActionUpdate(event: GestureEvent) { + onVolumeActionUpdate(event?: GestureEvent) { + if (!event) { + return; + } + if (this.avPlayer === null) { + return; + } if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) { return; } - if (!this.playerThis.brightShow) { - this.playerThis.volumeShow = true; - let changeVolume = (event.offsetX - this.positionX) / globalThis.screenWidth; - let currentVolume = this.playerThis.volume + changeVolume; - let volumeMinFlag = currentVolume <= PlayConstants.PLAY_PAGE.MIN_VALUE; - let volumeMaxFlag = currentVolume > PlayConstants.PLAY_PAGE.MAX_VALUE; - this.playerThis.volume = volumeMinFlag ? PlayConstants.PLAY_PAGE.MIN_VALUE : - (volumeMaxFlag ? PlayConstants.PLAY_PAGE.MAX_VALUE : currentVolume); - this.avPlayer.setVolume(this.playerThis.volume); + if (this.playerModel.brightShow === false) { + this.playerModel.volumeShow = true; + let screenWidth = GlobalContext.getContext().getObject('screenWidth') as number; + let changeVolume = (event.offsetX - this.positionX) / screenWidth; + let volume: number = this.playerModel.volume; + let currentVolume = volume + changeVolume; + let volumeMinFlag = currentVolume <= PlayConstants.MIN_VALUE; + let volumeMaxFlag = currentVolume > PlayConstants.MAX_VALUE; + this.playerModel.volume = volumeMinFlag ? PlayConstants.MIN_VALUE : + (volumeMaxFlag ? PlayConstants.MAX_VALUE : currentVolume); + this.avPlayer.setVolume(this.playerModel.volume); this.positionX = event.offsetX; } } + /** * Gesture method onActionUpdate. * * @param event Gesture event. */ - onBrightActionUpdate(event: GestureEvent) { - if (!this.playerThis.volumeShow) { - this.playerThis.brightShow = true; - let changeBright = (this.positionY - event.offsetY) / globalThis.screenHeight; - let currentBright = this.playerThis.bright + changeBright; - let brightMinFlag = currentBright <= PlayConstants.PLAY_PAGE.MIN_VALUE; - let brightMaxFlag = currentBright > PlayConstants.PLAY_PAGE.MAX_VALUE; - this.playerThis.bright = brightMinFlag ? PlayConstants.PLAY_PAGE.MIN_VALUE : - (brightMaxFlag ? PlayConstants.PLAY_PAGE.MAX_VALUE : currentBright); + onBrightActionUpdate(event?: GestureEvent) { + if (!event) { + return; + } + if (this.playerModel.volumeShow === false) { + this.playerModel.brightShow = true; + let screenHeight = GlobalContext.getContext().getObject('screenHeight') as number; + let changeBright = (this.positionY - event.offsetY) / screenHeight; + let bright: number = this.playerModel.bright; + let currentBright = bright + changeBright; + let brightMinFlag = currentBright <= PlayConstants.MIN_VALUE; + let brightMaxFlag = currentBright > PlayConstants.MAX_VALUE; + this.playerModel.bright = brightMinFlag ? PlayConstants.MIN_VALUE : + (brightMaxFlag ? PlayConstants.MAX_VALUE : currentBright); this.setBright(); this.positionY = event.offsetY; } @@ -337,21 +395,22 @@ export class VideoController { */ onActionEnd() { setTimeout(() => { - this.playerThis.volumeShow = false; - this.playerThis.brightShow = false; - this.positionX = PlayConstants.PLAY_PAGE.POSITION_X; - this.positionY = PlayConstants.PLAY_PAGE.POSITION_Y; - }, PlayConstants.PLAY_PAGE.DISAPPEAR_TIME); + this.playerModel.volumeShow = false; + this.playerModel.brightShow = false; + this.positionX = PlayConstants.POSITION_X; + this.positionY = PlayConstants.POSITION_Y; + }, PlayConstants.DISAPPEAR_TIME); } /** * Sets whether the screen is a constant based on the playback status. */ watchStatus() { + let windowClass = GlobalContext.getContext().getObject('windowClass') as window.Window; if (this.status === CommonConstants.STATUS_START) { - globalThis.windowClass.setWindowKeepScreenOn(true); + windowClass.setWindowKeepScreenOn(true); } else { - globalThis.windowClass.setWindowKeepScreenOn(false); + windowClass.setWindowKeepScreenOn(false); } } @@ -359,28 +418,22 @@ export class VideoController { * Sets the playback page size based on the video size. */ setVideoSize() { + if (this.avPlayer === null) { + return; + } if (this.avPlayer.height > this.avPlayer.width) { - this.playPageThis.videoWidth = PlayConstants.PLAY_PAGE.PLAY_PLAYER_HEIGHT_FULL; - this.playPageThis.videoHeight = PlayConstants.PLAY_PAGE.PLAY_PLAYER_HEIGHT_FULL; - this.playPageThis.videoPosition = FlexAlign.Start; - this.playPageThis.videoMargin = PlayConstants.PLAY_PAGE.HEIGHT; + this.playerModel.videoWidth = PlayConstants.PLAY_PLAYER_HEIGHT_FULL; + this.playerModel.videoHeight = PlayConstants.PLAY_PLAYER_HEIGHT_FULL; + this.playerModel.videoPosition = FlexAlign.Start; + this.playerModel.videoMargin = PlayConstants.HEIGHT; } else { - this.playPageThis.videoWidth = CommonConstants.FULL_PERCENT; - this.playPageThis.videoHeight = PlayConstants.PLAY_PAGE.PLAY_PLAYER_HEIGHT; - this.playPageThis.videoPosition = FlexAlign.Center; - this.playPageThis.videoMargin = PlayConstants.PLAY_PAGE.MARGIN_ZERO; + this.playerModel.videoWidth = CommonConstants.FULL_PERCENT; + this.playerModel.videoHeight = PlayConstants.PLAY_PLAYER_HEIGHT; + this.playerModel.videoPosition = FlexAlign.Center; + this.playerModel.videoMargin = PlayConstants.MARGIN_ZERO; } } - /** - * Obtains the this object of the PlayPage. - * - * @param playPageThis This object of PlayPage. - */ - initPlayPageThis(playPageThis) { - this.playPageThis = playPageThis; - } - /** * An error is reported during network video playback. */ diff --git a/Media/VideoPlayer/entry/src/main/ets/entryability/EntryAbility.ts b/Media/VideoPlayer/entry/src/main/ets/entryability/EntryAbility.ts index 38b920161c1303d7a01fdf726b66ab3dddecb9a5..649863d424be226266bb7e2c485506b3044c5bf8 100644 --- a/Media/VideoPlayer/entry/src/main/ets/entryability/EntryAbility.ts +++ b/Media/VideoPlayer/entry/src/main/ets/entryability/EntryAbility.ts @@ -1,8 +1,6 @@ import UIAbility from '@ohos.app.ability.UIAbility'; import hilog from '@ohos.hilog'; import window from '@ohos.window'; -import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; -import { Permissions } from '@ohos.abilityAccessCtrl'; export default class EntryAbility extends UIAbility { onCreate(want, launchParam) { @@ -17,9 +15,6 @@ export default class EntryAbility extends UIAbility { // Main window is created, set main page for this ability hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); - let context = this.context; - globalThis.resourceManager = context.resourceManager; - windowStage.loadContent('pages/HomePage', (err, data) => { if (err.code) { hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); diff --git a/Media/VideoPlayer/entry/src/main/ets/pages/HomePage.ets b/Media/VideoPlayer/entry/src/main/ets/pages/HomePage.ets index cb0d2d30bf2ef60a58b676e66cba0b26eda40b3b..6b441c14e7a04ddb9154426268e1ca9ef6013d04 100644 --- a/Media/VideoPlayer/entry/src/main/ets/pages/HomePage.ets +++ b/Media/VideoPlayer/entry/src/main/ets/pages/HomePage.ets @@ -17,35 +17,37 @@ import ScreenUtil from '../common/util/ScreenUtil'; import { HomeConstants } from '../common/constants/HomeConstants'; import { CommonConstants } from '../common/constants/CommonConstants'; import { HomeTabContent } from '../view/HomeTabContent'; +import HomeVideoListModel from '../viewmodel/HomeVideoListModel'; @Entry @Component struct HomePage { - @State currentIndex: number = HomeConstants.HOME_TAB.CURRENT_INDEX; + @State currentIndex: number = HomeConstants.CURRENT_INDEX; private controller: TabsController = new TabsController(); - aboutToAppear() { + async aboutToAppear() { ScreenUtil.setScreenSize(); } - @Builder TabBuilder(index: number, name: Resource) { + @Builder + TabBuilder(index: number, name: Resource) { Column() { Text(name) .fontColor(this.currentIndex === index ? - $r('app.color.index_tab_selected_font_color') : $r('app.color.index_tab_font_color')) + $r('app.color.index_tab_selected_font_color') : $r('app.color.index_tab_font_color')) .fontSize($r('app.float.home_page_font_size')) .fontWeight(this.currentIndex === index ? - HomeConstants.HOME_TAB.FONT_WEIGHT_SELECT : HomeConstants.HOME_TAB.FONT_WEIGHT_UNSELECT) - .lineHeight(HomeConstants.HOME_TAB.LINE_HEIGHT) + HomeConstants.FONT_WEIGHT_SELECT : HomeConstants.FONT_WEIGHT_UNSELECT) + .lineHeight(HomeConstants.LINE_HEIGHT) .margin({ - top: HomeConstants.HOME_TAB.MARGIN_TOP_TWO, - bottom: HomeConstants.HOME_TAB.MARGIN_BOTTOM + top: HomeConstants.MARGIN_TOP_TWO, + bottom: HomeConstants.MARGIN_BOTTOM }) Divider() - .strokeWidth(HomeConstants.HOME_TAB.STROKE_WIDTH) + .strokeWidth(HomeConstants.STROKE_WIDTH) .color($r('app.color.index_tab_selected_font_color')) .opacity(this.currentIndex === index ? - HomeConstants.HOME_TAB.TAB_BAR_SECOND : HomeConstants.HOME_TAB.TAB_BAR_FIRST) + HomeConstants.TAB_BAR_SECOND : HomeConstants.TAB_BAR_FIRST) } .width(CommonConstants.FULL_PERCENT) } @@ -54,17 +56,17 @@ struct HomePage { Column() { Tabs({ barPosition: BarPosition.Start, controller: this.controller }) { TabContent() { - HomeTabContent({ currIndex: HomeConstants.HOME_TAB.TAB_BAR_FIRST }); - }.tabBar(this.TabBuilder(HomeConstants.HOME_TAB.TAB_BAR_FIRST, $r('app.string.index_tab_local_video'))) + HomeTabContent({ currIndex: HomeConstants.TAB_BAR_FIRST }); + }.tabBar(this.TabBuilder(HomeConstants.TAB_BAR_FIRST, $r('app.string.index_tab_local_video'))) TabContent() { - HomeTabContent({ currIndex: HomeConstants.HOME_TAB.TAB_BAR_SECOND }); - }.tabBar(this.TabBuilder(HomeConstants.HOME_TAB.TAB_BAR_SECOND, $r('app.string.index_tab_internet_video'))) + HomeTabContent({ currIndex: HomeConstants.TAB_BAR_SECOND }); + }.tabBar(this.TabBuilder(HomeConstants.TAB_BAR_SECOND, $r('app.string.index_tab_internet_video'))) } .vertical(false) .barMode(BarMode.Fixed) - .barWidth(HomeConstants.HOME_TAB.BAR_WIDTH) - .barHeight(HomeConstants.HOME_TAB.BAR_HEIGHT) + .barWidth(HomeConstants.BAR_WIDTH) + .barHeight(HomeConstants.BAR_HEIGHT) .onChange((index: number) => { this.currentIndex = index; }) diff --git a/Media/VideoPlayer/entry/src/main/ets/pages/PlayPage.ets b/Media/VideoPlayer/entry/src/main/ets/pages/PlayPage.ets index cdfe010cb55dc0ad0d9bc94d66f6eb949b7d5e17..92e1b39c1a0a4a90affe37134a89258b2e79b3d6 100644 --- a/Media/VideoPlayer/entry/src/main/ets/pages/PlayPage.ets +++ b/Media/VideoPlayer/entry/src/main/ets/pages/PlayPage.ets @@ -21,62 +21,68 @@ import { PlayProgress } from '../view/PlayProgress'; import { VideoController } from '../controller/VideoController'; import { CommonConstants } from '../common/constants/CommonConstants'; import { PlayConstants } from '../common/constants/PlayConstants'; +import resourceManager from '@ohos.resourceManager'; +import { PlayerModel } from '../common/model/PlayerModel'; @Entry @Component struct PlayPage { - @State videoHeight: string = PlayConstants.PLAY_PAGE.PLAY_PLAYER_HEIGHT; - @State videoWidth: string = CommonConstants.FULL_PERCENT; - @State videoMargin: string = PlayConstants.PLAY_PAGE.MARGIN_ZERO; - @State videoPosition: FlexAlign = FlexAlign.Center; - private playVideoModel: VideoController = new VideoController(); - @Provide src: string = router.getParams()['src']; - @Provide index: number = router.getParams()['index']; - @Provide type: number = router.getParams()['type']; + @Provide playerModel: PlayerModel = new PlayerModel(); + @Provide src: resourceManager.RawFileDescriptor = {} as resourceManager.RawFileDescriptor; + @Provide iSrc: string = ''; + @Provide index: number = 0; + @Provide type: number = 0; @Provide status: number = CommonConstants.STATUS_START; + playVideoModel: VideoController = new VideoController(this.playerModel); private panOptionBright: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Vertical }); private panOptionVolume: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Horizontal }); - onPageHide() { - this.status = CommonConstants.STATUS_PAUSE; - globalThis.windowClass.setWindowKeepScreenOn(false); + aboutToAppear() { + let params = router.getParams() as Record; + this.src = params.src as resourceManager.RawFileDescriptor; + this.iSrc = params.iSrc as string; + this.index = params.index as number; + this.type = params.type as number; } - aboutToAppear() { - this.playVideoModel.initPlayPageThis(this); + aboutToDisappear() { + this.playVideoModel.release(); } - onBackPress() { - this.playVideoModel.stop(); + onPageHide() { + this.status = CommonConstants.STATUS_PAUSE; + this.playVideoModel.pause(); } build() { Stack() { - Column () { - Column(){ + Column() { + Column() { } - .height(this.videoMargin) + .height(this.playerModel.videoMargin) + PlayPlayer({ playVideoModel: this.playVideoModel }) - .width(this.videoWidth) - .height(this.videoHeight) + .width(this.playerModel.videoWidth) + .height(this.playerModel.videoHeight) } .height(CommonConstants.FULL_PERCENT) .width(CommonConstants.FULL_PERCENT) - .justifyContent(this.videoPosition) + .justifyContent(this.playerModel.videoPosition) .zIndex(0) + Column() { PlayTitle({ playVideoModel: this.playVideoModel }) .width(CommonConstants.FULL_PERCENT) - .height(PlayConstants.PLAY_PAGE.HEIGHT) + .height(PlayConstants.HEIGHT) Column() .width(CommonConstants.FULL_PERCENT) - .height(PlayConstants.PLAY_PAGE.COLUMN_HEIGHT_ONE) + .height(PlayConstants.COLUMN_HEIGHT_ONE) .gesture( PanGesture(this.panOptionBright) - .onActionStart((event: GestureEvent) => { + .onActionStart((event?: GestureEvent) => { this.playVideoModel.onBrightActionStart(event); }) - .onActionUpdate((event: GestureEvent) => { + .onActionUpdate((event?: GestureEvent) => { this.playVideoModel.onBrightActionUpdate(event); }) .onActionEnd(() => { @@ -86,16 +92,17 @@ struct PlayPage { Column() { } .width(CommonConstants.FULL_PERCENT) - .height(PlayConstants.PLAY_PAGE.PLAY_PLAYER_HEIGHT) + .height(PlayConstants.PLAY_PLAYER_HEIGHT) + Column() .width(CommonConstants.FULL_PERCENT) - .height(PlayConstants.PLAY_PAGE.COLUMN_HEIGHT_TWO) + .height(PlayConstants.COLUMN_HEIGHT_TWO) .gesture( PanGesture(this.panOptionVolume) - .onActionStart((event: GestureEvent) => { + .onActionStart((event?: GestureEvent) => { this.playVideoModel.onVolumeActionStart(event); }) - .onActionUpdate((event: GestureEvent) => { + .onActionUpdate((event?: GestureEvent) => { this.playVideoModel.onVolumeActionUpdate(event); }) .onActionEnd(() => { @@ -104,10 +111,10 @@ struct PlayPage { ) PlayControl({ playVideoModel: this.playVideoModel }) .width(CommonConstants.FULL_PERCENT) - .height(PlayConstants.PLAY_PAGE.HEIGHT) + .height(PlayConstants.HEIGHT) PlayProgress({ playVideoModel: this.playVideoModel }) .width(CommonConstants.FULL_PERCENT) - .height(PlayConstants.PLAY_PAGE.PLAY_PROGRESS_HEIGHT) + .height(PlayConstants.PLAY_PROGRESS_HEIGHT) } .height(CommonConstants.FULL_PERCENT) .width(CommonConstants.FULL_PERCENT) diff --git a/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContent.ets b/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContent.ets index 459da5c4fe5ec0cc1ec62d89e75ca70865d43e41..b72647eaafecb01728217a508334a448273191c5 100644 --- a/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContent.ets +++ b/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContent.ets @@ -13,20 +13,22 @@ * limitations under the License. */ -import { VideoBean } from '../common/bean/VideoBean'; import { HomeTabContentList } from './HomeTabContentList'; import { HomeTabContentButton } from './HomeTabContentButton'; import { CommonConstants } from '../common/constants/CommonConstants'; +import { HomeDialogModel } from '../viewmodel/HomeDialogModel'; +import { HomeTabModel } from '../common/model/HomeTabModel'; @Component export struct HomeTabContent { - private currIndex: number; - @Provide videoList: Array = []; + private currIndex: number = 0; + @Provide homeTabModel: HomeTabModel = new HomeTabModel(); + homeDialogModel: HomeDialogModel = new HomeDialogModel(this.homeTabModel); build() { Column() { - HomeTabContentList({currIndex: this.currIndex}); - HomeTabContentButton({currIndex: this.currIndex}); + HomeTabContentList({ currIndex: this.currIndex}); + HomeTabContentButton({ currIndex: this.currIndex, homeDialogModel: this.homeDialogModel }); } .width(CommonConstants.FULL_PERCENT) .height(CommonConstants.FULL_PERCENT) diff --git a/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentButton.ets b/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentButton.ets index cbec9d075d6b4ebe5cb48fcf3068d575e2111067..b81d662d70c79a21ff464edd2606cf41c403599a 100644 --- a/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentButton.ets +++ b/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentButton.ets @@ -14,39 +14,42 @@ */ import { HomeTabContentDialog } from './HomeTabContentDialog'; -import { VideoBean } from '../common/bean/VideoBean'; +import { VideoItem } from '../viewmodel/VideoItem'; import HomeVideoListModel from '../viewmodel/HomeVideoListModel'; import { CommonConstants } from '../common/constants/CommonConstants'; import { HomeConstants } from '../common/constants/HomeConstants'; +import { GlobalContext } from '../common/util/GlobalContext'; +import { HomeTabModel } from '../common/model/HomeTabModel'; +import { HomeDialogModel } from '../viewmodel/HomeDialogModel'; @Component export struct HomeTabContentButton { - private currIndex: number; - @Consume videoList: Array; - @State name: string = ''; - @State src: string = ''; + private currIndex: number = 0; + private homeDialogModel: HomeDialogModel | null = null; + @Consume homeTabModel: HomeTabModel; dialogController: CustomDialogController = new CustomDialogController({ - builder: HomeTabContentDialog({ - confirm: this.confirm, - name: $name, - src: $src, - videoList: $videoList + builder:HomeTabContentDialog({ + homeDialogModel: this.homeDialogModel! }), autoCancel: true, alignment: DialogAlignment.Default, offset: { - dx: HomeConstants.INTERNET_ADD_DIALOG.OFFSET_DX, - dy: HomeConstants.INTERNET_ADD_DIALOG.OFFSET_DY + dx: HomeConstants.OFFSET_DX, + dy: HomeConstants.OFFSET_DY }, - gridCount: HomeConstants.INTERNET_ADD_DIALOG.GRID_COUNT, + gridCount: HomeConstants.GRID_COUNT, customStyle: false }); - confirm() { - HomeVideoListModel.setInternetVideo(this.name, this.src); - this.videoList = globalThis.videoInternetList; - this.src = ''; - this.name = ''; + aboutToAppear(){ + this.homeTabModel.confirm = () =>{ + HomeVideoListModel.setInternetVideo(this.homeTabModel.name, this.homeTabModel.src); + let videoInternetList = GlobalContext.getContext().getObject('videoInternetList') as VideoItem[]; + this.homeTabModel.videoList = videoInternetList; + this.homeTabModel.src = ''; + this.homeTabModel.name = ''; + }; + this.homeTabModel.controller = this.dialogController; } build() { @@ -57,18 +60,18 @@ export struct HomeTabContentButton { }) .borderRadius($r('app.float.tab_border_radius')) .fontSize($r('app.float.button_font_size')) - .height(HomeConstants.HOME_TAB_BUTTON.HEIGHT) + .height(HomeConstants.TAB_BUTTON_HEIGHT) .backgroundColor($r('app.color.button_back_ground_color')) .onClick(async () => { if (this.currIndex === 0) { - this.videoList = await HomeVideoListModel.getLocalVideo(); + this.homeTabModel.videoList = await HomeVideoListModel.getLocalVideo(); } else { this.dialogController.open(); } }) } .width(CommonConstants.FULL_PERCENT) - .height(HomeConstants.HOME_TAB_BUTTON.COLUMN_HEIGHT) + .height(HomeConstants.TAB_COLUMN_HEIGHT) .justifyContent(FlexAlign.Center) } } \ No newline at end of file diff --git a/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentDialog.ets b/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentDialog.ets index f4671b8fe72d1850e50ff0bb1fcf692ed1671cd7..c4d32822e47ff5ed44fe4226ff8e61a4f34af487 100644 --- a/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentDialog.ets +++ b/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentDialog.ets @@ -13,46 +13,42 @@ * limitations under the License. */ -import { VideoBean } from '../common/bean/VideoBean'; import { HomeDialogModel } from '../viewmodel/HomeDialogModel'; import { CommonConstants } from '../common/constants/CommonConstants'; import { HomeConstants } from '../common/constants/HomeConstants'; +import { HomeTabModel } from '../common/model/HomeTabModel'; @CustomDialog export struct HomeTabContentDialog { - private dialogModel: HomeDialogModel = new HomeDialogModel(this); - @State linkCheck: Resource = $r('app.string.link_check'); - @State confirmAdd: Resource = $r('app.string.confirm_add'); - @State loadColor: Resource = $r('app.color.index_tab_selected_font_color'); - @Link name: string; - @Link src: string; - @Link videoList: Array; - controller: CustomDialogController; - confirm: () => void; + private homeDialogModel?: HomeDialogModel | null = null;; + @Consume homeTabModel: HomeTabModel; + controller: CustomDialogController = new CustomDialogController({ + builder:HomeTabContentDialog({homeDialogModel:this.homeDialogModel!}) + }); build() { Column() { - TextInput({ placeholder: $r('app.string.link_placeholder'), text: this.src }) - .height(HomeConstants.INTERNET_ADD_DIALOG.TEXT_HEIGHT) + TextInput({ placeholder: $r('app.string.link_placeholder'), text: this.homeTabModel.src }) + .height(HomeConstants.TEXT_HEIGHT) .width(CommonConstants.NINETY_PERCENT) - .margin({ top: HomeConstants.INTERNET_ADD_DIALOG.TEXT_MARGIN_TOP }) + .margin({ top: HomeConstants.TEXT_MARGIN_TOP }) .onChange((value: string) => { - this.src = value; + this.homeTabModel.src = value; }) - TextInput({ placeholder: $r('app.string.name_placeholder'), text: this.name }) - .height(HomeConstants.INTERNET_ADD_DIALOG.TEXT_HEIGHT) + TextInput({ placeholder: $r('app.string.name_placeholder'), text: this.homeTabModel.name }) + .height(HomeConstants.TEXT_HEIGHT) .width(CommonConstants.NINETY_PERCENT) - .margin({ top: HomeConstants.INTERNET_ADD_DIALOG.TEXT_MARGIN_TOP }) + .margin({ top: HomeConstants.TEXT_MARGIN_TOP }) .onChange((value: string) => { - this.name = value; + this.homeTabModel.name = value; }) Flex({ justifyContent: FlexAlign.SpaceAround }) { - Text(this.linkCheck) + Text(this.homeTabModel.linkCheck) .fontSize($r('app.float.dialog_font_size')) - .fontColor(this.loadColor) + .fontColor(this.homeTabModel.loadColor) .onClick(() => { - if (this.dialogModel.checkSrcNull()) { - this.dialogModel.checkSrcValidity(0); + if (this.homeDialogModel!.checkSrcNull()) { + this.homeDialogModel!.checkSrcValidity(0); } }) Divider() @@ -64,12 +60,12 @@ export struct HomeTabContentDialog { left: $r('app.float.dialog_divider_margin_left'), right: $r('app.float.dialog_divider_margin_left') }) - Text(this.confirmAdd) + Text(this.homeTabModel.confirmAdd) .fontSize($r('app.float.dialog_font_size')) - .fontColor(this.loadColor) + .fontColor(this.homeTabModel.loadColor) .onClick(() => { - if (this.dialogModel.checkSrcNull() && this.dialogModel.checkNameNull()) { - this.dialogModel.checkSrcValidity(1); + if (this.homeDialogModel!.checkSrcNull() && this.homeDialogModel!.checkNameNull()) { + this.homeDialogModel!.checkSrcValidity(1); } }) } diff --git a/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentList.ets b/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentList.ets index 5c24a412e7e16f29241ced51b1990e5c2781839c..bce55d66203133fc5519de7f82990b317241ab5d 100644 --- a/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentList.ets +++ b/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentList.ets @@ -15,54 +15,59 @@ import router from '@ohos.router'; import Logger from '../common/util/Logger'; -import { VideoBean } from '../common/bean/VideoBean'; +import { VideoItem } from '../viewmodel/VideoItem'; import HomeVideoListModel from '../viewmodel/HomeVideoListModel'; import { HomeConstants } from '../common/constants/HomeConstants'; import { CommonConstants } from '../common/constants/CommonConstants'; import { HomeTabContentListItem } from './HomeTabContentListItem'; +import { GlobalContext } from '../common/util/GlobalContext'; +import resourceManager from '@ohos.resourceManager'; +import { HomeTabModel } from '../common/model/HomeTabModel'; @Component export struct HomeTabContentList { - private currIndex: number; - @Consume videoList: Array; - @State item: VideoBean = undefined; + private currIndex: number = 0; + @Consume homeTabModel: HomeTabModel; + @State item: VideoItem = new VideoItem('video1', {} as resourceManager.RawFileDescriptor, 'video1.mp4'); async aboutToAppear() { if (this.currIndex === CommonConstants.TYPE_LOCAL) { - this.videoList = await HomeVideoListModel.getLocalVideo(); + this.homeTabModel.videoList = await HomeVideoListModel.getLocalVideo(); } else { - this.videoList = globalThis.videoInternetList; + let videoInternetList = GlobalContext.getContext().getObject('videoInternetList') as VideoItem[]; + this.homeTabModel.videoList = videoInternetList; } } build() { Column() { List({ - space: HomeConstants.HOME_TAB_LIST.LIST_SPACE, - initialIndex: HomeConstants.HOME_TAB_LIST.LIST_INITIAL_INDEX + space: HomeConstants.LIST_SPACE, + initialIndex: HomeConstants.LIST_INITIAL_INDEX }) { - ForEach(this.videoList, (item: VideoBean, index: number) => { + ForEach(this.homeTabModel.videoList, (item: VideoItem, index?: number) => { ListItem() { - HomeTabContentListItem({item: item}); + HomeTabContentListItem({ item: item }); }.onClick(() => { - globalThis.videoList = this.videoList; + GlobalContext.getContext().setObject('globalVideoList', this.homeTabModel.videoList); router.pushUrl({ url: CommonConstants.PAGE, params: { src: item.src, + iSrc: item.iSrc, index: index, type: this.currIndex } - }).catch(err => { + }).catch((err: Error) => { Logger.error('[IndexTabLocalList] router error: ' + JSON.stringify(err)) }); }) - }, item => JSON.stringify(item)) + }, (item: VideoItem) => JSON.stringify(item)) } .backgroundColor(Color.White) .borderRadius($r('app.float.list_border_radius')) } - .width(HomeConstants.HOME_TAB_LIST.COLUMN_WIDTH) + .width(HomeConstants.COLUMN_WIDTH) .height(CommonConstants.NINETY_PERCENT) } } \ No newline at end of file diff --git a/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentListItem.ets b/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentListItem.ets index 6466c9024a50e1a84c7221aef128d2f076c9b770..35befec4902e4631f71f3bab0bc9160b58c88a22 100644 --- a/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentListItem.ets +++ b/Media/VideoPlayer/entry/src/main/ets/view/HomeTabContentListItem.ets @@ -13,19 +13,20 @@ * limitations under the License. */ -import { VideoBean } from '../common/bean/VideoBean'; +import { VideoItem } from '../viewmodel/VideoItem'; import { HomeConstants } from '../common/constants/HomeConstants'; import { CommonConstants } from '../common/constants/CommonConstants'; +import resourceManager from '@ohos.resourceManager'; @Component export struct HomeTabContentListItem { - private item: VideoBean; + private item: VideoItem = new VideoItem('video1', {} as resourceManager.RawFileDescriptor, 'video1.mp4'); build() { Row() { Image(this.item.pixelMap === undefined ? $r('app.media.ic_internet') : this.item.pixelMap) - .height(HomeConstants.HOME_TAB_LIST.IMAGE_HEIGHT) - .width(HomeConstants.HOME_TAB_LIST.IMAGE_WIDTH) + .height(HomeConstants.IMAGE_HEIGHT) + .width(HomeConstants.IMAGE_WIDTH) .margin({ left: $r('app.float.item_image_margin_left') }) .borderRadius($r('app.float.image_border_radius')) Column() { @@ -43,7 +44,7 @@ export struct HomeTabContentListItem { .alignItems(HorizontalAlign.Start) Divider() - .strokeWidth(HomeConstants.HOME_TAB_LIST.DIVIDER_STROKE_WIDTH) + .strokeWidth(HomeConstants.DIVIDER_STROKE_WIDTH) .color($r('app.color.divider_color')) .margin({ left: $r('app.float.item_divider_margin_left'), @@ -51,9 +52,9 @@ export struct HomeTabContentListItem { }) } .height(CommonConstants.FULL_PERCENT) - .width(HomeConstants.HOME_TAB_LIST.LIST_ITEM_ROW_COLUMN_WIDTH) + .width(HomeConstants.LIST_ITEM_ROW_COLUMN_WIDTH) } .width(CommonConstants.FULL_PERCENT) - .height(HomeConstants.HOME_TAB_LIST.LIST_ITEM_ROW_HEIGHT) + .height(HomeConstants.LIST_ITEM_ROW_HEIGHT) } } \ No newline at end of file diff --git a/Media/VideoPlayer/entry/src/main/ets/view/PlayControl.ets b/Media/VideoPlayer/entry/src/main/ets/view/PlayControl.ets index 662beb8035e3b1b3d84d2ac2dbdfe7b9dd60b54a..3f10ae7c4ff987c9f81e4216dc3c62e1586b219e 100644 --- a/Media/VideoPlayer/entry/src/main/ets/view/PlayControl.ets +++ b/Media/VideoPlayer/entry/src/main/ets/view/PlayControl.ets @@ -19,7 +19,7 @@ import { PlayConstants } from '../common/constants/PlayConstants'; @Component export struct PlayControl { - private playVideoModel: VideoController; + private playVideoModel?: VideoController; @Consume status: number; build() { @@ -29,30 +29,37 @@ export struct PlayControl { .width($r('app.float.control_image_width')) .aspectRatio(CommonConstants.ASPECT_RATIO) .onClick(async () => { - this.playVideoModel.previousVideo(); + if (this.playVideoModel !== null) { + this.playVideoModel!.previousVideo(); + } this.status = CommonConstants.STATUS_START; }) Column() { Image(this.status === CommonConstants.STATUS_START ? - $r('app.media.ic_pause') : $r('app.media.ic_play')) + $r('app.media.ic_pause') : $r('app.media.ic_play')) .width($r('app.float.control_image_width')) .aspectRatio(CommonConstants.ASPECT_RATIO) .onClick(async () => { - let curStatus = (this.playVideoModel.getStatus() === CommonConstants.STATUS_START); - this.status = curStatus ? CommonConstants.STATUS_PAUSE : CommonConstants.STATUS_START; - await this.playVideoModel.switchPlayOrPause(); + if (this.playVideoModel !== null) { + let curStatus = (this.playVideoModel!.getStatus() === CommonConstants.STATUS_START); + this.status = curStatus ? CommonConstants.STATUS_PAUSE : CommonConstants.STATUS_START; + this.playVideoModel!.switchPlayOrPause(); + } }) } .layoutWeight(1) + Image($r('app.media.ic_next')) .width($r('app.float.control_image_width')) .aspectRatio(CommonConstants.ASPECT_RATIO) .onClick(() => { - this.playVideoModel.nextVideo(); + if (this.playVideoModel !== null) { + this.playVideoModel!.nextVideo(); + } this.status = CommonConstants.STATUS_START; }) } - .width(PlayConstants.PLAY_CONTROL.ROW_WIDTH) + .width(PlayConstants.CONTROL_ROW_WIDTH) } .width(CommonConstants.FULL_PERCENT) .height(CommonConstants.FULL_PERCENT) diff --git a/Media/VideoPlayer/entry/src/main/ets/view/PlayPlayer.ets b/Media/VideoPlayer/entry/src/main/ets/view/PlayPlayer.ets index 08cf3c15216d50262a5663ae4232017547b029b7..0f3ffff860fc3876c6b1032e7d9abb95902b4788 100644 --- a/Media/VideoPlayer/entry/src/main/ets/view/PlayPlayer.ets +++ b/Media/VideoPlayer/entry/src/main/ets/view/PlayPlayer.ets @@ -16,74 +16,67 @@ import { VideoController } from '../controller/VideoController'; import { CommonConstants } from '../common/constants/CommonConstants'; import { PlayConstants } from '../common/constants/PlayConstants'; +import resourceManager from '@ohos.resourceManager'; +import { PlayerModel } from '../common/model/PlayerModel'; @Component export struct PlayPlayer { - private playVideoModel: VideoController; - @Consume src: string; + private playVideoModel?: VideoController; + @Consume playerModel: PlayerModel; + @Consume src: resourceManager.RawFileDescriptor; + @Consume iSrc: string; @Consume index: number; - @State volume: number = PlayConstants.PLAY_PAGE.VOLUME; - @State volumeShow: boolean = PlayConstants.PLAY_PAGE.VOLUME_SHOW; - @State bright: number = PlayConstants.PLAY_PAGE.BRIGHT; - @State brightShow: boolean = PlayConstants.PLAY_PAGE.BRIGHT_SHOW; - private xComponentController; - private surfaceID: number; - - aboutToAppear() { - if (this.playVideoModel !== null) { - this.playVideoModel.initPlayerThis(this); - } - this.xComponentController = new XComponentController(); - } + private xComponentController = new XComponentController(); + private surfaceID: string = ''; build() { Stack() { XComponent({ - id: PlayConstants.PLAY_PLAYER.ID, - type: PlayConstants.PLAY_PLAYER.TYPE, - libraryname: PlayConstants.PLAY_PLAYER.LIBRARY_NAME, + id: PlayConstants.PLAYER_ID, + type: PlayConstants.PLAYER_TYPE, + libraryname: PlayConstants.PLAYER_LIBRARY_NAME, controller: this.xComponentController }) .onLoad(async () => { this.xComponentController.setXComponentSurfaceSize({ - surfaceWidth: PlayConstants.PLAY_PLAYER.SURFACE_WIDTH, - surfaceHeight: PlayConstants.PLAY_PLAYER.SURFACE_HEIGHT + surfaceWidth: PlayConstants.PLAYER_SURFACE_WIDTH, + surfaceHeight: PlayConstants.PLAYER_SURFACE_HEIGHT }); this.surfaceID = this.xComponentController.getXComponentSurfaceId(); - this.playVideoModel.firstPlay(this.index, this.src, this.surfaceID); + this.playVideoModel!.firstPlay(this.index, this.src, this.iSrc, this.surfaceID); }) .width(CommonConstants.FULL_PERCENT) .height(CommonConstants.FULL_PERCENT) Stack() { Progress({ - value: Math.floor(this.volume * CommonConstants.ONE_HUNDRED), + value: Math.floor(this.playerModel.volume * CommonConstants.ONE_HUNDRED), type: ProgressType.Ring }) .width(CommonConstants.FULL_PERCENT) .aspectRatio(CommonConstants.ASPECT_RATIO) Image($r('app.media.ic_volume')) - .width(PlayConstants.PLAY_PLAYER.IMAGE_WIDTH) + .width(PlayConstants.PLAYER_IMAGE_WIDTH) .aspectRatio(CommonConstants.ASPECT_RATIO) } - .width(PlayConstants.PLAY_PLAYER.STACK_WIDTH) + .width(PlayConstants.PLAYER_STACK_WIDTH) .aspectRatio(CommonConstants.ASPECT_RATIO) - .visibility(this.volumeShow ? Visibility.Visible : Visibility.Hidden) + .visibility(this.playerModel.volumeShow ? Visibility.Visible : Visibility.Hidden) Stack() { Progress({ - value: Math.floor(this.bright * CommonConstants.ONE_HUNDRED), + value: Math.floor(this.playerModel.bright * CommonConstants.ONE_HUNDRED), type: ProgressType.Ring }) .width(CommonConstants.FULL_PERCENT) .aspectRatio(CommonConstants.ASPECT_RATIO) Image($r('app.media.ic_brightness')) - .width(PlayConstants.PLAY_PLAYER.IMAGE_WIDTH) + .width(PlayConstants.PLAYER_IMAGE_WIDTH) .aspectRatio(CommonConstants.ASPECT_RATIO) } - .width(PlayConstants.PLAY_PLAYER.STACK_WIDTH) + .width(PlayConstants.PLAYER_STACK_WIDTH) .aspectRatio(CommonConstants.ASPECT_RATIO) - .visibility(this.brightShow ? Visibility.Visible : Visibility.Hidden) + .visibility(this.playerModel.brightShow ? Visibility.Visible : Visibility.Hidden) } .width(CommonConstants.FULL_PERCENT) .height(CommonConstants.FULL_PERCENT) diff --git a/Media/VideoPlayer/entry/src/main/ets/view/PlayProgress.ets b/Media/VideoPlayer/entry/src/main/ets/view/PlayProgress.ets index 249c941a0c5b82234c08314e5aac9de50a611874..85439ffce50127b678a6b8f144bec670b63388f4 100644 --- a/Media/VideoPlayer/entry/src/main/ets/view/PlayProgress.ets +++ b/Media/VideoPlayer/entry/src/main/ets/view/PlayProgress.ets @@ -16,46 +16,39 @@ import { VideoController } from '../controller/VideoController'; import { CommonConstants } from '../common/constants/CommonConstants'; import { PlayConstants } from '../common/constants/PlayConstants'; +import { PlayerModel } from '../common/model/PlayerModel'; @Component export struct PlayProgress { - private playVideoModel: VideoController; - @State currentTime: string = PlayConstants.PLAY_PROGRESS.CURRENT_TIME; - @State totalTime: string = PlayConstants.PLAY_PROGRESS.TOTAL_TIME; - @State progressVal: number = PlayConstants.PLAY_PROGRESS.PROGRESS_VAL; - - aboutToAppear() { - if (this.playVideoModel !== null) { - this.playVideoModel.initProgressThis(this); - } - } + private playVideoModel?: VideoController; + @Consume playerModel: PlayerModel; build() { Column() { Row() { - Text(this.currentTime) + Text(this.playerModel.currentTime) .fontSize($r('app.float.slider_font_size')) .fontColor(Color.White) Slider({ - value: this.progressVal, - step: PlayConstants.PLAY_PROGRESS.STEP, + value: this.playerModel.progressVal, + step: PlayConstants.PROGRESS_STEP, style: SliderStyle.OutSet }) .blockColor(Color.White) .trackColor($r('app.color.track_color')) .selectedColor(Color.White) - .trackThickness(PlayConstants.PLAY_PROGRESS.TRACK_THICKNESS) + .trackThickness(PlayConstants.PROGRESS_TRACK_THICKNESS) .layoutWeight(1) - .margin({ left: PlayConstants.PLAY_PROGRESS.MARGIN_LEFT }) + .margin({ left: PlayConstants.PROGRESS_MARGIN_LEFT }) .onChange((value: number, mode: SliderChangeMode) => { - this.playVideoModel.setSeekTime(value, mode); + this.playVideoModel!.setSeekTime(value, mode); }) - Text(this.totalTime) + Text(this.playerModel.totalTime) .fontSize($r('app.float.slider_font_size')) .fontColor(Color.White) - .margin({ left: PlayConstants.PLAY_PROGRESS.MARGIN_LEFT }) + .margin({ left: PlayConstants.PROGRESS_MARGIN_LEFT }) } - .width(PlayConstants.PLAY_PROGRESS.ROW_WIDTH) + .width(PlayConstants.PROGRESS_ROW_WIDTH) } .width(CommonConstants.FULL_PERCENT) .height(CommonConstants.FULL_PERCENT) diff --git a/Media/VideoPlayer/entry/src/main/ets/view/PlayTitle.ets b/Media/VideoPlayer/entry/src/main/ets/view/PlayTitle.ets index ded425f53bd7d5e0463a9dd57a619056879012f0..df4212fab50173ff7c1524e1094928fd731d1292 100644 --- a/Media/VideoPlayer/entry/src/main/ets/view/PlayTitle.ets +++ b/Media/VideoPlayer/entry/src/main/ets/view/PlayTitle.ets @@ -21,22 +21,20 @@ import { PlayConstants } from '../common/constants/PlayConstants'; @Component export struct PlayTitle { - private playVideoModel: VideoController; - @State @Watch('watchSpeed')playSpeed: number = 1; + private playVideoModel: VideoController | null = null; @State loop: boolean = false; @State customPopup: boolean = false; dialogController: CustomDialogController = new CustomDialogController({ - builder: PlayTitleDialog({ - playSpeed: $playSpeed - }), + builder: PlayTitleDialog({ playVideoModel: this.playVideoModel! }), autoCancel: true, alignment: DialogAlignment.Bottom, - offset: { dx: PlayConstants.PLAY_TITLE.DX, dy: PlayConstants.PLAY_TITLE.DY }, - gridCount: PlayConstants.PLAY_TITLE.GRID_COUNT, + offset: { dx: PlayConstants.DX, dy: PlayConstants.DY }, + gridCount: PlayConstants.GRID_COUNT, customStyle: false }) - @Builder popupBuilder() { + @Builder + popupBuilder() { Column() { Row() { Image($r('app.media.ic_speed')) @@ -48,8 +46,8 @@ export struct PlayTitle { .margin({ left: $r('app.float.title_popup_text_left') }) } .width(CommonConstants.FULL_PERCENT) - .height(PlayConstants.PLAY_TITLE.POPUP.ROW_HEIGHT) - .margin({ top: PlayConstants.PLAY_TITLE.POPUP.ROW_MARGIN_TOP }) + .height(PlayConstants.POPUP_ROW_HEIGHT) + .margin({ top: PlayConstants.POPUP_ROW_MARGIN_TOP }) .onClick(() => { this.customPopup = !this.customPopup; this.dialogController.open(); @@ -57,11 +55,11 @@ export struct PlayTitle { Row() { Divider() - .strokeWidth(PlayConstants.PLAY_TITLE.POPUP.DIVIDER_STROKE_WIDTH) + .strokeWidth(PlayConstants.POPUP_DIVIDER_STROKE_WIDTH) .color($r('app.color.divider_color')) .margin({ left: $r('app.float.title_popup_divider_left'), - right: PlayConstants.PLAY_TITLE.POPUP.DIVIDER_MARGIN_RIGHT + right: PlayConstants.POPUP_DIVIDER_MARGIN_RIGHT }) } .width(CommonConstants.FULL_PERCENT) @@ -76,23 +74,19 @@ export struct PlayTitle { .margin({ left: $r('app.float.title_popup_text_left') }) } .width(CommonConstants.FULL_PERCENT) - .height(PlayConstants.PLAY_TITLE.POPUP.ROW_HEIGHT) + .height(PlayConstants.POPUP_ROW_HEIGHT) .onClick(() => { this.loop = !this.loop; - this.playVideoModel.setLoop(); + this.playVideoModel!.setLoop(); setTimeout(() => { this.customPopup = !this.customPopup; - }, PlayConstants.PLAY_TITLE.POPUP.CLOSE_TIME); + }, PlayConstants.POPUP_CLOSE_TIME); }) } .justifyContent(FlexAlign.Center) .alignItems(HorizontalAlign.Center) - .width(PlayConstants.PLAY_TITLE.POPUP.COLUMN_WIDTH) - .height(PlayConstants.PLAY_TITLE.POPUP.COLUMN_HEIGHT) - } - - watchSpeed() { - this.playVideoModel.setSpeed(this.playSpeed); + .width(PlayConstants.POPUP_COLUMN_WIDTH) + .height(PlayConstants.POPUP_COLUMN_HEIGHT) } build() { @@ -102,13 +96,12 @@ export struct PlayTitle { .width($r('app.float.title_image_size')) .aspectRatio(CommonConstants.ASPECT_RATIO) .onClick(() => { - this.playVideoModel.stop(); router.back(); }) Text($r('app.string.video_playback')) .fontColor(Color.White) .fontSize($r('app.float.title_font_size')) - .margin({ left: PlayConstants.PLAY_TITLE.TEXT_MARGIN_LEFT }) + .margin({ left: PlayConstants.TEXT_MARGIN_LEFT }) .layoutWeight(1) Image($r('app.media.ic_more')) .width($r('app.float.title_image_size')) @@ -123,7 +116,7 @@ export struct PlayTitle { this.customPopup = !this.customPopup; }) } - .width(PlayConstants.PLAY_TITLE.ROW_WIDTH) + .width(PlayConstants.ROW_WIDTH) } .width(CommonConstants.FULL_PERCENT) .height(CommonConstants.FULL_PERCENT) diff --git a/Media/VideoPlayer/entry/src/main/ets/view/PlayTitleDialog.ets b/Media/VideoPlayer/entry/src/main/ets/view/PlayTitleDialog.ets index 6289a114ccea38cb2d6ca0a4ec1a2975fbe979ea..97e8882f151c3054b3b7a5b8ffbe24d6b9f23033 100644 --- a/Media/VideoPlayer/entry/src/main/ets/view/PlayTitleDialog.ets +++ b/Media/VideoPlayer/entry/src/main/ets/view/PlayTitleDialog.ets @@ -12,14 +12,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +import { VideoSpeed } from '../viewmodel/VideoSpeed'; +import { VideoController } from '../controller/VideoController'; import { CommonConstants } from '../common/constants/CommonConstants'; import { PlayConstants } from '../common/constants/PlayConstants'; @CustomDialog export struct PlayTitleDialog { - @Link playSpeed: number; - controller: CustomDialogController; + private playVideoModel?: VideoController; + controller?: CustomDialogController; build() { Column() { @@ -27,12 +28,12 @@ export struct PlayTitleDialog { Text($r('app.string.speed_play')) .fontSize($r('app.float.title_font_size')) } - .height(PlayConstants.PLAY_TITLE_DIALOG.ROW_HEIGHT) - .width(PlayConstants.PLAY_TITLE_DIALOG.ROW_WIDTH) + .height(PlayConstants.TITLE_DIALOG_ROW_HEIGHT) + .width(PlayConstants.TITLE_DIALOG_ROW_WIDTH) Column() { Grid() { - ForEach(CommonConstants.SPEED_ARRAY, (item) => { + ForEach(CommonConstants.SPEED_ARRAY, (item: VideoSpeed) => { GridItem() { Text(item.text) .fontSize($r('app.float.title_dialog_font_size')) @@ -43,16 +44,16 @@ export struct PlayTitleDialog { .borderRadius($r('app.float.text_border_radius')) } .onClick(() => { - this.playSpeed = item.value; - this.controller.close(); + this.playVideoModel!.setSpeed(item.value); + this.controller!.close(); }) - }, item => JSON.stringify(item)) + }, (item: VideoSpeed) => JSON.stringify(item)) } - .columnsTemplate(PlayConstants.PLAY_TITLE_DIALOG.COLUMNS_TEMPLATE) - .rowsTemplate(PlayConstants.PLAY_TITLE_DIALOG.ROWS_TEMPLATE) - .columnsGap(PlayConstants.PLAY_TITLE_DIALOG.COLUMNS_GAP) - .rowsGap(PlayConstants.PLAY_TITLE_DIALOG.ROWS_GAP) - .width(PlayConstants.PLAY_TITLE_DIALOG.ROW_WIDTH) + .columnsTemplate(PlayConstants.TITLE_DIALOG_COLUMNS_TEMPLATE) + .rowsTemplate(PlayConstants.TITLE_DIALOG_ROWS_TEMPLATE) + .columnsGap(PlayConstants.TITLE_DIALOG_COLUMNS_GAP) + .rowsGap(PlayConstants.TITLE_DIALOG_ROWS_GAP) + .width(PlayConstants.TITLE_DIALOG_ROW_WIDTH) .height(CommonConstants.FULL_PERCENT) } .height(CommonConstants.FIFTY_PERCENT) @@ -62,14 +63,14 @@ export struct PlayTitleDialog { .fontColor($r('app.color.index_tab_selected_font_color')) .fontSize($r('app.float.title_dialog_font_size')) } - .height(PlayConstants.PLAY_TITLE_DIALOG.ROW_HEIGHT) - .width(PlayConstants.PLAY_TITLE_DIALOG.ROW_WIDTH) + .height(PlayConstants.TITLE_DIALOG_ROW_HEIGHT) + .width(PlayConstants.TITLE_DIALOG_ROW_WIDTH) .justifyContent(FlexAlign.Center) .onClick(() => { - this.controller.close(); + this.controller!.close(); }) } - .height(PlayConstants.PLAY_TITLE_DIALOG.COLUMN_WIDTH) + .height(PlayConstants.TITLE_DIALOG_COLUMN_WIDTH) .width(CommonConstants.FULL_PERCENT) .backgroundColor(Color.White) } diff --git a/Media/VideoPlayer/entry/src/main/ets/viewmodel/HomeDialogModel.ets b/Media/VideoPlayer/entry/src/main/ets/viewmodel/HomeDialogModel.ets index d9ad834bf91726c55d06fb3bd8b11637875bc031..8f4121baa9e6693da7fc2af76f5abb35b889a077 100644 --- a/Media/VideoPlayer/entry/src/main/ets/viewmodel/HomeDialogModel.ets +++ b/Media/VideoPlayer/entry/src/main/ets/viewmodel/HomeDialogModel.ets @@ -18,17 +18,18 @@ import media from '@ohos.multimedia.media'; import Logger from '../common/util/Logger'; import { HomeConstants } from '../common/constants/HomeConstants'; import { AvplayerStatus, Events } from '../common/constants/CommonConstants'; +import { HomeTabModel } from '../common/model/HomeTabModel'; export class HomeDialogModel { - private context; - private avPlayer; - private url; - private duration; - private checkFlag; + public homeTabModel: HomeTabModel; + private avPlayer: media.AVPlayer | null = null; + private url: string = ''; + private duration: number = 0; + private checkFlag: number = 0; private isLoading; - constructor(context) { - this.context = context; + constructor(homeTabModel: HomeTabModel) { + this.homeTabModel = homeTabModel; this.isLoading = false; } @@ -36,46 +37,44 @@ export class HomeDialogModel { * Creates a videoPlayer object. */ createAvPlayer() { - media.createAVPlayer().then((video) => { + media.createAVPlayer().then((video: media.AVPlayer) => { if (video != null) { this.avPlayer = video; this.bindState(); - this.url = this.context.src; + this.url = this.homeTabModel.src; this.avPlayer.url = this.url; } else { Logger.info(`[HomeDialogModel] createAVPlayer fail`); } - }).catch((err) => { + }).catch((err: Error) => { this.failureCallback(err); }); } bindState() { - this.avPlayer.on(Events.STATE_CHANGE, async (state) => { - switch (state) { - case AvplayerStatus.IDLE: - break; - case AvplayerStatus.INITIALIZED: - this.avPlayer.prepare(); - break; - case AvplayerStatus.PREPARED: - this.duration = this.avPlayer.duration; - this.checkUrlValidity(); - break; - case AvplayerStatus.RELEASED: - break; - case Events.ERROR: - this.avPlayer.reset(); - break; - default: - break; + if (this.avPlayer === null) { + return; + } + this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => { + if (this.avPlayer === null) { + return; + } + if (state === AvplayerStatus.INITIALIZED) { + this.avPlayer.prepare(); + } else if (state === AvplayerStatus.PREPARED) { + this.duration = this.avPlayer.duration; + this.checkUrlValidity(); + } else if (state === AvplayerStatus.ERROR) { + this.avPlayer.reset(); } }); - this.avPlayer.on(Events.ERROR, (error) => { + this.avPlayer.on(Events.ERROR, (error: Error) => { this.isLoading = false; - this.context.linkCheck = $r('app.string.link_check'); - this.context.loadColor = $r('app.color.index_tab_selected_font_color'); - this.avPlayer.release(); + this.homeTabModel.linkCheck = $r('app.string.link_check'); + this.homeTabModel.loadColor = $r('app.color.index_tab_selected_font_color'); + if (this.avPlayer !== null) { + this.avPlayer.release(); + } this.failureCallback(error); }) } @@ -90,8 +89,8 @@ export class HomeDialogModel { return; } this.isLoading = true; - this.context.linkCheck = $r('app.string.link_checking'); - this.context.loadColor = $r('app.color.index_tab_unselected_font_color'); + this.homeTabModel.linkCheck = $r('app.string.link_checking'); + this.homeTabModel.loadColor = $r('app.color.index_tab_unselected_font_color'); this.checkFlag = checkFlag; this.createAvPlayer(); } @@ -101,24 +100,24 @@ export class HomeDialogModel { */ checkUrlValidity() { this.isLoading = false; - this.context.linkCheck = $r('app.string.link_check'); - this.context.loadColor = $r('app.color.index_tab_selected_font_color'); - this.avPlayer.release(); - if (this.duration === HomeConstants.INTERNET_ADD_DIALOG.DURATION_TWO) { + this.homeTabModel.linkCheck = $r('app.string.link_check'); + this.homeTabModel.loadColor = $r('app.color.index_tab_selected_font_color'); + if (this.avPlayer !== null) { + this.avPlayer.release(); + } + if (this.duration === HomeConstants.DURATION_TWO) { // Failed to verify the link this.showPrompt($r('app.string.link_check_fail')); - this.context.result = false; - } else if (this.duration === HomeConstants.INTERNET_ADD_DIALOG.DURATION_ONE) { + } else if (this.duration === HomeConstants.DURATION_ONE) { // The address is incorrect or no network is available this.showPrompt($r('app.string.link_check_address_internet')); - this.context.result = false; } else { this.duration = 0; if (this.checkFlag === 0) { this.showPrompt($r('app.string.link_check_success')); } else { - this.context.confirm(); - this.context.controller.close(); + this.homeTabModel!.confirm(); + this.homeTabModel!.controller!.close(); } } } @@ -128,9 +127,8 @@ export class HomeDialogModel { * * @param error Error information. */ - failureCallback(error) { + failureCallback(error: Error) { Logger.error(`[HomeDialogModel] error happened: ` + JSON.stringify(error)); - this.context.result = false; this.showPrompt($r('app.string.link_check_fail')); } @@ -141,7 +139,7 @@ export class HomeDialogModel { */ showPrompt(msg: Resource) { prompt.showToast({ - duration: HomeConstants.INTERNET_ADD_DIALOG.DURATION, + duration: HomeConstants.DURATION, message: msg }); } @@ -149,13 +147,13 @@ export class HomeDialogModel { /** * Check whether the playback path is empty. */ - checkSrcNull() { + checkSrcNull(): boolean { if (this.isLoading) { - return; + return false; } - if (this.context.src.trim() === '') { + if (this.homeTabModel.src.trim() === '') { prompt.showToast({ - duration: HomeConstants.INTERNET_ADD_DIALOG.DURATION, + duration: HomeConstants.DURATION, message: $r('app.string.place_holder_src') }); return false; @@ -166,13 +164,13 @@ export class HomeDialogModel { /** * Check whether the name is empty. */ - checkNameNull() { + checkNameNull(): boolean { if (this.isLoading) { - return; + return false; } - if (this.context.name.trim() === '') { + if (this.homeTabModel.name.trim() === '') { prompt.showToast({ - duration: HomeConstants.INTERNET_ADD_DIALOG.DURATION, + duration: HomeConstants.DURATION, message: $r('app.string.place_holder_name') }); return false; diff --git a/Media/VideoPlayer/entry/src/main/ets/viewmodel/HomeVideoListModel.ets b/Media/VideoPlayer/entry/src/main/ets/viewmodel/HomeVideoListModel.ets index 5ff148cc3aa034be781706e1904b4d0eee1bcdf7..4aebc1c4a64d0b2c3535d32b6a41858a57d0c0ba 100644 --- a/Media/VideoPlayer/entry/src/main/ets/viewmodel/HomeVideoListModel.ets +++ b/Media/VideoPlayer/entry/src/main/ets/viewmodel/HomeVideoListModel.ets @@ -14,12 +14,14 @@ */ import image from '@ohos.multimedia.image'; -import { VideoBean } from '../common/bean/VideoBean'; +import { VideoItem } from './VideoItem'; import { VIDEO_DATA } from '../common/constants/CommonConstants'; +import { GlobalContext } from '../common/util/GlobalContext'; +import resourceManager from '@ohos.resourceManager'; export class HomeVideoListModel { - private videoLocalList: Array = []; - private videoInternetList: Array = []; + private videoLocalList: Array = []; + private videoInternetList: Array = []; /** * Scan the local video. @@ -29,18 +31,18 @@ export class HomeVideoListModel { async getLocalVideo() { this.videoLocalList = []; await this.assemblingVideoBean(); - globalThis.videoLocalList = this.videoLocalList; + GlobalContext.getContext().setObject('videoLocalList', this.videoLocalList); return this.videoLocalList; } /** * Assembling the video object */ - async assemblingVideoBean () { - VIDEO_DATA.forEach(async (item: VideoBean) => { - let videoBean = await globalThis.resourceManager.getRawFd(item.src); - let uri = `fd://${videoBean.fd}`; - this.videoLocalList.push(new VideoBean(item.name, uri)); + async assemblingVideoBean() { + VIDEO_DATA.forEach(async (item: VideoItem) => { + let videoBean = await getContext().resourceManager.getRawFd(item.iSrc); + let uri = videoBean; + this.videoLocalList.push(new VideoItem(item.name, uri, '')); }); } @@ -54,11 +56,13 @@ export class HomeVideoListModel { * @return Network video list data. */ async setInternetVideo(name: string, src: string, pixelMap?: image.PixelMap) { - this.videoInternetList.push(new VideoBean(name, src, pixelMap)); - globalThis.videoInternetList = this.videoInternetList; - return globalThis.videoInternetList; + this.videoInternetList.push(new VideoItem(name, {} as resourceManager.RawFileDescriptor, src, pixelMap)); + let videoInternetList = this.videoInternetList; + GlobalContext.getContext().setObject('videoInternetList', videoInternetList); + return videoInternetList; } } let homeVideoListModel = new HomeVideoListModel(); + export default homeVideoListModel as HomeVideoListModel; \ No newline at end of file diff --git a/Media/VideoPlayer/entry/src/main/ets/common/bean/VideoBean.ets b/Media/VideoPlayer/entry/src/main/ets/viewmodel/VideoItem.ets similarity index 73% rename from Media/VideoPlayer/entry/src/main/ets/common/bean/VideoBean.ets rename to Media/VideoPlayer/entry/src/main/ets/viewmodel/VideoItem.ets index 2036bd066466327f55c36b00f4771cc8ec82e603..27434b2e36a8ca45a721c8b84c1747bda8a2e34c 100644 --- a/Media/VideoPlayer/entry/src/main/ets/common/bean/VideoBean.ets +++ b/Media/VideoPlayer/entry/src/main/ets/viewmodel/VideoItem.ets @@ -14,15 +14,18 @@ */ import image from '@ohos.multimedia.image'; +import resourceManager from '@ohos.resourceManager'; -@Observed export class VideoBean { +@Observed export class VideoItem { name: string; - src: string; + src: resourceManager.RawFileDescriptor; + iSrc: string; pixelMap?: image.PixelMap; - constructor(name: string, src: string, pixelMap?: image.PixelMap) { + constructor(name: string, src: resourceManager.RawFileDescriptor, iSrc: string, pixelMap?: image.PixelMap) { this.name = name; this.src = src; + this.iSrc = iSrc; this.pixelMap = pixelMap; } } \ No newline at end of file diff --git a/ETSUI/SimpleCalculator/entry/src/main/ets/common/bean/PressKeysBean.ets b/Media/VideoPlayer/entry/src/main/ets/viewmodel/VideoSpeed.ets similarity index 70% rename from ETSUI/SimpleCalculator/entry/src/main/ets/common/bean/PressKeysBean.ets rename to Media/VideoPlayer/entry/src/main/ets/viewmodel/VideoSpeed.ets index 8485d4c16b6501e3112ce3fa8a92105e1982a5f3..123594fb8a556391b156a330d3d75fe8fb647076 100644 --- a/ETSUI/SimpleCalculator/entry/src/main/ets/common/bean/PressKeysBean.ets +++ b/Media/VideoPlayer/entry/src/main/ets/viewmodel/VideoSpeed.ets @@ -13,18 +13,12 @@ * limitations under the License. */ -export class PressKeysBean { - flag: number; - width: string; - height: string; - value: string; - source?: Resource; +export class VideoSpeed { + text: string; + value: number; - constructor(flag, width, height, value, source) { - this.flag = flag; - this.width = width; - this.height = height; + constructor(text: string, value: number) { + this.text = text; this.value = value; - this.source = source; } } \ No newline at end of file diff --git a/Media/VideoPlayer/entry/src/main/module.json5 b/Media/VideoPlayer/entry/src/main/module.json5 index bf390bbadd6358dfb44187039a649d7ae669a858..eeccd4f4a0009a97a4f602bedaf549dc59883cd8 100644 --- a/Media/VideoPlayer/entry/src/main/module.json5 +++ b/Media/VideoPlayer/entry/src/main/module.json5 @@ -34,29 +34,15 @@ } ], "requestPermissions": [ - { - "name": "ohos.permission.READ_MEDIA", - "reason": "$string:reason_read", - "usedScene": { - "abilities": ["EntryAbility"], - "when": "inuse" - } - }, - { - "name": "ohos.permission.MEDIA_LOCATION", - "reason": "$string:reason_location", - "usedScene": { - "abilities": ["EntryAbility"], - "when": "inuse" - } - }, { "name": "ohos.permission.INTERNET", - "reason": "$string:reason_internet", - "usedScene": { - "abilities": ["EntryAbility"], - "when": "inuse" - } + "reason": "$string:reason_internet", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } } ] } diff --git a/Media/VideoPlayer/entry/src/main/resources/base/element/string.json b/Media/VideoPlayer/entry/src/main/resources/base/element/string.json index 9d01b62f50ebee70320383ef860211a0d41ebfd0..4450c72652174e337520714a66287f4e4ed722a7 100644 --- a/Media/VideoPlayer/entry/src/main/resources/base/element/string.json +++ b/Media/VideoPlayer/entry/src/main/resources/base/element/string.json @@ -88,15 +88,15 @@ "name": "place_holder_name", "value": "Please enter a file name" }, - { + { "name": "reason_read", "value": "Reading Local Videos." }, - { + { "name": "reason_location", "value": "Obtaining Local Videos." }, - { + { "name": "reason_internet", "value": "Network video rights." } diff --git a/Media/VideoPlayer/entry/src/main/resources/en_US/element/string.json b/Media/VideoPlayer/entry/src/main/resources/en_US/element/string.json index 96ebf8c074d4015abfa0be9971a618e117157e05..2d1a215c5c4bb558445890ca2483225de75dbe26 100644 --- a/Media/VideoPlayer/entry/src/main/resources/en_US/element/string.json +++ b/Media/VideoPlayer/entry/src/main/resources/en_US/element/string.json @@ -88,15 +88,15 @@ "name": "place_holder_name", "value": "Please enter a file name" }, - { + { "name": "reason_read", "value": "Reading Local Videos." }, - { + { "name": "reason_location", "value": "Obtaining Local Videos." }, - { + { "name": "reason_internet", "value": "Network video rights." } diff --git a/Media/VideoPlayer/entry/src/main/resources/zh_CN/element/string.json b/Media/VideoPlayer/entry/src/main/resources/zh_CN/element/string.json index c5c51e9622f7c8c2bb22e614dda06a8a8a2c53e1..2d23edabd6ca1dd246e417aa417c434e6f7b1602 100644 --- a/Media/VideoPlayer/entry/src/main/resources/zh_CN/element/string.json +++ b/Media/VideoPlayer/entry/src/main/resources/zh_CN/element/string.json @@ -88,15 +88,15 @@ "name": "place_holder_name", "value": "请输入文件名称" }, - { + { "name": "reason_read", "value": "本地媒体读取权限" }, - { + { "name": "reason_location", "value": "获取本地视频" }, - { + { "name": "reason_internet", "value": "获取网络权限" } diff --git a/Media/VideoPlayer/hvigor/hvigor-config.json5 b/Media/VideoPlayer/hvigor/hvigor-config.json5 index e5bf1bf2b10d77ae8849c97d378d3831f13480b2..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/Media/VideoPlayer/hvigor/hvigor-config.json5 +++ b/Media/VideoPlayer/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.1.1", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.1.1" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/NativeAPI/NativeTemplateDemo/README.md b/NativeAPI/NativeTemplateDemo/README.md index 4ebfb5dea1e280dad836e455f45a1dd25a29ebab..5856097469dcb05f710ff5d5b54efcff7d9e6bd4 100644 --- a/NativeAPI/NativeTemplateDemo/README.md +++ b/NativeAPI/NativeTemplateDemo/README.md @@ -8,20 +8,20 @@ ### 相关概念 -- [Native API](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Release/zh-cn/application-dev/napi/napi-guidelines.md):NAPI提供的接口名与三方Node.js一致,目前支持部分接口。 -- [Native API中支持的标准库](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Release/zh-cn/application-dev/reference/native-lib/third_party_libc/musl.md):目前支持标准C库、C++库、OpenSL ES、zlib。 +- [Native API](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/napi/napi-guidelines.md):NAPI提供的接口名与三方Node.js一致,目前支持部分接口。 +- [Native API中支持的标准库](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/native-lib/third_party_libc/musl.md):目前支持标准C库、C++库、OpenSL ES、zlib。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/Index.ets b/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/Index.ets index 4100b0184983791819c430c9f2b9aedcaefb4cfb..04e37593ef5e3990fbd3dccde8c144b88d702083 100644 --- a/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/Index.ets +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/Index.ets @@ -98,7 +98,7 @@ struct NativeTemplate { .margin({ left: $r('app.float.text_input_margin_left') }) .layoutWeight(CommonContants.TEXTINPUT_LAYOUT_WEIGHT) .onChange(value => { - this.numX = parseFloat(value); + this.numX = Number.parseFloat(value); }) } .height($r('app.float.tips_num_height')) @@ -117,7 +117,7 @@ struct NativeTemplate { .margin({ left: $r('app.float.text_input_margin_left') }) .layoutWeight(CommonContants.TEXTINPUT_LAYOUT_WEIGHT) .onChange(value => { - this.numY = parseFloat(value); + this.numY = Number.parseFloat(value); }) } .height($r('app.float.tips_num_height')) diff --git a/NativeAPI/NativeTemplateDemo/hvigor/hvigor-config.json5 b/NativeAPI/NativeTemplateDemo/hvigor/hvigor-config.json5 index e5bf1bf2b10d77ae8849c97d378d3831f13480b2..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/NativeAPI/NativeTemplateDemo/hvigor/hvigor-config.json5 +++ b/NativeAPI/NativeTemplateDemo/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.1.1", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.1.1" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/NativeAPI/XComponent/README.md b/NativeAPI/XComponent/README.md index c14fb4cd7ca5cfdc0896bd8653b21fa669c5e69b..0213bb6271dc16358cee793d2f50b914a11aca96 100644 --- a/NativeAPI/XComponent/README.md +++ b/NativeAPI/XComponent/README.md @@ -10,20 +10,20 @@ ### 相关概念 -- [EGL\(Embedded Graphic Library\)](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Release/zh-cn/application-dev/reference/native-lib/third_party_libc/musl.md#egl):EGL 是Khronos渲染API (如OpenGL ES 或 OpenVG) 与底层原生窗口系统之间的接口。 -- [XComponent](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Release/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-xcomponent.md):可用于EGL/OpenGLES和媒体数据写入,并显示在XComponent组件。 +- [EGL\(Embedded Graphic Library\)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/native-lib/third_party_opengl/egl.md):EGL 是Khronos渲染API (如OpenGL ES 或 OpenVG) 与底层原生窗口系统之间的接口。 +- [XComponent](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-xcomponent.md):可用于EGL/OpenGLES和媒体数据写入,并显示在XComponent组件。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -146,7 +146,7 @@ import nativerender from 'libnativerender.so'; @Component struct Index { // XComponent实例对象的context - private xComponentContext = null; + private xComponentContext: Record void> = {}; ... build() { ... @@ -156,9 +156,10 @@ struct Index { type: CommonConstants.XCOMPONENT_TYPE, libraryname: CommonConstants.XCOMPONENT_LIBRARY_NAME }) - .onLoad((xComponentContext) => { - // 获取XComponent实例对象的context,context上挂载的方法由开发者在C++侧定义 - this.xComponentContext = xComponentContext; + .onLoad((xComponentContext?: object | Record void>) => { + if (xComponentContext) { + this.xComponentContext = xComponentContext as Record void>; + } }) ... // 增加Button组件 diff --git a/NativeAPI/XComponent/entry/src/main/ets/pages/Index.ets b/NativeAPI/XComponent/entry/src/main/ets/pages/Index.ets index a366a30c1368f4d3572e260645fa6bcea6d50f2c..e663535871aad0261118b16ca93e16a41371c51a 100644 --- a/NativeAPI/XComponent/entry/src/main/ets/pages/Index.ets +++ b/NativeAPI/XComponent/entry/src/main/ets/pages/Index.ets @@ -17,12 +17,13 @@ import nativeRender from 'libnativerender.so'; import { ContextType } from '../entryability/EntryAbility'; import CommonConstants from '../common/CommonConstants'; -const nativePageLifecycle = nativeRender.getContext(ContextType.PAGE_LIFECYCLE); +const nativePageLifecycle: Record void> = + nativeRender.getContext(ContextType.PAGE_LIFECYCLE) as Record void>; @Entry @Component struct Index { - private xComponentContext = null; + private xComponentContext: Record void> = {}; aboutToAppear(): void { console.log('[LIFECYCLE-Index] aboutToAppear'); @@ -65,8 +66,10 @@ struct Index { type: CommonConstants.XCOMPONENT_TYPE, libraryname: CommonConstants.XCOMPONENT_LIBRARY_NAME }) - .onLoad((xComponentContext) => { - this.xComponentContext = xComponentContext; + .onLoad((xComponentContext?: object | Record void>) => { + if (xComponentContext) { + this.xComponentContext = xComponentContext as Record void>; + } }) } .margin({ diff --git a/NativeAPI/XComponent/hvigor/hvigor-config.json5 b/NativeAPI/XComponent/hvigor/hvigor-config.json5 index e5bf1bf2b10d77ae8849c97d378d3831f13480b2..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/NativeAPI/XComponent/hvigor/hvigor-config.json5 +++ b/NativeAPI/XComponent/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.1.1", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.1.1" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/app.js b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/app.js new file mode 100644 index 0000000000000000000000000000000000000000..94cf2229e8238e3993ae6778d8c650fc5122bdd8 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/app.js @@ -0,0 +1,45 @@ +var createError = require('http-errors'); +var express = require('express'); +var path = require('path'); +var cookieParser = require('cookie-parser'); +var logger = require('morgan'); +var bodyParser = require('body-parser'); + +var newsRouter = require('./routes/news'); + +var app = express(); + +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'jade'); + +app.use(logger('dev')); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, 'public'))); + +app.use('/images',express.static('images')); +app.use('/news', newsRouter); + +// catch 404 and forward to error handler +app.use(function (req, res, next) { + next(createError(404)); +}); + +// error handler +app.use(function (err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.render('error'); +}); + +app.listen(9588, () => { + console.log('服务器启动成功!'); +}); + +module.exports = app; diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/bin/www b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/bin/www new file mode 100644 index 0000000000000000000000000000000000000000..7786c6db00be23d931a1e59e87171c13b49eb94d --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/bin/www @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var app = require('../app'); +var debug = require('debug')('httpserver:server'); +var http = require('http'); + +/** + * Get port from environment and store in Express. + */ + +var port = normalizePort(process.env.PORT || '3000'); +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/controllers/newsController.js b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/controllers/newsController.js new file mode 100644 index 0000000000000000000000000000000000000000..cbf01f65e40bbf7ca4ca9bbe79a1b265de7bbe50 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/controllers/newsController.js @@ -0,0 +1,47 @@ +/* controllers/newsController.js */ +const dbFile = require('../model/NewsDataModel'); +const NewsData = require('../model/NewsData'); +const NewsFile = require('../model/NewsFile'); + +const DEFAULT_PAGE_SIZE = 4; +const SUCCESS_CODE = 'success'; + +/** + * Get news type list. + * + * @param req request + * @param res response + */ +const getNewsType = (req, res) => { + res.send({ code: SUCCESS_CODE, data: dbFile.newsType, msg: '' }); +}; + +/** + * Get news list by currentPage and pageSize. + * + * @param req request + * @param res response + */ +const getNewsList = (req, res) => { + let {currentPage = 1, pageSize = DEFAULT_PAGE_SIZE} = req.query; + let newsList = dbFile.newsDataArray.slice((currentPage - 1) * pageSize, currentPage * pageSize); + res.send({ code: SUCCESS_CODE, data: newsList, msg: '' }); +}; + +/** + * Get news list by currentPage and pageSize. + * + * @param req request + * @param res response + */ +const getExtraNewsList = (req, res) => { + let {currentPage = 1, pageSize = DEFAULT_PAGE_SIZE} = req.query; + let newsList = dbFile.newsExtraDataArray.slice((currentPage - 1) * pageSize, currentPage * pageSize); + res.send({ code: SUCCESS_CODE, data: newsList, msg: '' }); +}; + +module.exports = { + getNewsType, + getNewsList, + getExtraNewsList +} \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/model/NewsData.js b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/model/NewsData.js new file mode 100644 index 0000000000000000000000000000000000000000..e683f47ba017fc1fe6a74c04ed156d2ef731bda0 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/model/NewsData.js @@ -0,0 +1,11 @@ +class NewsData { + constructor(id, title, content, imagesUrl, source) { + this.id = id; + this.title = title; + this.content = content; + this.imagesUrl = imagesUrl; + this.source = source; + } +} + +module.exports = NewsData; \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/model/NewsDataModel.js b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/model/NewsDataModel.js new file mode 100644 index 0000000000000000000000000000000000000000..bc387d2598a8e8bb23fd74063670bd7e1a82ad68 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/model/NewsDataModel.js @@ -0,0 +1,30 @@ +/* NewsDataModel*/ +const NewsData = require('../model/NewsData'); +const NewsFile = require('../model/NewsFile'); + +var newsDataArray = [ + new NewsData(0, '入春来,百花香', '随着气温升高,连日来,某某县某某街道的各个角度盛开了各种各样的花朵,让人眼花缭乱,装点了春天的气息。', [new NewsFile(0, '/images/ic_news_1_1.png', 0, 0), new NewsFile(1, '/images/ic_news_1_2.png', 0, 0), new NewsFile(2, '/images/ic_news_1_3.png', 0, 0)], '2022年08月16日'), + new NewsData(1, '第四届美食节正式启动', '8月5日,某某市第四届美食节正式启动。美食节将围绕各地特色美食展开,推进各地美食文化交流。', [new NewsFile(0, '/images/ic_news_2_1.png', 0, 1), new NewsFile(1, '/images/ic_news_2_2.png', 0, 1)], '2022年8月5日'), + new NewsData(2, '江南风景美如画', '南朝四百八十寺,多少楼台烟雨中。江南美,去过风光绮丽的江南,便久久不能忘怀,江南的雨如沐春风。', [new NewsFile(0, '/images/ic_news_3_1.png', 0, 2), new NewsFile(1, '/images/ic_news_3_2.png', 0, 2), new NewsFile(1, '/images/ic_news_3_3.png', 0, 2)], '2022年7月26日'), + new NewsData(3, '好物推荐', '精选好物,提升家居氛围,享受美好生活。', [new NewsFile(0, '/images/ic_news_4_1.png', 0, 3), new NewsFile(1, '/images/ic_news_4_2.png', 0, 3)], '2023年4月20日'), + new NewsData(4, '某某大桥正式建成', '今日,历经了6年的某某大桥正式建成,自从2018年起,这座大桥就汇聚了全世界的目光,他的建筑风格十分新颖。', [new NewsFile(0, '/images/ic_yunnan.png', 0, 4) ], '2022年6月11日'), + new NewsData(5, '黑白复古风复苏', '近几年,时尚风潮不断变化,复古风又开始风靡全球。其中,黑白照片是提升复古质感的最佳利器,简洁优雅。', [new NewsFile(0, '/images/ic_yiqing.png', 0, 5), new NewsFile(1, '/images/ic_student.png', 0, 5)], '2022年6月10日'), + new NewsData(6, '设计中的材质碰撞', '近几年,设计风格已不满足于传统的二维图形,逐渐向三维立体图形靠近,但传统的三维图形操作复杂,未来方向仍值得深究。', [new NewsFile(0, '/images/ic_student.png', 0, 6), new NewsFile(1, '/images/ic_yunnan.png', 0, 6), new NewsFile(1, '/images/ic_news_3_3.png', 0, 6)], '2022年5月19日'), + new NewsData(7, '如何过好周末', '周末人们最喜爱做什么呢?有些人喜欢带着家人出门旅行,有些人喜欢宅在家里玩游戏,有的人喜欢约会,你呢?', [new NewsFile(0, '/images/ic_news_1_1.png', 0, 7), new NewsFile(1, '/images/ic_news_2_1.png', 0, 7)], '2022年5月15日') +]; + +var newsType = [ + { id: 0, name: '全部' }, + { id: 1, name: '国内' }, + { id: 2, name: '国际' }, + { id: 3, name: '娱乐' }, + { id: 4, name: '军事' }, + { id: 5, name: '体育' }, + { id: 6, name: '科技' }, + { id: 7, name: '财经' } +]; + +module.exports = { + newsDataArray, + newsType +} \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/model/NewsFile.js b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/model/NewsFile.js new file mode 100644 index 0000000000000000000000000000000000000000..cf1090f33d1cf00d48e3dda02f12eb2e33e52478 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/model/NewsFile.js @@ -0,0 +1,10 @@ +class NewsFile { + constructor(id, url, type, newsId) { + this.id = id; + this.url = url; + this.type = type; + this.newsId = newsId; + } +} + +module.exports = NewsFile; \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/package.json b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/package.json new file mode 100644 index 0000000000000000000000000000000000000000..59a231cdc9af32c964e65015ed8d62993f2c15b2 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/package.json @@ -0,0 +1,19 @@ +{ + "name": "httpserverofnews", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www", + "dev": "nodemon ./bin/www" + }, + "dependencies": { + "cookie-parser": "1.4.6", + "debug": "2.6.9", + "express": "4.16.1", + "express-fileupload": "1.4.0", + "express-session": "1.17.3", + "http-errors": "1.6.3", + "jade": "1.11.0", + "morgan": "1.9.1" + } +} diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_1_1.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_1_1.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_1_1.png rename to NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_1_1.png diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_1_2.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_1_2.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_1_2.png rename to NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_1_2.png diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_1_3.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_1_3.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_1_3.png rename to NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_1_3.png diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_2_1.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_2_1.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_2_1.png rename to NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_2_1.png diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_2_2.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_2_2.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_2_2.png rename to NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_2_2.png diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_3_1.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_3_1.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_3_1.png rename to NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_3_1.png diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_3_2.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_3_2.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_3_2.png rename to NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_3_2.png diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_3_3.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_3_3.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_3_3.png rename to NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_3_3.png diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_4_1.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_4_1.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_4_1.png rename to NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_4_1.png diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_4_2.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_4_2.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/media/ic_news_4_2.png rename to NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_news_4_2.png diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_student.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_student.png new file mode 100644 index 0000000000000000000000000000000000000000..2d2a3fcc6ca979a148079f05e6ed6a27fddb3ecd Binary files /dev/null and b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_student.png differ diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_yiqing.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_yiqing.png new file mode 100644 index 0000000000000000000000000000000000000000..14ba5be8dc3cfef64bd90179f2604f8280bf522b Binary files /dev/null and b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_yiqing.png differ diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_yunnan.png b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_yunnan.png new file mode 100644 index 0000000000000000000000000000000000000000..97e01e9118fe562422fcc2b9450e5cce42104737 Binary files /dev/null and b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/images/ic_yunnan.png differ diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/stylesheets/style.css b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/stylesheets/style.css new file mode 100644 index 0000000000000000000000000000000000000000..9453385b9916ce9bc5e88d2f5d8cd8a554223590 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/public/stylesheets/style.css @@ -0,0 +1,8 @@ +body { + padding: 50px; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; +} + +a { + color: #00B7FF; +} diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/routes/news.js b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/routes/news.js new file mode 100644 index 0000000000000000000000000000000000000000..292d15a2dbd99a1ff68bc3b01d21db170a2416f3 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/routes/news.js @@ -0,0 +1,12 @@ +var express = require('express'); +var router = express.Router(); +const newsController = require('../controllers/newsController'); + +router.get('/getNewsType', newsController.getNewsType); + +router.get('/getNewsList', newsController.getNewsList); + +router.get('/getExtraNewsList', newsController.getExtraNewsList); + +module.exports = router; + diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/views/error.jade b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/views/error.jade new file mode 100644 index 0000000000000000000000000000000000000000..51ec12c6a26323d9f5bc51fb98cb1324a739ea4c --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/views/error.jade @@ -0,0 +1,6 @@ +extends layout + +block content + h1= message + h2= error.status + pre #{error.stack} diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/views/index.jade b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/views/index.jade new file mode 100644 index 0000000000000000000000000000000000000000..3d63b9a044a859b59259d5e23dd4e68ec8e1f2be --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/views/index.jade @@ -0,0 +1,5 @@ +extends layout + +block content + h1= title + p Welcome to #{title} diff --git a/NetworkManagement/NewsDataArkTS/HttpServerOfNews/views/layout.jade b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/views/layout.jade new file mode 100644 index 0000000000000000000000000000000000000000..15af079bf7c34e638ba14844efd979ac9111628b --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/HttpServerOfNews/views/layout.jade @@ -0,0 +1,7 @@ +doctype html +html + head + title= title + link(rel='stylesheet', href='/stylesheets/style.css') + body + block content diff --git a/NetworkManagement/NewsDataArkTS/README.md b/NetworkManagement/NewsDataArkTS/README.md index 599952e7aa004b3786ea7e4f00d133b79ebca45a..6c16bea89b57e25fccef0bbd7679b6a876bddd78 100644 --- a/NetworkManagement/NewsDataArkTS/README.md +++ b/NetworkManagement/NewsDataArkTS/README.md @@ -1,275 +1,321 @@ + # 新闻数据加载(ArkTS) + ## 介绍 -本篇Codelab是基于ArkTS的声明式开发范式的样例,主要介绍了数据请求和touch事件的使用。包含以下功能: -1. 数据请求。 -2. 列表下拉刷新。 -3. 列表上拉加载。 +本篇Codelab是基于ArkTS的声明式开发范式实现的样例,主要介绍了数据请求和touch事件的使用。包含以下功能: -最终效果图如下: +1. 数据请求。 +2. 列表下拉刷新。 +3. 列表上拉加载。 -![](figures/news.gif) +![](screenshots/device/news.gif) ### 相关概念 -- [List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md):列表包含一系列相同宽度的列表项。 -- [Tabs组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabs.md):通过页签进行内容视图切换。 -- [TabContent组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabcontent.md):仅在Tabs中使用,对应一个切换页签的内容视图。 -- [数据请求](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-http.md):提供发起请求、中断请求、订阅/取消订阅HTTP Response Header 等方法。 -- [触摸事件onTouch](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-events-touch.md):触摸动作触发调用该方法。 +- [List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md):列表包含一系列相同宽度的列表项。 +- [Tabs](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabs.md):通过页签进行内容视图切换。 +- [TabContent](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabcontent.md):仅在Tabs中使用,对应一个切换页签的内容视图。 +- [数据请求](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-http.md):提供HTTP数据请求能力。 +- [触摸事件onTouch](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-events-touch.md):触摸动作触发调用该方法。 ### 相关权限 -本Codelab使用了网络数据请求,需要在配置文件module.json5文件里添加网络权限:ohos.permission.INTERNET。 +添加网络权限:ohos.permission.INTERNET。 -```typescript -{ - "module": { - "name": "entry", - ... - "requestPermissions": [ - { - "name": "ohos.permission.INTERNET" - } - ] - } -} -``` +### 使用说明 + +#### 服务端搭建流程 + +1. 搭建nodejs环境:本篇Codelab的服务端是基于nodejs实现的,需要安装nodejs,如果您本地已有nodejs环境可以跳过此步骤。 + 1. 检查本地是否安装nodejs:打开命令行工具(如Windows系统的cmd和Mac电脑的Terminal,这里以Windows为例),输入node -v,如果可以看到版本信息,说明已经安装nodejs。 + + ![](screenshots/device/node.PNG) + 2. 如果本地没有nodejs环境,您可以去nodejs官网上下载所需版本进行安装配置。 + 3. 配置完环境变量后,重新打开命令行工具,输入node -v,如果可以看到版本信息,说明已安装成功。 +2. 构建局域网环境:测试本Codelab时要确保运行服务端代码的电脑和测试机连接的是同一局域网下的网络,您可以用您的手机开一个个人热点,然后将测试机和运行服务端代码的电脑都连接您的手机热点进行测试。 +3. 运行服务端代码:在本项目的HttpServerOfNews目录下打开命令行工具,输入npm install 安装服务端依赖包,安装成功后输入npm start点击回车。看到“服务器启动成功!”则表示服务端已经在正常运行。 + + ![](screenshots/device/npm_360.PNG) +4. 连接服务器地址:打开命令行工具,输入ipconfig命令查看本地ip,将本地ip地址复制到src/main/ets/common/constant/CommonConstants.ets文件下的23行,注意只替换ip地址部分,不要修改端口号,保存好ip之后即可运行Codelab进行测试。 + +#### 前端使用说明 + +1. 点击应用进入主页面,页面使用tabBar展示新闻分类,tabContent展示新闻列表,新闻分类和新闻列表通过请求nodejs服务端获取。 +2. 点击页签或左右滑动页面,切换标签并展示对应新闻类型的数据。 +3. 新闻列表页面,滑动到新闻列表首项数据,接着往下滑动会触发下拉刷新操作,页面更新初始4条新闻数据,滑动到新闻列表最后一项数据,往上拉会触发上拉加载操作,新闻列表会在后面加载4条新闻数据。 ## 环境搭建 ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 -- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: -1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以3.2 Release版本为例: +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以3.2Release版本为例: + + ![](screenshots/device/environment.png) - ![](figures/systemVersion.png) +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) -2. 搭建烧录环境。 - 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) - 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建arkts工程)创建工程(模板选择“Empty Ability”)。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 -3. 搭建开发环境。 - 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 - 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 - 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 - ## 代码结构解读 本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 ``` -├──entry/src/main/ets // 代码区 +├──entry/src/main/ets // ArkTS代码区 │ ├──common -│ │ ├──bean -│ │ │ └──NewsData.ets // 新闻数据实体类 -│ │ ├──constants -│ │ │ └──CommonConstants.ets // 公共常量类 +│ │ ├──constant +│ │ │ └──CommonConstant.ets // 公共常量类 │ │ └──utils -│ │ ├──DataUtils.ets // 获取新闻数据、类型等方法 │ │ ├──HttpUtil.ets // 网络请求方法 +│ │ ├──Logger.ets // 日志工具类 │ │ ├──PullDownRefresh.ets // 下拉刷新方法 │ │ └──PullUpLoadMore.ets // 上拉加载更多方法 │ ├──entryability │ │ └──EntryAbility.ts // 程序入口类 │ ├──pages -│ │ └──Index.ets // 入口文件 -│ └──view -│ ├──CustomRefreshLoadLayout.ets // 下拉刷新、上拉加载布局文件 -│ ├──LoadMoreLayout.ets // 上拉加载布局封装 -│ ├──NewsItem.ets // 新闻数据 -│ ├──NewsList.ets // 新闻列表 -│ ├──RefreshLayout.ets // 下拉刷新布局封装 -│ └──TabBar.ets // 新闻类型页签 -└──entry/src/main/resources // 资源文件目录 +│ │ └──Index.ets // 主页面 +│ ├──view +│ │ ├──CustomRefreshLoadLayout.ets // 下拉刷新、上拉加载布局文件 +│ │ ├──LoadMoreLayout.ets // 上拉加载布局封装 +│ │ ├──NewsItem.ets // 新闻数据 +│ │ ├──NewsList.ets // 新闻列表 +│ │ ├──NoMoreLayout.ets // 上拉停止布局封装 +│ │ ├──RefreshLayout.ets // 下拉刷新布局封装 +│ │ └──TabBar.ets // 新闻类型页签 +│ └──viewmodel +│ ├──NewsModel.ets // 新闻模型类 +│ └──NewsViewModel.ets // 新闻ViewModel +├──entry/src/main/resources // 资源文件目录 +└──HttpServerOfNews // 服务端代码 ``` ## 构建主界面 -本章节将介绍新闻列表页面的实现,用tabBar展示新闻分类,tabContent展示新闻列表,效果图如下: +本章节将介绍新闻列表页面的实现,用tabBar展示新闻分类,tabContent展示新闻列表,效果图如图所示: -![](figures/mainPage.png) +![](screenshots/device/homePage.png) -在TabBar.ets文件中的aboutToAppear()方法里获取新闻分类。示例代码如下: +在TabBar.ets文件中的aboutToAppear\(\)方法里获取新闻分类。 ```typescript +// TabBar.ets aboutToAppear() { - // 新闻类别 - loadNewsTypes({ - onSuccess: (value) => this.tabBarArray = value, - onFail: () => this.tabBarArray = TabBars.DEFAULT_NEWS_TYPES + // 请求服务端新闻类别 + NewsViewModel.getNewsTypeList().then((typeList: NewsTypeBean[]) => { + this.tabBarArray = typeList; + }).catch((typeList: NewsTypeBean[]) => { + this.tabBarArray = typeList; }); } ``` -在NewsList.ets文件中的aboutToAppear()方法里获取新闻数据,将数据加载到新闻列表页面ListLayout布局中。示例代码如下: +在NewsList.ets文件中的aboutToAppear\(\)方法里获取新闻数据,将数据加载到新闻列表页面ListLayout布局中。 ```typescript // NewsList.ets +changeCategory() { + this.newsModel.currentPage = 1; + NewsViewModel.getNewsList(this.newsModel.currentPage, this.newsModel.pageSize, Const.GET_NEWS_LIST) + .then((data: NewsData[]) => { + this.newsModel.pageState = PageState.Success; + if (data.length === this.newsModel.pageSize) { + this.newsModel.currentPage++; + this.newsModel.hasMore = true; + } else { + this.newsModel.hasMore = false; + } + this.newsModel.newsData = data; + }) + .catch((err: string | Resource) => { + promptAction.showToast({ + message: err, + duration: Const.ANIMATION_DURATION + }); + this.newsModel.pageState = PageState.Fail; + }); +} + aboutToAppear() { - // 请求新闻数据 - getTabData(this.currentPage - 1, this.pageSize, this.currentIndex, { - onSuccess: (value) => { - this.pageState = PageState.Success; - this.newsData = value.newsPageData; - }, - onFail: () => this.pageState = PageState.Fail - }); + // 请求服务端新闻数据 + this.changeCategory(); } ... @Builder ListLayout() { List() { - // 下拉刷新布局 - ListItem() { - RefreshLayout({ - refreshLayoutClass: new CustomRefreshLoadLayoutClass(this.isVisiblePullDown, this.pullDownRefreshImage, this.pullDownRefreshText, - this. pullDownRefreshHeight) - }); - } - ForEach(this.newsData, item => { - // 新闻数据 + ... + ForEach(this.newsModel.newsData, (item: NewsData) => { ListItem() { - NewsItem({ newsData: item }); + // 新闻数据 + NewsItem({ newsData: item }) } - ... - }, (item, index) => JSON.stringify(item) + index.toString()) - // 上拉加载布局 + .height($r('app.float.news_list_height')) + .backgroundColor($r('app.color.white')) + .margin({ top: $r('app.float.news_list_margin_top') }) + .borderRadius(Const.NewsListConstant_ITEM_BORDER_RADIUS) + }, (item: NewsData, index?: number) => JSON.stringify(item) + index) ... } + ... } ``` ## 数据请求 -这一章节,将基于新闻数据请求(getTabData方法)来介绍如何从服务端请求数据。 - 在module.json5文件中配置如下权限: -```typescript +```json +// module.json5 "requestPermissions": [ { - "name": "ohos.permission.INTERNET" + "name": "ohos.permission.INTERNET", + "reason": "$string:dependency_reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } } ] ``` -导入http模块,封装httpRequestGet方法,调用者传入url地址发起网络数据请求。示例代码如下: +这一章节,将基于新闻数据请求来介绍如何从服务端请求数据。 + +导入http模块,封装httpRequestGet方法,调用者传入url地址和所需参数发起网络数据请求。 ```typescript +// HttpUtil.ets import http from '@ohos.net.http'; ... -export function httpRequestGet(url: string, params: Array) { - ... +export function httpRequestGet(url: string): Promise { let httpRequest = http.createHttp(); // 发送数据请求 let responseResult = httpRequest.request(url, { method: http.RequestMethod.GET, - readTimeout: HTTP_READ_TIMEOUT, - connectTimeout: HTTP_READ_TIMEOUT + readTimeout: Const.HTTP_READ_TIMEOUT, + header: { + 'Content-Type': ContentType.JSON + }, + connectTimeout: Const.HTTP_READ_TIMEOUT, + extraData: {} }); - let serverData: { - code, - data: any, - msg: string | Resource - } = { code: 0, data: '', msg: '' }; + let serverData: ResponseResult = new ResponseResult(); // 处理数据,并返回 - return responseResult.then((value) => { - if (value.responseCode === HTTP_CODE_200) { + return responseResult.then((value: http.HttpResponse) => { + Logger.info(`http value ${JSON.stringify(value)}`); + if (value.responseCode === Const.HTTP_CODE_200) { // 获取返回数据 let result = `${value.result}`; - let resultJson = JSON.parse(result); - if (resultJson.code === SERVER_CODE_SUCCESS) { + let resultJson: ResponseResult = JSON.parse(result); + if (resultJson.code === Const.SERVER_CODE_SUCCESS) { serverData.data = resultJson.data; } serverData.code = resultJson.code; serverData.msg = resultJson.msg; } else { - serverData.code = value.responseCode; serverData.msg = `${$r('app.string.http_error_message')}&${value.responseCode}`; } return serverData; }).catch(() => { - serverData.msg = $r('app.string.http_error_message') + serverData.msg = $r('app.string.http_error_message'); return serverData; }) } ``` -在DataUtils.ets文件中封装getTabData方法,调用httpRequestGet方法统一发起网络数据请求,callback回调方法处理请求到的数据。示例代码如下: +在NewsViewModel.ets文件中封装getNewsList方法,调用httpRequestGet方法请求服务端,用Promise异步保存返回的新闻数据列表。 ```typescript -// DataUtils.ets -export async function getTabData(currentPage: number, pageSize: number, currentIndex: number, callback) { - ... - let data = await httpRequestGet(url, params); - if (data.code === SERVER_CODE_SUCCESS) { - newsPageData = data.data.pageData; - callback.onSuccess({ currentPage, newsPageData }); - } else { - callback.onFail(data.msg); - } +// NewsViewModel.ets +// 获取服务端新闻数据列表 +getNewsList(currentPage: number, pageSize: number, path: string): Promise { + return new Promise(async (resolve: Function, reject: Function) => { + let url = `${Const.SERVER}/${path}`; + url += '?currentPage=' + currentPage + '&pageSize=' + pageSize; + httpRequestGet(url).then((data: ResponseResult) => { + if (data.code === Const.SERVER_CODE_SUCCESS) { + resolve(data.data); + } else { + Logger.error('getNewsList failed', JSON.stringify(data)); + reject($r('app.string.page_none_msg')); + } + }).catch((err: Error) => { + Logger.error('getNewsList failed', JSON.stringify(err)); + reject($r('app.string.http_error_message')); + }); + }); } ``` ## 下拉刷新 -本章节将以下拉刷新的功能效果来介绍touch事件的使用。效果图如下: +本章节将以下拉刷新的功能效果来介绍touch事件的使用。效果图如图所示: -![](figures/pullDownRefresh.png) +![](screenshots/device/homePage2.png) -创建一个下拉刷新布局CustomLayout,动态传入刷新图片和刷新文字描述。示例代码如下: +创建一个下拉刷新布局CustomLayout,动态传入刷新图片和刷新文字描述。 ```typescript -@Component -export default struct CustomLayout { +// CustomRefreshLoadLayout.ets +build() { Row() { // 下拉刷新图片 - Image(this.customClass.imageSrc) + Image(this.customRefreshLoadClass.imageSrc) ... // 下拉刷新文字 - Text(this.customClass.textValue) + Text(this.customRefreshLoadClass.textValue) ... } ... } ``` -将下拉刷新的布局添加到NewsList.ets文件中新闻列表布局ListLayout里面,监听ListLayout组件的onTouch事件实现下拉刷新。示例代码如下: +将下拉刷新的布局添加到NewsList.ets文件中新闻列表布局ListLayout里面,监听ListLayout组件的onTouch事件实现下拉刷新。 ```typescript +// NewsList.ets build() { Column() { - ... - this.ListLayout(); - ... + if (this.newsModel.pageState === PageState.Success) { + this.ListLayout() + } + ... } ... - .onTouch((event) => { - if (this.pageState === PageState.Success) { - listTouchEvent.call(this, event); + .onTouch((event: TouchEvent | undefined) => { + if (event) { + if (this.newsModel.pageState === PageState.Success) { + listTouchEvent(this.newsModel, event); + } } }) } ... @Builder ListLayout() { List() { - // 下拉刷新布局 ListItem() { RefreshLayout({ - refreshLayoutClass: new CustomRefreshLoadLayoutClass(this.isVisiblePullDown, - this.pullDownRefreshImage, this.pullDownRefreshText, this.pullDownRefreshHeight) - }); + refreshLayoutClass: new CustomRefreshLoadLayoutClass(this.newsModel.isVisiblePullDown, this.newsModel.pullDownRefreshImage, + this.newsModel.pullDownRefreshText, this.newsModel.pullDownRefreshHeight) + }) ... } } @@ -277,65 +323,75 @@ build() { } ``` -在onTouch事件中,listTouchEvent方法判断触摸事件是否满足下拉条件。示例代码如下: +1. 在onTouch事件中,listTouchEvent方法判断触摸事件是否满足下拉条件。如下listTouchEvent所示: +2. 在touchMovePullRefresh方法中,我们将对下拉的偏移量与下拉刷新布局的高度进行对比,如果大于布局高度并且在新闻列表的顶部,则表示达到刷新条件。如下touchMovePullRefresh所示: +3. 在pullRefreshState方法中我们会对下拉刷新布局中的状态图片和描述进行改变,如下pullRefreshState所示: +4. 当手指松开,才执行刷新操作。 ```typescript -export function listTouchEvent(event: TouchEvent) { +// PullDownRefresh.ets +export function listTouchEvent(newsModel: NewsModel, event: TouchEvent) { switch (event.type) { ... case TouchType.Move: - let isDownPull = event.touches[0].y - this.lastMoveY > 0 - if ((isDownPull || this.isPullRefreshOperation) && !this.isCanLoadMore) { - // 手指移动,处理下拉刷新 - touchMovePullRefresh.call(this,event); + if ((newsModel.isRefreshing === true) || (newsModel.isLoading === true)) { + return; + } + let isDownPull = event.touches[0].y - newsModel.lastMoveY > 0; + if (((isDownPull === true) || (newsModel.isPullRefreshOperation === true)) && (newsModel.isCanLoadMore === false)) + { + // 手指移动,处理下拉刷新 + touchMovePullRefresh(newsModel, event); } ... break; } } -``` -在touchMovePullRefresh方法中,我们将对下拉的偏移量与下拉刷新布局的高度进行对比,如果大于布局高度并且在新闻列表的顶部,则表示达到刷新条件。 - -示例代码如下: - -```typescript -export function touchMovePullRefresh(event: TouchEvent) { - if (this.startIndex === 0) { - this.isPullRefreshOperation = true; - let height = vp2px(this.pullDownRefreshHeight); - this.offsetY = event.touches[0].y - this.downY; - // 滑动的偏移量大于下拉刷新布局高度,达到刷新条件 - if (this.offsetY >= height) { - pullRefreshState.call(this, RefreshState.Release); - ... +export function touchMovePullRefresh(newsModel: NewsModel, event: TouchEvent) { + if (newsModel.startIndex === 0) { + newsModel.isPullRefreshOperation = true; + let height = vp2px(newsModel.pullDownRefreshHeight); + newsModel.offsetY = event.touches[0].y - newsModel.downY; + // 滑动偏移量大于下拉刷新布局高度,满足刷新条件。 + if (newsModel.offsetY >= height) { + pullRefreshState(newsModel, RefreshState.Release); + newsModel.offsetY = height + newsModel.offsetY * Const.Y_OFF_SET_COEFFICIENT; } else { - pullRefreshState.call(this, RefreshState.DropDown); + pullRefreshState(newsModel, RefreshState.DropDown); + } + if (newsModel.offsetY < 0) { + newsModel.offsetY = 0; + newsModel.isPullRefreshOperation = false; } - ... } } -``` - -在pullRefreshState方法中我们会对下拉刷新布局中的状态图片和描述进行改变,此处不做详细介绍。 -当手指松开,才执行刷新操作。示例代码如下: - -```typescript -export function pullRefreshState(state: number) { +export function pullRefreshState(newsModel: NewsModel, state: number) { switch (state) { ... - case TouchType.Up: - if (this.isRefreshing || this.isLoading) { - return; - } - if (this.isPullRefreshOperation) { - // 手指抬起,处理下拉刷新 - touchUpPullRefresh.call(this); - } - ... + case RefreshState.Release: + newsModel.pullDownRefreshText = $r('app.string.release_refresh_text'); + newsModel.pullDownRefreshImage = $r('app.media.ic_pull_up_refresh'); + newsModel.isCanRefresh = true; + newsModel.isRefreshing = false; + break; + case RefreshState.Refreshing: + newsModel.offsetY = vp2px(newsModel.pullDownRefreshHeight); + newsModel.pullDownRefreshText = $r('app.string.refreshing_text'); + newsModel.pullDownRefreshImage = $r('app.media.ic_pull_up_load'); + newsModel.isCanRefresh = true; + newsModel.isRefreshing = true; + break; + case RefreshState.Success: + newsModel.pullDownRefreshText = $r('app.string.refresh_success_text'); + newsModel.pullDownRefreshImage = $r('app.media.ic_succeed_refresh'); + newsModel.isCanRefresh = true; + newsModel.isRefreshing = true; break; ... + default: + break; } } ``` @@ -346,9 +402,9 @@ export function pullRefreshState(state: number) { 您已经完成了本次Codelab的学习,并了解到以下知识点: -1. 使用List组件实现数据列表。 -2. 使用Tabs、TabContent组件实现内容视图切换。 -3. 网络数据请求。 -4. 触摸事件onTouch的用法。 +1. 使用List组件实现数据列表。 +2. 使用Tabs、TabContent组件实现内容视图切换。 +3. 网络数据请求。 +4. 触摸事件onTouch的使用。 -![](figures/summarize.gif) \ No newline at end of file +![](screenshots/device/summary.gif) \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/constant/CommonConstant.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/constant/CommonConstant.ets index cbe72578f65192f010f9d69d96b16a283509a867..50e05245cca314b2347e1897f6c219d26f2fb32d 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/constant/CommonConstant.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/constant/CommonConstant.ets @@ -13,94 +13,91 @@ * limitations under the License. */ -/** - * The host address of the server. - */ -export const SERVER: string = 'http://**.**.**.**:**'; - -/** - * Get the news type. - */ -export const GET_NEWS_TYPE: string = 'getNewsType'; - -/** - * Get the news list. - */ -export const GET_NEWS_LIST: string = 'getNewsList'; - -/** - * The request success status code. - */ -export const SERVER_CODE_SUCCESS: string = 'success'; - -/** - * The off set coefficient. - */ -export const Y_OFF_SET_COEFFICIENT: number = 0.1; - -/** - * The page size. - */ -export const PAGE_SIZE: number = 10; - -/** - * The refresh and load height. - */ -export const CUSTOM_LAYOUT_HEIGHT: number = 70; - -/** - * Gt tab data current page. - */ -export const GET_TAB_DATA_CURRENT_PAGE: number = 1; - -/** - * Http request success status code. - */ -export const HTTP_CODE_200: number = 200; - -/** - * The animation delay time. - */ -export const DELAY_ANIMATION_DURATION: number = 300; - -/** - * The delay time. - */ -export const DELAY_TIME: number = 1000; - -/** - * The animation duration. - */ -export const ANIMATION_DURATION: number = 2000; - -/** - * The http timeout duration. - */ -export const HTTP_READ_TIMEOUT: number = 10000; - -/** - * Full the width. - */ -export const FULL_WIDTH: string = '100%'; - -/** - * Full the height. - */ -export const FULL_HEIGHT: string = '100%'; - -/** - * The TabBars constants. - */ -export const TabBars = { - UN_SELECT_TEXT_FONT_SIZE: 18, - SELECT_TEXT_FONT_SIZE: 24, - UN_SELECT_TEXT_FONT_WEIGHT: 400, - SELECT_TEXT_FONT_WEIGHT: 700, - BAR_HEIGHT: '7.2%', - HORIZONTAL_PADDING: '2.2%', - BAR_WIDTH: '100%', - DEFAULT_NEWS_TYPES: - [ +import { NewsTypeBean } from '../../viewmodel/NewsViewModel'; + +export class CommonConstant { + + /** + * The host address of the server. + */ + static readonly SERVER: string = 'http://**.**.**.**:9588'; + + /** + * Get the news type. + */ + static readonly GET_NEWS_TYPE: string = 'news/getNewsType'; + + /** + * Get the news list. + */ + static readonly GET_NEWS_LIST: string = 'news/getNewsList'; + + /** + * The request success status code. + */ + static readonly SERVER_CODE_SUCCESS: string = 'success'; + + /** + * The off set coefficient. + */ + static readonly Y_OFF_SET_COEFFICIENT: number = 0.1; + + /** + * The page size. + */ + static readonly PAGE_SIZE: number = 4; + + /** + * The refresh and load height. + */ + static readonly CUSTOM_LAYOUT_HEIGHT: number = 70; + + /** + * Http request success status code. + */ + static readonly HTTP_CODE_200: number = 200; + + /** + * The animation delay time. + */ + static readonly DELAY_ANIMATION_DURATION: number = 300; + + /** + * The delay time. + */ + static readonly DELAY_TIME: number = 1000; + + /** + * The animation duration. + */ + static readonly ANIMATION_DURATION: number = 2000; + + /** + * The http timeout duration. + */ + static readonly HTTP_READ_TIMEOUT: number = 10000; + + /** + * Full the width. + */ + static readonly FULL_WIDTH: string = '100%'; + + /** + * Full the height. + */ + static readonly FULL_HEIGHT: string = '100%'; + + /** + * The TabBars constants. + */ + static readonly TabBars_UN_SELECT_TEXT_FONT_SIZE: number = 18; + static readonly TabBars_SELECT_TEXT_FONT_SIZE: number = 24; + static readonly TabBars_UN_SELECT_TEXT_FONT_WEIGHT: number = 400; + static readonly TabBars_SELECT_TEXT_FONT_WEIGHT: number = 700; + static readonly TabBars_BAR_HEIGHT: string = '7.2%'; + static readonly TabBars_HORIZONTAL_PADDING: string = '2.2%'; + static readonly TabBars_BAR_WIDTH: string = '100%'; + static readonly TabBars_DEFAULT_NEWS_TYPES: Array = [ { id: 0, name: '全部' }, { id: 1, name: '国内' }, { id: 2, name: '国际' }, @@ -109,102 +106,99 @@ export const TabBars = { { id: 5, name: '体育' }, { id: 6, name: '科技' }, { id: 7, name: '财经' } - ] -} - -/** - * The NewsListConstant constants. - */ -export const NewsListConstant = { - LIST_DIVIDER_STROKE_WIDTH: 0.5, - GET_TAB_DATA_TYPE_ONE: 1, - ITEM_BORDER_RADIUS: 16, - NONE_IMAGE_SIZE: 120, - NONE_TEXT_opacity: 0.6, - NONE_TEXT_size: 16, - NONE_TEXT_margin: 12, - ITEM_MARGIN_TOP: '1.5%', - LIST_MARGIN_LEFT: '3.3%', - LIST_MARGIN_RIGHT: '3.3%', - ITEM_HEIGHT: '32%', - LIST_WIDTH: '93.3%' -} - -/** - * The NewsTitle constants. - */ -export const NewsTitle = { - TEXT_MAX_LINES: 3, - TEXT_FONT_SIZE: 20, - TEXT_FONT_WEIGHT: 500, - TEXT_MARGIN_LEFT: '2.4%', - TEXT_MARGIN_TOP: '7.2%', - TEXT_HEIGHT: '9.6%', - TEXT_WIDTH: '78.6%', - IMAGE_MARGIN_LEFT: '3.5%', - IMAGE_MARGIN_TOP: '7.9%', - IMAGE_HEIGHT: '8.9%', - IMAGE_WIDTH: '11.9%', -} - -/** - * The NewsContent constants. - */ -export const NewsContent = { - WIDTH: '93%', - HEIGHT: '16.8%', - MARGIN_LEFT: '3.5%', - MARGIN_TOP: '3.4%', - MAX_LINES: 3, - FONT_SIZE: 15, -} - -/** - * The NewsSource constants. - */ -export const NewsSource = { - MAX_LINES: 1, - FONT_SIZE: 12, - MARGIN_LEFT: '3.5%', - MARGIN_TOP: '3.4%', - HEIGHT: '7.2%', - WIDTH: '93%', -} - -/** - * The NewsGrid constants. - */ -export const NewsGrid = { - MARGIN_LEFT: '3.5%', - MARGIN_RIGHT: '3.5%', - MARGIN_TOP: '5.1%', - WIDTH: '93%', - HEIGHT: '31.5%', - ASPECT_RATIO: 4, - COLUMNS_GAP: 5, - ROWS_TEMPLATE: '1fr', - IMAGE_BORDER_RADIUS: 8 -} - -/** - * The RefreshLayout constants. - */ -export const RefreshLayout = { - MARGIN_LEFT: '40%', - TEXT_MARGIN_BOTTOM: 1, - TEXT_MARGIN_LEFT: 7, - TEXT_FONT_SIZE: 17, - IMAGE_WIDTH: 18, - IMAGE_HEIGHT: 18 -} - -/** - * The RefreshConstant constants. - */ -export const RefreshConstant = { - DELAY_PULL_DOWN_REFRESH: 50, - CLOSE_PULL_DOWN_REFRESH_TIME: 150, - DELAY_SHRINK_ANIMATION_TIME: 500, + ]; + + /** + * The NewsListConstant constants. + */ + static readonly NewsListConstant_LIST_DIVIDER_STROKE_WIDTH: number = 0.5; + static readonly NewsListConstant_GET_TAB_DATA_TYPE_ONE: number = 1; + static readonly NewsListConstant_ITEM_BORDER_RADIUS: number = 16; + static readonly NewsListConstant_NONE_IMAGE_SIZE: number = 120; + static readonly NewsListConstant_NONE_TEXT_opacity: number = 0.6; + static readonly NewsListConstant_NONE_TEXT_size: number = 16; + static readonly NewsListConstant_NONE_TEXT_margin: number = 12; + // static readonly NewsListConstant_ITEM_MARGIN_TOP: string = '1.5%'; + static readonly NewsListConstant_LIST_MARGIN_LEFT: string = '3.3%'; + static readonly NewsListConstant_LIST_MARGIN_RIGHT: string = '3.3%'; + // static readonly NewsListConstant_ITEM_HEIGHT: string = '32%'; + static readonly NewsListConstant_LIST_WIDTH: string = '93.3%'; + + /** + * The NewsTitle constants. + */ + static readonly NewsTitle_TEXT_FONT_SIZE: number = 20; + static readonly NewsTitle_TEXT_FONT_WEIGHT: number = 500; + static readonly NewsTitle_TEXT_MARGIN_LEFT: string = '2.4%'; + static readonly NewsTitle_TEXT_WIDTH: string = '78.6%'; + static readonly NewsTitle_IMAGE_MARGIN_LEFT: string = '3.5%'; + static readonly NewsTitle_IMAGE_WIDTH: string = '11.9%'; + + /** + * The NewsContent constants. + */ + static readonly NewsContent_WIDTH: string = '93%'; + static readonly NewsContent_HEIGHT: string = '16.8%'; + static readonly NewsContent_MARGIN_LEFT: string = '3.5%'; + static readonly NewsContent_MARGIN_TOP: string = '3.4%'; + static readonly NewsContent_MAX_LINES: number = 2; + static readonly NewsContent_FONT_SIZE: number = 15; + + /** + * The NewsSource constants. + */ + static readonly NewsSource_MAX_LINES: number = 1; + static readonly NewsSource_FONT_SIZE: number = 12; + static readonly NewsSource_MARGIN_LEFT: string = '3.5%'; + static readonly NewsSource_MARGIN_TOP: string = '3.4%'; + static readonly NewsSource_HEIGHT: string = '7.2%'; + static readonly NewsSource_WIDTH: string = '93%'; + + /** + * The NewsGrid constants. + */ + static readonly NewsGrid_MARGIN_LEFT: string = '3.5%'; + static readonly NewsGrid_MARGIN_RIGHT: string = '3.5%'; + static readonly NewsGrid_MARGIN_TOP: string = '5.1%'; + static readonly NewsGrid_WIDTH: string = '93%'; + static readonly NewsGrid_HEIGHT: string = '31.5%'; + static readonly NewsGrid_ASPECT_RATIO: number = 4; + static readonly NewsGrid_COLUMNS_GAP: number = 5; + static readonly NewsGrid_ROWS_TEMPLATE: string = '1fr'; + static readonly NewsGrid_IMAGE_BORDER_RADIUS: number = 8; + + /** + * The RefreshLayout constants. + */ + static readonly RefreshLayout_MARGIN_LEFT: string = '40%'; + static readonly RefreshLayout_TEXT_MARGIN_BOTTOM: number = 1; + static readonly RefreshLayout_TEXT_MARGIN_LEFT: number = 7; + static readonly RefreshLayout_TEXT_FONT_SIZE: number = 17; + static readonly RefreshLayout_IMAGE_WIDTH: number = 18; + static readonly RefreshLayout_IMAGE_HEIGHT: number = 18; + + /** + * The NoMoreLayout constants. + */ + static readonly NoMoreLayoutConstant_NORMAL_PADDING: number = 8; + static readonly NoMoreLayoutConstant_TITLE_FONT: string = '16fp'; + + /** + * The RefreshConstant constants. + */ + static readonly RefreshConstant_DELAY_PULL_DOWN_REFRESH: number = 50; + static readonly RefreshConstant_CLOSE_PULL_DOWN_REFRESH_TIME: number = 150; + static readonly RefreshConstant_DELAY_SHRINK_ANIMATION_TIME: number = 500; + + /** + * Grid column templates. + */ + static readonly GRID_COLUMN_TEMPLATES: string = '1fr '; + + /** + * List offset unit. + */ + static readonly LIST_OFFSET_UNIT: string = 'px'; } /** @@ -228,56 +222,8 @@ export const enum PageState { } /** - * The host address of the default server. - */ -export const DEFAULT_SERVER: string = 'http://**.**.**.**:**'; - -/** - * Local analog data. + * The request content type enum. */ -export const LOCAL_DATA = [ - { - id: 0, - title: '入春来,百花香', - content: '随着气温升高,连日来,某某县某某街道的各个角度盛开了各种各样的花朵,让人眼花缭乱,装点了春天的气息。', - imagesUrl: - [ - { id: 1, url: $r('app.media.ic_news_1_1') }, - { id: 2, url: $r('app.media.ic_news_1_2') }, - { id: 3, url: $r('app.media.ic_news_1_3') } - ] - }, - { - id: 1, - title: '第四届美食节正式启动', - content: '8月5日,某某市第四届美食节正式启动。美食节将围绕各地特色美食展开,推进各地美食文化交流。', - imagesUrl: - [ - { id: 1, url: $r('app.media.ic_news_2_1') }, - { id: 2, url: $r('app.media.ic_news_2_1') }, - { id: 3, url: $r('app.media.ic_news_2_1') } - ] - }, - { - id: 2, - title: '江南风景美如画', - content: '南朝四百八十寺,多少楼台烟雨中。江南美,去过风光绮丽的江南,便久久不能忘怀,江南的雨如沐春风。', - imagesUrl: - [ - { id: 1, url: $r('app.media.ic_news_3_1') }, - { id: 2, url: $r('app.media.ic_news_3_2') }, - { id: 3, url: $r('app.media.ic_news_3_3') } - ] - }, - { - id: 3, - title: '好物推荐', - content: '精选好物,提升家居氛围,享受美好生活。', - imagesUrl: - [ - { id: 1, url: $r('app.media.ic_news_4_1') }, - { id: 2, url: $r('app.media.ic_news_4_2') }, - { id: 3, url: $r('app.media.ic_news_4_2') } - ] - } -] \ No newline at end of file +export const enum ContentType { + JSON = 'application/json' +} \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/DataUtils.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/DataUtils.ets deleted file mode 100644 index d5cb3020999911b5d4b2498e49b7a541461f1ff7..0000000000000000000000000000000000000000 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/DataUtils.ets +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2021 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 promptAction from '@ohos.promptAction'; -import { - SERVER, - GET_NEWS_TYPE, - GET_NEWS_LIST, - GET_TAB_DATA_CURRENT_PAGE, - SERVER_CODE_SUCCESS, - LOCAL_DATA, - DEFAULT_SERVER -} from '../constant/CommonConstant'; -import { httpRequestGet } from '../utils/HttpUtil'; - -/** - * Initiate request for tab data. - * - * @param currentPage The current page number. - * @param pageSize The number of current pages. - * @param currentIndex The current index. - * @param callback The function callback. - */ -export async function getTabData(currentPage: number, pageSize: number, currentIndex: number, callback) { - currentPage = currentPage + GET_TAB_DATA_CURRENT_PAGE; - let newsPageData = []; - if (SERVER === DEFAULT_SERVER) { - newsPageData = LOCAL_DATA; - callback.onSuccess({ currentPage, newsPageData }); - return; - } - if (currentPage > pageSize) { - promptAction.showToast({ message: $r('app.string.prompt_message') }); - currentPage = currentPage - GET_TAB_DATA_CURRENT_PAGE; - } - let url = `${SERVER}/${GET_NEWS_LIST}`; - let params = { 'currentPage': currentPage, 'pageSize': pageSize, 'currentIndex': currentIndex }; - let data = await httpRequestGet(url, params); - if (data.code === SERVER_CODE_SUCCESS) { - newsPageData = data.data.pageData; - callback.onSuccess({ currentPage, newsPageData }); - } else { - callback.onFail(data.msg); - } -} - -/** - * Initiate request news type. - * - * @param callback The function callback. - */ -export async function loadNewsTypes(callback) { - let tabBars = []; - let url = `${SERVER}/${GET_NEWS_TYPE}`; - let data = await httpRequestGet(url, null); - if (data.code === SERVER_CODE_SUCCESS) { - tabBars = data.data; - callback.onSuccess(tabBars); - } else { - callback.onFail(data.msg); - } -} \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/HttpUtil.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/HttpUtil.ets index c416aa651061ce437a96d191320e64f798c56369..3582208f4bd3d26f772972dc708798cdfd479327 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/HttpUtil.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/HttpUtil.ets @@ -14,7 +14,8 @@ */ import http from '@ohos.net.http'; -import { HTTP_READ_TIMEOUT, HTTP_CODE_200, SERVER_CODE_SUCCESS } from '../constant/CommonConstant'; +import { ResponseResult } from '../../viewmodel/NewsViewModel'; +import { CommonConstant as Const, ContentType } from '../constant/CommonConstant'; /** * Initiates an HTTP request to a given URL. @@ -22,35 +23,30 @@ import { HTTP_READ_TIMEOUT, HTTP_CODE_200, SERVER_CODE_SUCCESS } from '../consta * @param url URL for initiating an HTTP request. * @param params Params for initiating an HTTP request. */ -export function httpRequestGet(url: string, params: any) { - if (params) { - url = `${url}?${'currentPage'}=${params.currentPage}&${'pageSize'}=${params.pageSize}` - + `&${'currentIndex'}=${params.currentIndex}`; - } +export function httpRequestGet(url: string): Promise { let httpRequest = http.createHttp(); let responseResult = httpRequest.request(url, { method: http.RequestMethod.GET, - readTimeout: HTTP_READ_TIMEOUT, - connectTimeout: HTTP_READ_TIMEOUT + readTimeout: Const.HTTP_READ_TIMEOUT, + header: { + 'Content-Type': ContentType.JSON + }, + connectTimeout: Const.HTTP_READ_TIMEOUT, + extraData: {} }); - let serverData: { - code, - data: any, - msg: string | Resource - } = { code: 0, data: '', msg: '' }; + let serverData: ResponseResult = new ResponseResult(); // Processes the data and returns. - return responseResult.then((value) => { - if (value.responseCode === HTTP_CODE_200) { + return responseResult.then((value: http.HttpResponse) => { + if (value.responseCode === Const.HTTP_CODE_200) { // Obtains the returned data. let result = `${value.result}`; - let resultJson = JSON.parse(result); - if (resultJson.code === SERVER_CODE_SUCCESS) { + let resultJson: ResponseResult = JSON.parse(result); + if (resultJson.code === Const.SERVER_CODE_SUCCESS) { serverData.data = resultJson.data; } serverData.code = resultJson.code; serverData.msg = resultJson.msg; } else { - serverData.code = value.responseCode; serverData.msg = `${$r('app.string.http_error_message')}&${value.responseCode}`; } return serverData; @@ -58,5 +54,4 @@ export function httpRequestGet(url: string, params: any) { serverData.msg = $r('app.string.http_error_message'); return serverData; }) -} - +} \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/Logger.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..4403cc9351585be51eb44295df6dfc2e9f19a158 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/Logger.ets @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog'; + +const LOGGER_PREFIX: string = 'News Release'; + +class Logger { + private domain: number; + private prefix: string; + + // format Indicates the log format string. + private format: string = '%{public}s, %{public}s'; + + /** + * constructor. + * + * @param prefix Identifies the log tag. + * @param domain Indicates the service domain, which is a hexadecimal integer ranging from 0x0 to 0xFFFFF + * @param args Indicates the log parameters. + */ + constructor(prefix: string = '', domain: number = 0xFF00) { + this.prefix = prefix; + this.domain = domain; + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger(LOGGER_PREFIX); \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/PullDownRefresh.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/PullDownRefresh.ets index 8b569f795f29c915b43f9667b7f4e84b63c68177..68852835e278811efd5e11d4b3f062cee241b5e8 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/PullDownRefresh.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/PullDownRefresh.ets @@ -14,48 +14,47 @@ */ import promptAction from '@ohos.promptAction'; -import { getTabData } from './DataUtils'; import { touchMoveLoadMore, touchUpLoadMore } from './PullUpLoadMore'; import { - DELAY_TIME, - DELAY_ANIMATION_DURATION, - Y_OFF_SET_COEFFICIENT, - RefreshState, - RefreshConstant + CommonConstant as Const, + RefreshState } from '../constant/CommonConstant'; +import NewsViewModel, { NewsData } from '../../viewmodel/NewsViewModel'; +import NewsModel from '../../viewmodel/NewsModel'; -export function listTouchEvent(event: TouchEvent) { +export function listTouchEvent(newsModel: NewsModel, event: TouchEvent) { switch (event.type) { case TouchType.Down: - this.downY = event.touches[0].y; - this.lastMoveY = event.touches[0].y; + newsModel.downY = event.touches[0].y; + newsModel.lastMoveY = event.touches[0].y; break; case TouchType.Move: - if (this.isRefreshing || this.isLoading) { + if ((newsModel.isRefreshing === true) || (newsModel.isLoading === true)) { return; } - let isDownPull = event.touches[0].y - this.lastMoveY > 0; - if ((isDownPull || this.isPullRefreshOperation) && !this.isCanLoadMore) { + let isDownPull = event.touches[0].y - newsModel.lastMoveY > 0; + if (((isDownPull === true) || (newsModel.isPullRefreshOperation === true)) && (newsModel.isCanLoadMore === false)) + { // Finger movement, processing pull-down refresh. - touchMovePullRefresh.call(this, event); + touchMovePullRefresh(newsModel, event); } else { // Finger movement, processing load more. - touchMoveLoadMore.call(this, event); + touchMoveLoadMore(newsModel, event); } - this.lastMoveY = event.touches[0].y; + newsModel.lastMoveY = event.touches[0].y; break; case TouchType.Cancel: break; case TouchType.Up: - if (this.isRefreshing || this.isLoading) { + if ((newsModel.isRefreshing === true) || (newsModel.isLoading === true)) { return; } - if (this.isPullRefreshOperation) { + if ((newsModel.isPullRefreshOperation === true)) { // Lift your finger and pull down to refresh. - touchUpPullRefresh.call(this); + touchUpPullRefresh(newsModel); } else { // Fingers up, handle loading more. - touchUpLoadMore.call(this); + touchUpLoadMore(newsModel); } break; default: @@ -63,105 +62,109 @@ export function listTouchEvent(event: TouchEvent) { } } -export function touchMovePullRefresh(event: TouchEvent) { - if (this.startIndex === 0) { - this.isPullRefreshOperation = true; - let height = vp2px(this.pullDownRefreshHeight); - this.offsetY = event.touches[0].y - this.downY; +export function touchMovePullRefresh(newsModel: NewsModel, event: TouchEvent) { + if (newsModel.startIndex === 0) { + newsModel.isPullRefreshOperation = true; + let height = vp2px(newsModel.pullDownRefreshHeight); + newsModel.offsetY = event.touches[0].y - newsModel.downY; // The sliding offset is greater than the pull-down refresh layout height, and the refresh condition is met. - if (this.offsetY >= height) { - pullRefreshState.call(this, RefreshState.Release); - this.offsetY = height + this.offsetY * Y_OFF_SET_COEFFICIENT; + if (newsModel.offsetY >= height) { + pullRefreshState(newsModel, RefreshState.Release); + newsModel.offsetY = height + newsModel.offsetY * Const.Y_OFF_SET_COEFFICIENT; } else { - pullRefreshState.call(this, RefreshState.DropDown); + pullRefreshState(newsModel, RefreshState.DropDown); } - if (this.offsetY < 0) { - this.offsetY = 0; - this.isPullRefreshOperation = false; + if (newsModel.offsetY < 0) { + newsModel.offsetY = 0; + newsModel.isPullRefreshOperation = false; } } } -export function touchUpPullRefresh() { - if (this.isCanRefresh) { - this.offsetY = vp2px(this.pullDownRefreshHeight); - pullRefreshState.call(this, RefreshState.Refreshing); +export function touchUpPullRefresh(newsModel: NewsModel) { + if (newsModel.isCanRefresh === true) { + newsModel.offsetY = vp2px(newsModel.pullDownRefreshHeight); + pullRefreshState(newsModel, RefreshState.Refreshing); + newsModel.currentPage = 1; setTimeout(() => { - let self = this; - getTabData(self.currentPage, self.pageSize, self.currentIndex, { - onSuccess: (value) => { - self.currentPage = parseInt(value.currentPage.toString()); - self.newsData = value.newsPageData; - closeRefresh.call(self, true); - }, - onFail: (msg) => { - promptAction.showToast({ message: msg }); - closeRefresh.call(self, false); + let self: NewsModel = newsModel; + NewsViewModel.getNewsList(newsModel.currentPage, newsModel.pageSize, Const.GET_NEWS_LIST).then((data: + NewsData[]) => { + if (data.length === newsModel.pageSize) { + self.hasMore = true; + self.currentPage++; + } else { + self.hasMore = false; } + self.newsData = data; + closeRefresh(self, true); + }).catch((err: string | Resource) => { + promptAction.showToast({ message: err }); + closeRefresh(self, false); }); - }, DELAY_TIME); + }, Const.DELAY_TIME); } else { - closeRefresh.call(this, false); + closeRefresh(newsModel, false); } } -export function pullRefreshState(state: number) { +export function pullRefreshState(newsModel: NewsModel, state: number) { switch (state) { case RefreshState.DropDown: - this.pullDownRefreshText = $r('app.string.pull_down_refresh_text'); - this.pullDownRefreshImage = $r("app.media.ic_pull_down_refresh"); - this.isCanRefresh = false; - this.isRefreshing = false; - this.isVisiblePullDown = true; + newsModel.pullDownRefreshText = $r('app.string.pull_down_refresh_text'); + newsModel.pullDownRefreshImage = $r('app.media.ic_pull_down_refresh'); + newsModel.isCanRefresh = false; + newsModel.isRefreshing = false; + newsModel.isVisiblePullDown = true; break; case RefreshState.Release: - this.pullDownRefreshText = $r('app.string.release_refresh_text'); - this.pullDownRefreshImage = $r("app.media.ic_pull_up_refresh"); - this.isCanRefresh = true; - this.isRefreshing = false; + newsModel.pullDownRefreshText = $r('app.string.release_refresh_text'); + newsModel.pullDownRefreshImage = $r('app.media.ic_pull_up_refresh'); + newsModel.isCanRefresh = true; + newsModel.isRefreshing = false; break; case RefreshState.Refreshing: - this.offsetY = vp2px(this.pullDownRefreshHeight); - this.pullDownRefreshText = $r('app.string.refreshing_text'); - this.pullDownRefreshImage = $r("app.media.ic_pull_up_load"); - this.isCanRefresh = true; - this.isRefreshing = true; + newsModel.offsetY = vp2px(newsModel.pullDownRefreshHeight); + newsModel.pullDownRefreshText = $r('app.string.refreshing_text'); + newsModel.pullDownRefreshImage = $r('app.media.ic_pull_up_load'); + newsModel.isCanRefresh = true; + newsModel.isRefreshing = true; break; case RefreshState.Success: - this.pullDownRefreshText = $r('app.string.refresh_success_text'); - this.pullDownRefreshImage = $r("app.media.ic_succeed_refresh"); - this.isCanRefresh = true; - this.isRefreshing = true; + newsModel.pullDownRefreshText = $r('app.string.refresh_success_text'); + newsModel.pullDownRefreshImage = $r('app.media.ic_succeed_refresh'); + newsModel.isCanRefresh = true; + newsModel.isRefreshing = true; break; case RefreshState.Fail: - this.pullDownRefreshText = $r('app.string.refresh_fail_text'); - this.pullDownRefreshImage = $r("app.media.ic_fail_refresh"); - this.isCanRefresh = true; - this.isRefreshing = true; + newsModel.pullDownRefreshText = $r('app.string.refresh_fail_text'); + newsModel.pullDownRefreshImage = $r('app.media.ic_fail_refresh'); + newsModel.isCanRefresh = true; + newsModel.isRefreshing = true; break; default: break; } } -export function closeRefresh(isRefreshSuccess: boolean) { - let self = this; +export function closeRefresh(newsModel: NewsModel, isRefreshSuccess: boolean) { + let self = newsModel; setTimeout(() => { - let delay = RefreshConstant.DELAY_PULL_DOWN_REFRESH; - if (self.isCanRefresh) { - pullRefreshState.call(this, isRefreshSuccess ? RefreshState.Success : RefreshState.Fail); - delay = RefreshConstant.DELAY_SHRINK_ANIMATION_TIME; + let delay = Const.RefreshConstant_DELAY_PULL_DOWN_REFRESH; + if (self.isCanRefresh === true) { + pullRefreshState(newsModel, isRefreshSuccess ? RefreshState.Success : RefreshState.Fail); + delay = Const.RefreshConstant_DELAY_SHRINK_ANIMATION_TIME; } animateTo({ - duration: RefreshConstant.CLOSE_PULL_DOWN_REFRESH_TIME, + duration: Const.RefreshConstant_CLOSE_PULL_DOWN_REFRESH_TIME, delay: delay, onFinish: () => { - pullRefreshState.call(this, RefreshState.DropDown); + pullRefreshState(newsModel, RefreshState.DropDown); self.isVisiblePullDown = false; self.isPullRefreshOperation = false; } }, () => { self.offsetY = 0; }) - }, self.isCanRefresh ? DELAY_ANIMATION_DURATION : 0); + }, self.isCanRefresh ? Const.DELAY_ANIMATION_DURATION : 0); } \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/PullUpLoadMore.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/PullUpLoadMore.ets index 1b1326a4d3135c69da06f522115b1e36899ae1c6..3a54826d9d580aa2566f15d88baa5f77597e1f95 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/PullUpLoadMore.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/utils/PullUpLoadMore.ets @@ -14,46 +14,51 @@ */ import promptAction from '@ohos.promptAction'; -import { getTabData } from '../utils/DataUtils'; -import { DELAY_TIME, ANIMATION_DURATION, Y_OFF_SET_COEFFICIENT } from '../constant/CommonConstant'; +import { CommonConstant as Const } from '../constant/CommonConstant'; +import NewsViewModel, { NewsData } from '../../viewmodel/NewsViewModel'; +import NewsModel from '../../viewmodel/NewsModel'; -export function touchMoveLoadMore(event: TouchEvent) { - if (this.endIndex === this.newsData.length - 1 || this.endIndex === this.newsData.length) { - this.offsetY = event.touches[0].y - this.downY; - if (Math.abs(this.offsetY) > vp2px(this.pullUpLoadHeight) / 2) { - this.isCanLoadMore = true; - this.isVisiblePullUpLoad = true; - this.offsetY = -vp2px(this.pullUpLoadHeight) + this.offsetY * Y_OFF_SET_COEFFICIENT; +export function touchMoveLoadMore(newsModel: NewsModel, event: TouchEvent) { + if (newsModel.endIndex === newsModel.newsData.length - 1 || newsModel.endIndex === newsModel.newsData.length) { + newsModel.offsetY = event.touches[0].y - newsModel.downY; + if (Math.abs(newsModel.offsetY) > vp2px(newsModel.pullUpLoadHeight) / 2) { + newsModel.isCanLoadMore = true; + newsModel.isVisiblePullUpLoad = true; + newsModel.offsetY = -vp2px(newsModel.pullUpLoadHeight) + newsModel.offsetY * Const.Y_OFF_SET_COEFFICIENT; } } } -export function touchUpLoadMore() { - let self = this; +export function touchUpLoadMore(newsModel: NewsModel) { + let self: NewsModel = newsModel; animateTo({ - duration: ANIMATION_DURATION, + duration: Const.ANIMATION_DURATION, }, () => { self.offsetY = 0; }) - if (self.isCanLoadMore) { + if ((self.isCanLoadMore === true) && (self.hasMore === true)) { self.isLoading = true; setTimeout(() => { - closeLoadMore.call(this); - getTabData(self.currentPage, self.pageSize, self.currentIndex, { - onSuccess: (value) => { - self.currentPage = parseInt(value.currentPage.toString()); - self.newsData = self.newsData.concat(value.newsPageData); - }, - onFail: (msg) => promptAction.showToast({ message: msg }) - }); - }, DELAY_TIME); + closeLoadMore(newsModel); + NewsViewModel.getNewsList(self.currentPage, self.pageSize, Const.GET_NEWS_LIST).then((data: NewsData[]) => { + if (data.length === self.pageSize) { + self.currentPage++; + self.hasMore = true; + } else { + self.hasMore = false; + } + self.newsData = self.newsData.concat(data); + }).catch((err: string | Resource) => { + promptAction.showToast({ message: err }); + }) + }, Const.DELAY_TIME); } else { - closeLoadMore.call(this); + closeLoadMore(self); } } -export function closeLoadMore() { - this.isCanLoadMore = false; - this.isLoading = false; - this.isVisiblePullUpLoad = false; +export function closeLoadMore(newsModel: NewsModel) { + newsModel.isCanLoadMore = false; + newsModel.isLoading = false; + newsModel.isVisiblePullUpLoad = false; } \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/pages/Index.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/pages/Index.ets index 5b0fe89df5bbf0db8e893d2d1d1a759a06008c76..a895d9eb737aa5afe302b800a23554a8d1c5723e 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/pages/Index.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/pages/Index.ets @@ -14,7 +14,7 @@ */ import TabBar from '../view/TabBar'; -import { FULL_WIDTH } from '../common/constant/CommonConstant'; +import { CommonConstant as Const } from '../common/constant/CommonConstant'; /** * The Index is the entry point of the application. @@ -27,7 +27,7 @@ struct Index { Column() { TabBar() } - .width(FULL_WIDTH) + .width(Const.FULL_WIDTH) .backgroundColor($r('app.color.listColor')) .justifyContent(FlexAlign.Center) } diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/CustomRefreshLoadLayout.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/CustomRefreshLoadLayout.ets index 808acd2b29edbc2bdbe8b468aa2e6c823b18c896..26ec520963d1bbe91d81668087a77831f7593aba 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/CustomRefreshLoadLayout.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/CustomRefreshLoadLayout.ets @@ -13,8 +13,8 @@ * limitations under the License. */ -import { CustomRefreshLoadLayoutClass } from '../common/bean/NewsData'; -import { RefreshLayout, FULL_WIDTH } from '../common/constant/CommonConstant'; +import { CommonConstant as Const } from '../common/constant/CommonConstant'; +import { CustomRefreshLoadLayoutClass } from '../viewmodel/NewsViewModel'; /** * Custom layout to show refresh or load. @@ -26,15 +26,19 @@ export default struct CustomLayout { build() { Row() { Image(this.customRefreshLoadClass.imageSrc) - .width(RefreshLayout.IMAGE_WIDTH) - .height(RefreshLayout.IMAGE_HEIGHT) + .width(Const.RefreshLayout_IMAGE_WIDTH) + .height(Const.RefreshLayout_IMAGE_HEIGHT) Text(this.customRefreshLoadClass.textValue) - .margin({ left: RefreshLayout.TEXT_MARGIN_LEFT, - bottom: RefreshLayout.TEXT_MARGIN_BOTTOM }) - .fontSize(RefreshLayout.TEXT_FONT_SIZE).textAlign(TextAlign.Center) + .margin({ + left: Const.RefreshLayout_TEXT_MARGIN_LEFT, + bottom: Const.RefreshLayout_TEXT_MARGIN_BOTTOM + }) + .fontSize(Const.RefreshLayout_TEXT_FONT_SIZE) + .textAlign(TextAlign.Center) } - .width(FULL_WIDTH) + .clip(true) + .width(Const.FULL_WIDTH) .justifyContent(FlexAlign.Center) .height(this.customRefreshLoadClass.heightValue) } diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/LoadMoreLayout.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/LoadMoreLayout.ets index de67cf6f000dda6dda1c75c582aed99a8d233824..ef4bedc4f9b332f1db8dccb1e6d283536b5ae9d5 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/LoadMoreLayout.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/LoadMoreLayout.ets @@ -13,8 +13,8 @@ * limitations under the License. */ +import { CustomRefreshLoadLayoutClass } from '../viewmodel/NewsViewModel'; import CustomRefreshLoadLayout from './CustomRefreshLoadLayout'; -import { CustomRefreshLoadLayoutClass } from '../common/bean/NewsData'; /** * The load more layout component. diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NewsItem.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NewsItem.ets index b096eb184eabcf524439b0dd3cf83569fded3219..a5250f1e99616a942ad8eec8d15a35d50f8d90da 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NewsItem.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NewsItem.ets @@ -1,4 +1,3 @@ -import { NewsListConstant } from '../common/constant/CommonConstant'; /* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,71 +13,72 @@ import { NewsListConstant } from '../common/constant/CommonConstant'; * limitations under the License. */ -import { NewsData } from '../common/bean/NewsData'; -import { NewsSource, NewsContent, NewsTitle, NewsGrid } from '../common/constant/CommonConstant'; +import { CommonConstant, CommonConstant as Const } from '../common/constant/CommonConstant'; +import { NewsData, NewsFile } from '../viewmodel/NewsViewModel'; /** * The news list item component. */ @Component export default struct NewsItem { - private newsData: NewsData; + private newsData: NewsData = new NewsData(); build() { Column() { Row() { Image($r('app.media.news')) - .width(NewsTitle.IMAGE_WIDTH) - .height(NewsTitle.IMAGE_HEIGHT) - .margin({ - top: NewsTitle.IMAGE_MARGIN_TOP, - left: NewsTitle.IMAGE_MARGIN_LEFT - }) + .width(Const.NewsTitle_IMAGE_WIDTH) + .height($r('app.float.news_title_image_height')) .objectFit(ImageFit.Fill) Text(this.newsData.title) - .fontSize(NewsTitle.TEXT_FONT_SIZE) + .fontSize(Const.NewsTitle_TEXT_FONT_SIZE) .fontColor($r('app.color.fontColor_text')) - .height(NewsTitle.TEXT_HEIGHT) - .width(NewsTitle.TEXT_WIDTH) - .maxLines(NewsTitle.TEXT_MAX_LINES) - .margin({ left: NewsTitle.TEXT_MARGIN_LEFT, top: NewsTitle.TEXT_MARGIN_TOP }) + .width(Const.NewsTitle_TEXT_WIDTH) + .maxLines(1) + .margin({ left: Const.NewsTitle_TEXT_MARGIN_LEFT }) .textOverflow({ overflow: TextOverflow.Ellipsis }) - .fontWeight(NewsTitle.TEXT_FONT_WEIGHT) + .fontWeight(Const.NewsTitle_TEXT_FONT_WEIGHT) } + .alignItems(VerticalAlign.Center) + .height($r('app.float.news_title_row_height')) + .margin({ + top: $r('app.float.news_title_row_margin_top'), + left: Const.NewsTitle_IMAGE_MARGIN_LEFT + }) Text(this.newsData.content) - .fontSize(NewsContent.FONT_SIZE) + .fontSize(Const.NewsContent_FONT_SIZE) .fontColor($r('app.color.fontColor_text')) - .height(NewsContent.HEIGHT) - .width(NewsContent.WIDTH) - .maxLines(NewsContent.MAX_LINES) - .margin({ left: NewsContent.MARGIN_LEFT, top: NewsContent.MARGIN_TOP }) + .height(Const.NewsContent_HEIGHT) + .width(Const.NewsContent_WIDTH) + .maxLines(Const.NewsContent_MAX_LINES) + .margin({ left: Const.NewsContent_MARGIN_LEFT, top: Const.NewsContent_MARGIN_TOP }) .textOverflow({ overflow: TextOverflow.Ellipsis }) Grid() { - ForEach(this.newsData.imagesUrl, itemImg => { + ForEach(this.newsData.imagesUrl, (itemImg: NewsFile) => { GridItem() { - Image(itemImg.url) + Image(Const.SERVER + itemImg.url) .objectFit(ImageFit.Cover) - .borderRadius(NewsGrid.IMAGE_BORDER_RADIUS) + .borderRadius(Const.NewsGrid_IMAGE_BORDER_RADIUS) } - }, (itemImg, index) => JSON.stringify(itemImg) + index.toString()) + }, (itemImg: NewsFile, index?: number) => JSON.stringify(itemImg) + index) } - .columnsTemplate('1fr '.repeat(this.newsData.imagesUrl.length)) - .columnsGap(NewsGrid.COLUMNS_GAP) - .rowsTemplate(NewsGrid.ROWS_TEMPLATE) - .width(NewsGrid.WIDTH) - .height(NewsGrid.HEIGHT) - .margin({ left: NewsGrid.MARGIN_LEFT, top: NewsGrid.MARGIN_TOP, - right: NewsGrid.MARGIN_RIGHT }) + .columnsTemplate(CommonConstant.GRID_COLUMN_TEMPLATES.repeat(this.newsData.imagesUrl.length)) + .columnsGap(Const.NewsGrid_COLUMNS_GAP) + .rowsTemplate(Const.NewsGrid_ROWS_TEMPLATE) + .width(Const.NewsGrid_WIDTH) + .height(Const.NewsGrid_HEIGHT) + .margin({ left: Const.NewsGrid_MARGIN_LEFT, top: Const.NewsGrid_MARGIN_TOP, + right: Const.NewsGrid_MARGIN_RIGHT }) Text(this.newsData.source) - .fontSize(NewsSource.FONT_SIZE) + .fontSize(Const.NewsSource_FONT_SIZE) .fontColor($r('app.color.fontColor_text2')) - .height(NewsSource.HEIGHT) - .width(NewsSource.WIDTH) - .maxLines(NewsSource.MAX_LINES) - .margin({ left: NewsSource.MARGIN_LEFT, top: NewsSource.MARGIN_TOP }) + .height(Const.NewsSource_HEIGHT) + .width(Const.NewsSource_WIDTH) + .maxLines(Const.NewsSource_MAX_LINES) + .margin({ left: Const.NewsSource_MARGIN_LEFT, top: Const.NewsSource_MARGIN_TOP }) .textOverflow({ overflow: TextOverflow.None }) } .alignItems(HorizontalAlign.Start) diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NewsList.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NewsList.ets index 1a2b20ce456321f057b0fb6dc804d6cbe6288c72..f188ba7f54b99ad1224e601a27b807a25e2ae0fb 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NewsList.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NewsList.ets @@ -13,58 +13,45 @@ * limitations under the License. */ +import promptAction from '@ohos.promptAction'; +import { CommonConstant, CommonConstant as Const, PageState } from '../common/constant/CommonConstant'; import NewsItem from './NewsItem'; import LoadMoreLayout from './LoadMoreLayout'; import RefreshLayout from './RefreshLayout'; import CustomRefreshLoadLayout from './CustomRefreshLoadLayout'; -import { getTabData } from '../common/utils/DataUtils'; -import { CustomRefreshLoadLayoutClass } from '../common/bean/NewsData'; import { listTouchEvent } from '../common/utils/PullDownRefresh'; -import { - CUSTOM_LAYOUT_HEIGHT, - NewsListConstant, - FULL_WIDTH, - FULL_HEIGHT, - PageState -} from '../common/constant/CommonConstant'; +import NewsViewModel, { CustomRefreshLoadLayoutClass, NewsData } from '../viewmodel/NewsViewModel'; +import NoMoreLayout from './NoMoreLayout'; +import NewsModel from '../viewmodel/NewsModel'; /** * The news list component. */ @Component export default struct NewsList { + @State newsModel: NewsModel = new NewsModel(); @Watch('changeCategory') @Link currentIndex: number; - @State newsData: Array = []; - @State currentPage: number = 1; - @State pageSize: number = 10; - @State pullDownRefreshText: Resource = $r('app.string.pull_down_refresh_text'); - @State pullDownRefreshImage: Resource = $r('app.media.ic_pull_down_refresh'); - @State pullDownRefreshHeight: number = CUSTOM_LAYOUT_HEIGHT; - @State isVisiblePullDown: boolean = false; - @State pullUpLoadText: Resource = $r('app.string.pull_up_load_text'); - @State pullUpLoadImage: Resource = $r('app.media.ic_pull_up_load'); - @State pullUpLoadHeight: number = CUSTOM_LAYOUT_HEIGHT; - @State isVisiblePullUpLoad: boolean = false; - private startIndex = 0; - private endIndex = 0; - @State offsetY: number = 0; - private downY = 0; - private lastMoveY = 0; - private isRefreshing: boolean = false; - private isCanRefresh = false; - private isPullRefreshOperation = false; - private isLoading: boolean = false; - private isCanLoadMore = false; - @State pageState: number = PageState.Loading; changeCategory() { - getTabData(this.currentPage - 1, this.pageSize, this.currentIndex, { - onSuccess: (value) => { - this.pageState = PageState.Success; - this.newsData = value.newsPageData; - }, - onFail: () => this.pageState = PageState.Fail - }) + this.newsModel.currentPage = 1; + NewsViewModel.getNewsList(this.newsModel.currentPage, this.newsModel.pageSize, Const.GET_NEWS_LIST) + .then((data: NewsData[]) => { + this.newsModel.pageState = PageState.Success; + if (data.length === this.newsModel.pageSize) { + this.newsModel.currentPage++; + this.newsModel.hasMore = true; + } else { + this.newsModel.hasMore = false; + } + this.newsModel.newsData = data; + }) + .catch((err: string | Resource) => { + promptAction.showToast({ + message: err, + duration: Const.ANIMATION_DURATION + }); + this.newsModel.pageState = PageState.Fail; + }); } aboutToAppear() { @@ -74,82 +61,88 @@ export default struct NewsList { build() { Column() { - if (this.pageState === PageState.Loading) { - this.LoadingLayout() - } else if (this.pageState === PageState.Success) { + if (this.newsModel.pageState === PageState.Success) { this.ListLayout() + } else if (this.newsModel.pageState === PageState.Loading) { + this.LoadingLayout() } else { this.FailLayout() } } - .width(FULL_WIDTH) - .height(FULL_HEIGHT) + .width(Const.FULL_WIDTH) + .height(Const.FULL_HEIGHT) .justifyContent(FlexAlign.Center) - .onTouch((event) => { - if (this.pageState === PageState.Success) { - listTouchEvent.call(this, event); + .onTouch((event: TouchEvent | undefined) => { + if (event) { + if (this.newsModel.pageState === PageState.Success) { + listTouchEvent(this.newsModel, event); + } } }) } @Builder LoadingLayout() { CustomRefreshLoadLayout({ customRefreshLoadClass: new CustomRefreshLoadLayoutClass(true, - $r('app.media.ic_pull_up_load'), $r('app.string.pull_up_load_text'), this.pullDownRefreshHeight) }) + $r('app.media.ic_pull_up_load'), $r('app.string.pull_up_load_text'), this.newsModel.pullDownRefreshHeight) }) } @Builder ListLayout() { List() { ListItem() { RefreshLayout({ - refreshLayoutClass: new CustomRefreshLoadLayoutClass(this.isVisiblePullDown, this.pullDownRefreshImage, - this.pullDownRefreshText, this.pullDownRefreshHeight) + refreshLayoutClass: new CustomRefreshLoadLayoutClass(this.newsModel.isVisiblePullDown, this.newsModel.pullDownRefreshImage, + this.newsModel.pullDownRefreshText, this.newsModel.pullDownRefreshHeight) }) } - ForEach(this.newsData, item => { + ForEach(this.newsModel.newsData, (item: NewsData) => { ListItem() { NewsItem({ newsData: item }) } - .height(NewsListConstant.ITEM_HEIGHT) + .height($r('app.float.news_list_height')) .backgroundColor($r('app.color.white')) - .margin({ top: NewsListConstant.ITEM_MARGIN_TOP}) - .borderRadius(NewsListConstant.ITEM_BORDER_RADIUS) - }, (item, index) => JSON.stringify(item) + index.toString()) + .margin({ top: $r('app.float.news_list_margin_top') }) + .borderRadius(Const.NewsListConstant_ITEM_BORDER_RADIUS) + }, (item: NewsData, index?: number) => JSON.stringify(item) + index) + ListItem() { - LoadMoreLayout({ - loadMoreLayoutClass: new CustomRefreshLoadLayoutClass(this.isVisiblePullUpLoad, this.pullUpLoadImage, - this.pullUpLoadText, this.pullUpLoadHeight) - }) + if (this.newsModel.hasMore) { + LoadMoreLayout({ + loadMoreLayoutClass: new CustomRefreshLoadLayoutClass(this.newsModel.isVisiblePullUpLoad, this.newsModel.pullUpLoadImage, + this.newsModel.pullUpLoadText, this.newsModel.pullUpLoadHeight) + }) + } else { + NoMoreLayout() + } } } - .width(NewsListConstant.LIST_WIDTH) - .height(FULL_HEIGHT) - .margin({ left: NewsListConstant.LIST_MARGIN_LEFT, right: NewsListConstant.LIST_MARGIN_RIGHT }) + .width(Const.NewsListConstant_LIST_WIDTH) + .height(Const.FULL_HEIGHT) + .margin({ left: Const.NewsListConstant_LIST_MARGIN_LEFT, right: Const.NewsListConstant_LIST_MARGIN_RIGHT }) .backgroundColor($r('app.color.listColor')) .divider({ color: $r('app.color.dividerColor'), - strokeWidth: NewsListConstant.LIST_DIVIDER_STROKE_WIDTH, - endMargin: NewsListConstant.LIST_MARGIN_RIGHT + strokeWidth: Const.NewsListConstant_LIST_DIVIDER_STROKE_WIDTH, + endMargin: Const.NewsListConstant_LIST_MARGIN_RIGHT }) // Remove the rebound effect. .edgeEffect(EdgeEffect.None) - .offset({ x: 0, y: `${this.offsetY}px` }) - .onScrollIndex((start, end) => { + .offset({ x: 0, y: `${this.newsModel.offsetY}${CommonConstant.LIST_OFFSET_UNIT}` }) + .onScrollIndex((start: number, end: number) => { // Listen to the first index of the current list. - this.startIndex = start; - this.endIndex = end; + this.newsModel.startIndex = start; + this.newsModel.endIndex = end; }) } @Builder FailLayout() { Image($r('app.media.none')) - .height(NewsListConstant.NONE_IMAGE_SIZE) - .width(NewsListConstant.NONE_IMAGE_SIZE) + .height(Const.NewsListConstant_NONE_IMAGE_SIZE) + .width(Const.NewsListConstant_NONE_IMAGE_SIZE) Text($r('app.string.page_none_msg')) - .opacity(NewsListConstant.NONE_TEXT_opacity) - .fontSize(NewsListConstant.NONE_TEXT_size) + .opacity(Const.NewsListConstant_NONE_TEXT_opacity) + .fontSize(Const.NewsListConstant_NONE_TEXT_size) .fontColor($r('app.color.fontColor_text3')) - .margin({ top: NewsListConstant.NONE_TEXT_margin }) + .margin({ top: Const.NewsListConstant_NONE_TEXT_margin }) } -} - +} \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NoMoreLayout.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NoMoreLayout.ets new file mode 100644 index 0000000000000000000000000000000000000000..5d566babce08ccf95fcc1d50054b14e51c82ed12 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/NoMoreLayout.ets @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License,Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonConstant as Const } from '../common/constant/CommonConstant' + +/** + * The No more data layout component. + */ +@Component +export default struct NoMoreLayout { + build() { + Row() { + Text($r('app.string.prompt_message')) + .margin({ left: Const.NoMoreLayoutConstant_NORMAL_PADDING }) + .fontSize(Const.NoMoreLayoutConstant_TITLE_FONT) + .textAlign(TextAlign.Center) + } + .width(Const.FULL_WIDTH) + .justifyContent(FlexAlign.Center) + .height(Const.CUSTOM_LAYOUT_HEIGHT) + } +} \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/RefreshLayout.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/RefreshLayout.ets index 105a3b860b1a136bb2156df08c66bcf0f8537e12..9f0a78d8dfb3492c32c649db8f6d6115bd27e3d7 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/RefreshLayout.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/RefreshLayout.ets @@ -13,8 +13,8 @@ * limitations under the License. */ +import { CustomRefreshLoadLayoutClass } from '../viewmodel/NewsViewModel'; import CustomRefreshLoadLayout from './CustomRefreshLoadLayout'; -import { CustomRefreshLoadLayoutClass } from '../common/bean/NewsData'; /** * The refresh layout component. diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/TabBar.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/TabBar.ets index c38aa18a640290964c9bafcd46cf6640cd789d2b..000a090077903648dffa7e25856fd27508fb16e9 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/TabBar.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/view/TabBar.ets @@ -14,51 +14,52 @@ */ import NewsList from '../view/newslist'; -import { TabBars, FULL_HEIGHT } from '../common/constant/CommonConstant'; -import { loadNewsTypes } from '../common/utils/DataUtils'; +import { CommonConstant as Const } from '../common/constant/CommonConstant'; +import NewsViewModel, { NewsTypeBean } from '../viewmodel/NewsViewModel'; /** * The tabBar component. */ @Component export default struct TabBar { - @State tabBarArray: Array = TabBars.DEFAULT_NEWS_TYPES; + @State tabBarArray: NewsTypeBean[] = NewsViewModel.getDefaultTypeList(); @State currentIndex: number = 0; @State currentPage: number = 1; @Builder TabBuilder(index: number) { Column() { Text(this.tabBarArray[index].name) - .height(FULL_HEIGHT) - .padding({ left: TabBars.HORIZONTAL_PADDING, right: TabBars.HORIZONTAL_PADDING }) - .fontSize(this.currentIndex === index ? TabBars.SELECT_TEXT_FONT_SIZE : TabBars.UN_SELECT_TEXT_FONT_SIZE) - .fontWeight(this.currentIndex === index ? TabBars.SELECT_TEXT_FONT_WEIGHT : TabBars.UN_SELECT_TEXT_FONT_WEIGHT) + .height(Const.FULL_HEIGHT) + .padding({ left: Const.TabBars_HORIZONTAL_PADDING, right: Const.TabBars_HORIZONTAL_PADDING }) + .fontSize(this.currentIndex === index ? Const.TabBars_SELECT_TEXT_FONT_SIZE : Const.TabBars_UN_SELECT_TEXT_FONT_SIZE) + .fontWeight(this.currentIndex === index ? Const.TabBars_SELECT_TEXT_FONT_WEIGHT : Const.TabBars_UN_SELECT_TEXT_FONT_WEIGHT) .fontColor($r('app.color.fontColor_text3')) } } aboutToAppear() { - // 请求新闻类别 - loadNewsTypes({ - onSuccess: (value) => this.tabBarArray = value, - onFail: () => this.tabBarArray = TabBars.DEFAULT_NEWS_TYPES + // Request news category. + NewsViewModel.getNewsTypeList().then((typeList: NewsTypeBean[]) => { + this.tabBarArray = typeList; + }).catch((typeList: NewsTypeBean[]) => { + this.tabBarArray = typeList; }); } build() { Tabs() { - ForEach(this.tabBarArray, tabsItem => { + ForEach(this.tabBarArray, (tabsItem: NewsTypeBean) => { TabContent() { Column() { NewsList({ currentIndex: $currentIndex }) } } .tabBar(this.TabBuilder(tabsItem.id)) - }, item => JSON.stringify(item)); + }, (item: NewsTypeBean) => JSON.stringify(item)); } - .barHeight(TabBars.BAR_HEIGHT) + .barHeight(Const.TabBars_BAR_HEIGHT) .barMode(BarMode.Scrollable) - .barWidth(TabBars.BAR_WIDTH) + .barWidth(Const.TabBars_BAR_WIDTH) .onChange((index: number) => { this.currentIndex = index; this.currentPage = 1; diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/viewmodel/NewsModel.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/viewmodel/NewsModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..b14bc6c702d6c37ff065324576fb66e92918e29d --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/viewmodel/NewsModel.ets @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonConstant as Const, PageState } from '../common/constant/CommonConstant'; +import { NewsData } from './NewsViewModel'; + +export default class NewsModel { + newsData: Array = []; + currentPage: number = 1; + pageSize: number = Const.PAGE_SIZE; + pullDownRefreshText: Resource = $r('app.string.pull_down_refresh_text'); + pullDownRefreshImage: Resource = $r('app.media.ic_pull_down_refresh'); + pullDownRefreshHeight: number = Const.CUSTOM_LAYOUT_HEIGHT; + isVisiblePullDown: boolean = false; + pullUpLoadText: Resource = $r('app.string.pull_up_load_text'); + pullUpLoadImage: Resource = $r('app.media.ic_pull_up_load'); + pullUpLoadHeight: number = Const.CUSTOM_LAYOUT_HEIGHT; + isVisiblePullUpLoad: boolean = false; + offsetY: number = 0; + pageState: number = PageState.Loading; + hasMore: boolean = true; + startIndex = 0; + endIndex = 0; + downY = 0; + lastMoveY = 0; + isRefreshing: boolean = false; + isCanRefresh = false; + isPullRefreshOperation = false; + isLoading: boolean = false; + isCanLoadMore: boolean = false; +} \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/bean/NewsData.ets b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/viewmodel/NewsViewModel.ets similarity index 39% rename from NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/bean/NewsData.ets rename to NetworkManagement/NewsDataArkTS/entry/src/main/ets/viewmodel/NewsViewModel.ets index 2b67d8746e7466bfa27de94a1f7d2d0d85a2ec3d..a24dfd758a338c05df3344e4c51375ad33a26e46 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/ets/common/bean/NewsData.ets +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/ets/viewmodel/NewsViewModel.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,6 +13,68 @@ * limitations under the License. */ +import { CommonConstant as Const } from '../common/constant/CommonConstant'; +import { httpRequestGet } from '../common/utils/HttpUtil'; +import Logger from '../common/utils/Logger'; + +class NewsViewModel { + /** + * Get news type list from server. + * + * @return NewsTypeBean[] newsTypeList + */ + getNewsTypeList(): Promise { + return new Promise((resolve: Function) => { + let url = `${Const.SERVER}/${Const.GET_NEWS_TYPE}`; + httpRequestGet(url).then((data: ResponseResult) => { + if (data.code === Const.SERVER_CODE_SUCCESS) { + resolve(data.data); + } else { + resolve(Const.TabBars_DEFAULT_NEWS_TYPES); + } + }).catch(() => { + resolve(Const.TabBars_DEFAULT_NEWS_TYPES); + }); + }); + } + + /** + * Get default news type list. + * + * @return NewsTypeBean[] newsTypeList + */ + getDefaultTypeList(): NewsTypeBean[] { + return Const.TabBars_DEFAULT_NEWS_TYPES; + } + + /** + * Get news type list from server. + * + * @return NewsData[] newsDataList + */ + getNewsList(currentPage: number, pageSize: number, path: string): Promise { + return new Promise(async (resolve: Function, reject: Function) => { + let url = `${Const.SERVER}/${path}`; + url += '?currentPage=' + currentPage + '&pageSize=' + pageSize; + httpRequestGet(url).then((data: ResponseResult) => { + if (data.code === Const.SERVER_CODE_SUCCESS) { + resolve(data.data); + } else { + Logger.error('getNewsList failed', JSON.stringify(data)); + reject($r('app.string.page_none_msg')); + } + }).catch((err: Error) => { + Logger.error('getNewsList failed', JSON.stringify(err)); + reject($r('app.string.http_error_message')); + }); + }); + } +} + +let newsViewModel = new NewsViewModel(); + +export default newsViewModel as NewsViewModel; + /** * News list item info. */ @@ -20,29 +82,22 @@ export class NewsData { /** * News list item title. */ - title: string; + title: string = ''; /** * News list item content. */ - content: string; + content: string = ''; /** * News list item imagesUrl. */ - imagesUrl: Array; + imagesUrl: Array = [new NewsFile()]; /** * News list item source. */ - source: string; - - constructor(title: string, content: string, imagesUrl: Array, source: string) { - this.title = title; - this.content = content; - this.imagesUrl = imagesUrl; - this.source = source; - } + source: string = ''; } /** @@ -52,29 +107,22 @@ export class NewsFile { /** * News image list item id. */ - id: number; + id: number = 0; /** * News image list item url. */ - url: string; + url: string = ''; /** * News image list item type. */ - type: number; + type: number = 0; /** * News image list item newsId. */ - newsId: number; - - constructor(id: number, url: string, type: number, newsId: number) { - this.id = id; - this.type = type; - this.url = url; - this.newsId = newsId; - } + newsId: number = 0; } /** @@ -109,3 +157,31 @@ export class CustomRefreshLoadLayoutClass { this.heightValue = heightValue; } } + +export class NewsTypeBean { + id: number = 0; + name: ResourceStr = ''; +} + +export class ResponseResult { + /** + * Code returned by the network request: success, fail. + */ + code: string; + + /** + * Message returned by the network request. + */ + msg: string | Resource; + + /** + * Data returned by the network request. + */ + data: string | Object | ArrayBuffer; + + constructor() { + this.code = ''; + this.msg = ''; + this.data = ''; + } +} \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/module.json5 b/NetworkManagement/NewsDataArkTS/entry/src/main/module.json5 index 751e33513e837bc401f2aa72ba82b01fba5f035e..4b7f1aef5dc05397611e9500d5196c6968a9f737 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/module.json5 +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/module.json5 @@ -5,16 +5,11 @@ "description": "$string:module_desc", "mainElement": "EntryAbility", "deviceTypes": [ - "default", - "tablet" - ], + "default" + ], "deliveryWithInstall": true, "installationFree": false, "pages": "$profile:main_pages", - "metadata": [{ - "name": "ArkTSPartialUpdate", - "value": "true" - }], "abilities": [ { "name": "EntryAbility", @@ -40,10 +35,10 @@ "requestPermissions": [ { "name": "ohos.permission.INTERNET", - "reason": "$string:reason", + "reason": "$string:dependency_reason", "usedScene": { "abilities": [ - "EntryAbility" + "EntryAbility" ], "when": "inuse" } diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/element/float.json b/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..cc1ff93ce1cad51e7091fc893b04db6a01a75ff5 --- /dev/null +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/element/float.json @@ -0,0 +1,24 @@ +{ + "float": [ + { + "name": "news_list_height", + "value": "256vp" + }, + { + "name": "news_list_margin_top", + "value": "12vp" + }, + { + "name": "news_title_image_height", + "value": "20vp" + }, + { + "name": "news_title_row_height", + "value": "22vp" + }, + { + "name": "news_title_row_margin_top", + "value": "16vp" + } + ] +} \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/element/string.json b/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/element/string.json index 688a16030e7f6e6488aced5c9d4300174f2e746f..fdd6d25ffbb72114c8e4b1cf0c10c377720a5da3 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/element/string.json +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/resources/base/element/string.json @@ -49,8 +49,8 @@ "value": "No more data" }, { - "name": "reason", - "value": "internet" + "name": "dependency_reason", + "value": "Used to initiate network data requests." } ] } \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/en_US/element/string.json b/NetworkManagement/NewsDataArkTS/entry/src/main/resources/en_US/element/string.json index 688a16030e7f6e6488aced5c9d4300174f2e746f..fdd6d25ffbb72114c8e4b1cf0c10c377720a5da3 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/en_US/element/string.json +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/resources/en_US/element/string.json @@ -49,8 +49,8 @@ "value": "No more data" }, { - "name": "reason", - "value": "internet" + "name": "dependency_reason", + "value": "Used to initiate network data requests." } ] } \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/zh_CN/element/string.json b/NetworkManagement/NewsDataArkTS/entry/src/main/resources/zh_CN/element/string.json index 3a32cbf077e8d90c24b3d19f0db2bb49d3dc05d4..235305588bab23312e781e56b3d5b05b617ec5fd 100644 --- a/NetworkManagement/NewsDataArkTS/entry/src/main/resources/zh_CN/element/string.json +++ b/NetworkManagement/NewsDataArkTS/entry/src/main/resources/zh_CN/element/string.json @@ -49,8 +49,8 @@ "value": "没有更多数据了" }, { - "name": "reason", - "value": "网络" + "name": "dependency_reason", + "value": "用于发起网络数据请求" } ] } \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/figures/mainPage.png b/NetworkManagement/NewsDataArkTS/figures/mainPage.png deleted file mode 100644 index 641daa88cf7edc9deba2b5319ec607102eec28c7..0000000000000000000000000000000000000000 Binary files a/NetworkManagement/NewsDataArkTS/figures/mainPage.png and /dev/null differ diff --git a/NetworkManagement/NewsDataArkTS/figures/pullDownRefresh.png b/NetworkManagement/NewsDataArkTS/figures/pullDownRefresh.png deleted file mode 100644 index f25c849ea640eb18b4b76aae4354b70983fa1b09..0000000000000000000000000000000000000000 Binary files a/NetworkManagement/NewsDataArkTS/figures/pullDownRefresh.png and /dev/null differ diff --git a/NetworkManagement/NewsDataArkTS/figures/summarize.gif b/NetworkManagement/NewsDataArkTS/figures/summarize.gif deleted file mode 100644 index 0d4a2fc153a9ae074efdb8d8f7579ad73501a98c..0000000000000000000000000000000000000000 Binary files a/NetworkManagement/NewsDataArkTS/figures/summarize.gif and /dev/null differ diff --git a/NetworkManagement/NewsDataArkTS/hvigor/hvigor-config.json5 b/NetworkManagement/NewsDataArkTS/hvigor/hvigor-config.json5 index 5d9bed6108611f15d956e823594d7824ce7cfd74..ec2a3ae0df3882488dc4c82e947a40f7eae1da15 100644 --- a/NetworkManagement/NewsDataArkTS/hvigor/hvigor-config.json5 +++ b/NetworkManagement/NewsDataArkTS/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } \ No newline at end of file diff --git a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-caution.gif b/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-caution.gif deleted file mode 100644 index 81fb2aba954177efa588e675927082b1f6bed41f..0000000000000000000000000000000000000000 Binary files a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-caution.gif and /dev/null differ diff --git a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-danger.gif b/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-danger.gif deleted file mode 100644 index 81fb2aba954177efa588e675927082b1f6bed41f..0000000000000000000000000000000000000000 Binary files a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-danger.gif and /dev/null differ diff --git a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-note.gif b/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-note.gif deleted file mode 100644 index db3995e34b6644fc11c916ffe69c7cb5512610d8..0000000000000000000000000000000000000000 Binary files a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-note.gif and /dev/null differ diff --git a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-notice.gif b/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-notice.gif deleted file mode 100644 index 75397a3efc5c345922fd37f551d7d28675ab6c5f..0000000000000000000000000000000000000000 Binary files a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-notice.gif and /dev/null differ diff --git a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-tip.gif b/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-tip.gif deleted file mode 100644 index 110cd67cefa9f6b2800a2b8076a7a0dcc00b783c..0000000000000000000000000000000000000000 Binary files a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-tip.gif and /dev/null differ diff --git a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-warning.gif b/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-warning.gif deleted file mode 100644 index 81fb2aba954177efa588e675927082b1f6bed41f..0000000000000000000000000000000000000000 Binary files a/NetworkManagement/NewsDataArkTS/public_sys-resources/icon-warning.gif and /dev/null differ diff --git a/NetworkManagement/NewsDataArkTS/figures/systemVersion.png b/NetworkManagement/NewsDataArkTS/screenshots/device/environment.png similarity index 100% rename from NetworkManagement/NewsDataArkTS/figures/systemVersion.png rename to NetworkManagement/NewsDataArkTS/screenshots/device/environment.png diff --git a/NetworkManagement/NewsDataArkTS/screenshots/device/homePage.png b/NetworkManagement/NewsDataArkTS/screenshots/device/homePage.png new file mode 100644 index 0000000000000000000000000000000000000000..c334ef9c49b5f96dc11774199b489a003c2297e3 Binary files /dev/null and b/NetworkManagement/NewsDataArkTS/screenshots/device/homePage.png differ diff --git a/NetworkManagement/NewsDataArkTS/screenshots/device/homePage2.png b/NetworkManagement/NewsDataArkTS/screenshots/device/homePage2.png new file mode 100644 index 0000000000000000000000000000000000000000..9db6a4f716ec7699b23bb155edbb1002a1e77d9d Binary files /dev/null and b/NetworkManagement/NewsDataArkTS/screenshots/device/homePage2.png differ diff --git a/NetworkManagement/NewsDataArkTS/screenshots/device/news.gif b/NetworkManagement/NewsDataArkTS/screenshots/device/news.gif new file mode 100644 index 0000000000000000000000000000000000000000..fe5940de50de6ddb8e7690ec4d30d5da73d59c27 Binary files /dev/null and b/NetworkManagement/NewsDataArkTS/screenshots/device/news.gif differ diff --git a/NetworkManagement/NewsDataArkTS/screenshots/device/node.PNG b/NetworkManagement/NewsDataArkTS/screenshots/device/node.PNG new file mode 100644 index 0000000000000000000000000000000000000000..a5ef047bd3747dbd8119676e970980e4791829de Binary files /dev/null and b/NetworkManagement/NewsDataArkTS/screenshots/device/node.PNG differ diff --git a/NetworkManagement/NewsDataArkTS/screenshots/device/npm_360.PNG b/NetworkManagement/NewsDataArkTS/screenshots/device/npm_360.PNG new file mode 100644 index 0000000000000000000000000000000000000000..1fcc39a6bf0214ec755df49b44977537d2761d91 Binary files /dev/null and b/NetworkManagement/NewsDataArkTS/screenshots/device/npm_360.PNG differ diff --git a/NetworkManagement/NewsDataArkTS/screenshots/device/summary.gif b/NetworkManagement/NewsDataArkTS/screenshots/device/summary.gif new file mode 100644 index 0000000000000000000000000000000000000000..952910d7f1381d054d28f70a5ecfe75e725250d5 Binary files /dev/null and b/NetworkManagement/NewsDataArkTS/screenshots/device/summary.gif differ diff --git a/Security/AccessPermission/README.md b/Security/AccessPermission/README.md index 0c551a067943eb5fd948e6f1728ddd7c6a4a2f19..ae86a5895588a8a858281a01552bf3ffb5b9fcc5 100644 --- a/Security/AccessPermission/README.md +++ b/Security/AccessPermission/README.md @@ -6,16 +6,16 @@ ![](figures/1.gif) ->![](public_sys-resources/icon-note.gif) **说明:** +>![](public_sys-resources/icon-note.gif) **说明:** >查询周边不可信设备之前,请确保本设备与周边设备未进行配对。如果已配对,则恢复出厂设置之后重新查询。 ### 相关概念 -- [访问控制权限申请](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-guidelines.md#访问控制授权申请):应用的APL(Ability Privilege Level)等级分为normal、system_basic和system_core三个等级,默认情况下,应用的APL等级都为normal等级。权限类型分为system_grant和user_grant两种类型。应用可申请的权限项参见应用权限列表。 -- [权限类型说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-overview.md#权限类型说明):根据授权方式的不同,权限类型可分为system_grant(系统授权)和user_grant(用户授权)。 -- [应用ALP等级说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-overview.md#%E5%BA%94%E7%94%A8apl%E7%AD%89%E7%BA%A7%E8%AF%B4%E6%98%8E):元能力权限等级APL(Ability Privilege Level)指的是应用的权限申请优先级的定义,不同APL等级的应用能够申请的权限等级不同。 -- [应用权限列表](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md):在申请目标权限前,建议开发者先阅读访问控制开发概述-权限的工作流程。对权限的工作流程有基本的了解后,再结合以下权限的具体说明,判断应用能否申请目标权限,提高开发效率。 -- [设备管理实例](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-device-manager.md#devicemanager):用于获取可信设备和本地设备的相关信息。在调用DeviceManager的方法前,需要先通过createDeviceManager构建一个DeviceManager实例dmInstance。 +- [访问控制权限申请](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-guidelines.md#访问控制授权申请):应用的APL(Ability Privilege Level)等级分为normal、system_basic和system_core三个等级,默认情况下,应用的APL等级都为normal等级。权限类型分为system_grant和user_grant两种类型。应用可申请的权限项参见应用权限列表。 +- [权限类型说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-overview.md#权限类型说明):根据授权方式的不同,权限类型可分为system_grant(系统授权)和user_grant(用户授权)。 +- [应用ALP等级说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-overview.md#%E5%BA%94%E7%94%A8apl%E7%AD%89%E7%BA%A7%E8%AF%B4%E6%98%8E):元能力权限等级APL(Ability Privilege Level)指的是应用的权限申请优先级的定义,不同APL等级的应用能够申请的权限等级不同。 +- [应用权限列表](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md):在申请目标权限前,建议开发者先阅读访问控制开发概述-权限的工作流程。对权限的工作流程有基本的了解后,再结合以下权限的具体说明,判断应用能否申请目标权限,提高开发效率。 +- [设备管理实例](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-device-manager.md#devicemanager):用于获取可信设备和本地设备的相关信息。在调用DeviceManager的方法前,需要先通过createDeviceManager构建一个DeviceManager实例dmInstance。 ### 约束与限制 @@ -29,13 +29,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 -- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -47,24 +47,22 @@ 2. 搭建烧录环境。 - 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) - 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) 3. 搭建开发环境。 - 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 - 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 - 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 ## 代码结构解读 本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 ``` -├──entry/src/main/ets // 代码区 +├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ └──DeviceBean.ets // 设备信息类 │ │ ├──constants │ │ │ └──CommonConstants.ets // 公共常量类 │ │ └──util @@ -72,10 +70,11 @@ │ │ ├──Logger.ets // 日志管理工具类 │ │ └──PermissionUtil.ets // 权限申请工具类 │ ├──entryability -│ │ └──EntryAbility.ts // 程序入口类 +│ │ └──EntryAbility.ts // 程序入口类 │ ├──pages │ │ └──HomePage.ets // 主页面 -│ └──view +│ └──view +│ ├──DeviceBean.ets // 设备信息类 │ ├──DeviceItem.ets // 设备信息对象 │ ├──DeviceListDialog.ets // 设备列表展示弹框 │ └──NoPermissionDialog.ets // 无权限弹框 @@ -134,7 +133,7 @@ struct HomePage { ![](figures/2.gif) ```typescript -// DeviceListDialog.ets +// NoPermissionDialog.ets @CustomDialog export struct NoPermissionDialog { controller: CustomDialogController; @@ -143,7 +142,6 @@ export struct NoPermissionDialog { Column() { Text($r('app.string.no_permission_title')) ... - .margin({ top: CommonConstants.PERMISSION_TEXT_TOP }) Text($r('app.string.clear_permission')) ... Text($r('app.string.dialog_confirm')) @@ -163,8 +161,9 @@ export struct NoPermissionDialog { ```typescript // DeviceListDialog.ets +@CustomDialog export struct DeviceListDialog { - @State deviceListUtil: DeviceListUtil = new DeviceListUtil(); + private deviceListUtil: DeviceListUtil = new DeviceListUtil(); @State deviceList: Array = []; controller: CustomDialogController; ... @@ -183,7 +182,7 @@ export struct DeviceListDialog { ListItem() { DeviceItem({item: item, index: index}); } - }, item => JSON.stringify(item)) + }, (item: DeviceBean) => JSON.stringify(item)) } } ... @@ -200,6 +199,7 @@ export struct DeviceListDialog { ... } } + ``` ## 权限申请 @@ -266,7 +266,7 @@ struct HomePage { async checkPermission() { let atManager = abilityAccessCtrl.createAtManager(); let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED; - let tokenId: number; + let tokenId: number = 0; try { let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); @@ -293,7 +293,7 @@ async checkPermission() { export struct DeviceListDialog { ... aboutToAppear() { - this.deviceListUtil.initDmInstance((data) => { + this.deviceListUtil.initDmInstance((data: DeviceInfoInterface) => { ... }); } @@ -315,7 +315,7 @@ initDmInstance(dealDeviceInfo: Function) { this.startDeviceDiscovery(); }); } catch (err) { - Logger.error(TAG, 'createDeviceManager errCode:' + err.code + ',errMessage:' + err.message); + Logger.error(TAG, 'createDeviceManager err=' + JSON.stringify(err)); } } @@ -323,11 +323,15 @@ initDmInstance(dealDeviceInfo: Function) { // 注册发现设备回调方法 deviceFoundOn() { try { - this.dmInstance.on(CommonConstants.DEVICE_FOUND, (data) => { - this.dealDeviceInfo(data); - }); + if (this.dmInstance !== undefined) { + this.dmInstance.on('deviceFound', (data) => { + if (this.dealDeviceInfo !== undefined) { + this.dealDeviceInfo(data); + } + }); + } } catch (err) { - Logger.error(TAG, 'deviceFoundOn errCode:' + err.code + ',errMessage:' + err.message); + Logger.error(TAG, 'deviceFoundOn err:' + JSON.stringify(err)); } } @@ -335,19 +339,21 @@ deviceFoundOn() { // 发现周边设备方法 startDeviceDiscovery() { this.subscribeId = Math.floor(Math.random() * CommonConstants.RANDOM_ONE + CommonConstants.RANDOM_TWO); - let subscribeInfo = { - 'subscribeId': this.subscribeId, - 'mode': CommonConstants.MODE, - 'medium': 0, - 'freq': CommonConstants.FREQ, - 'isSameAccount': false, - 'isWakeRemote': true, - 'capability': 1 + let subscribeInfo: SubscribeInfoInterface = { + subscribeId: this.subscribeId, + mode: CommonConstants.MODE, + medium: 0, + freq: CommonConstants.FREQ, + isSameAccount: false, + isWakeRemote: true, + capability: 1 }; try { - this.dmInstance.startDeviceDiscovery(subscribeInfo); + if (this.dmInstance !== undefined) { + this.dmInstance.startDeviceDiscovery(subscribeInfo); + } } catch (err) { - Logger.error(TAG, 'startDeviceDiscovery errCode:' + err.code + ',errMessage:' + err.message); + Logger.error(TAG, 'startDeviceDiscovery err:' + JSON.stringify(err)); } } ``` @@ -360,5 +366,4 @@ startDeviceDiscovery() { 2. 权限类型说明。 3. 如何获取周边设备。 - ![](figures/彩带动效.gif) diff --git a/Security/AccessPermission/build-profile.json5 b/Security/AccessPermission/build-profile.json5 index d7b1117cdb34aab2983ac65026d9e8dcc91332d1..c4a795e6c5ccc02a576f8606870d08233068a222 100644 --- a/Security/AccessPermission/build-profile.json5 +++ b/Security/AccessPermission/build-profile.json5 @@ -1,6 +1,19 @@ { "app": { - "signingConfigs": [], + "signingConfigs": [ + { + "name": "default", + "material": { + "certpath": "C:\\Users\\l30044346\\.ohos\\config\\openharmony\\auto_ohos_default_AccessPermission_com.example.accesspermission.cer", + "storePassword": "0000001A0A543B3A6295297D75D9EA8C7941AA529DB818E408B45917302F440EE319F95F61ED7F5D38D6", + "keyAlias": "debugKey", + "keyPassword": "0000001A773E0C52BAC726F6A37928CEB541B1ECD0FBCBAD59D91F8D0BD31C4897B1D3542D134A1D3192", + "profile": "C:\\Users\\l30044346\\.ohos\\config\\openharmony\\auto_ohos_default_AccessPermission_com.example.accesspermission.p7b", + "signAlg": "SHA256withECDSA", + "storeFile": "C:\\Users\\l30044346\\.ohos\\config\\openharmony\\auto_ohos_default_AccessPermission_com.example.accesspermission.p12" + } + } + ], "compileSdkVersion": 9, "compatibleSdkVersion": 9, "products": [ diff --git a/Security/AccessPermission/entry/src/main/ets/common/constants/CommonConstants.ets b/Security/AccessPermission/entry/src/main/ets/common/constants/CommonConstants.ets index 947601aeb06157fd6b74f2196f7cf77896edda03..cec4517694248f2757c2a6086e719055e863a9fe 100644 --- a/Security/AccessPermission/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/Security/AccessPermission/entry/src/main/ets/common/constants/CommonConstants.ets @@ -13,8 +13,14 @@ * limitations under the License. */ +import deviceManager from '@ohos.distributedHardware.deviceManager'; import { Permissions } from '@ohos.abilityAccessCtrl'; +export interface DeviceInfoInterface { + subscribeId: number, + device: deviceManager.DeviceInfo +} + /** * Common constants for all features. */ @@ -135,3 +141,13 @@ export class CommonConstants { */ static readonly LIST_MAX_HEIGHT: string = '50%'; } + +export interface SubscribeInfoInterface { + subscribeId: number, + mode: number, + medium: number, + freq: number, + isSameAccount: boolean, + isWakeRemote: boolean, + capability: number +} diff --git a/Security/AccessPermission/entry/src/main/ets/common/util/DeviceListUtil.ets b/Security/AccessPermission/entry/src/main/ets/common/util/DeviceListUtil.ets index 8c3eba3906789399fc19592eb0a8b35d96874b8c..fe3a509a233860a38fbe0dc3ce082063ad18cbe6 100644 --- a/Security/AccessPermission/entry/src/main/ets/common/util/DeviceListUtil.ets +++ b/Security/AccessPermission/entry/src/main/ets/common/util/DeviceListUtil.ets @@ -14,7 +14,7 @@ */ import deviceManager from '@ohos.distributedHardware.deviceManager'; -import { CommonConstants } from '../constants/CommonConstants'; +import { CommonConstants, SubscribeInfoInterface } from '../constants/CommonConstants'; import Logger from './Logger'; /** @@ -23,9 +23,9 @@ import Logger from './Logger'; const TAG = '[DeviceListUtil]'; export class DeviceListUtil { - private dmInstance; + private dmInstance?: deviceManager.DeviceManager; private subscribeId: number = 0; - private dealDeviceInfo: Function; + private dealDeviceInfo?: Function; /** * Initializing Device Management Objects. @@ -43,7 +43,7 @@ export class DeviceListUtil { this.startDeviceDiscovery(); }); } catch (err) { - Logger.error(TAG, 'createDeviceManager errCode:' + err.code + ',errMessage:' + err.message); + Logger.error(TAG, 'createDeviceManager err=' + JSON.stringify(err)); } } @@ -52,19 +52,21 @@ export class DeviceListUtil { */ startDeviceDiscovery() { this.subscribeId = Math.floor(Math.random() * CommonConstants.RANDOM_ONE + CommonConstants.RANDOM_TWO); - let subscribeInfo = { - 'subscribeId': this.subscribeId, - 'mode': CommonConstants.MODE, - 'medium': 0, - 'freq': CommonConstants.FREQ, - 'isSameAccount': false, - 'isWakeRemote': true, - 'capability': 1 + let subscribeInfo: SubscribeInfoInterface = { + subscribeId: this.subscribeId, + mode: CommonConstants.MODE, + medium: 0, + freq: CommonConstants.FREQ, + isSameAccount: false, + isWakeRemote: true, + capability: 1 }; try { - this.dmInstance.startDeviceDiscovery(subscribeInfo); + if (this.dmInstance !== undefined) { + this.dmInstance.startDeviceDiscovery(subscribeInfo); + } } catch (err) { - Logger.error(TAG, 'startDeviceDiscovery errCode:' + err.code + ',errMessage:' + err.message); + Logger.error(TAG, 'startDeviceDiscovery err:' + JSON.stringify(err)); } } @@ -73,11 +75,15 @@ export class DeviceListUtil { */ deviceFoundOn() { try { - this.dmInstance.on(CommonConstants.DEVICE_FOUND, (data) => { - this.dealDeviceInfo(data); - }); + if (this.dmInstance !== undefined) { + this.dmInstance.on('deviceFound', (data) => { + if (this.dealDeviceInfo !== undefined) { + this.dealDeviceInfo(data); + } + }); + } } catch (err) { - Logger.error(TAG, 'deviceFoundOn errCode:' + err.code + ',errMessage:' + err.message); + Logger.error(TAG, 'deviceFoundOn err:' + JSON.stringify(err)); } } @@ -86,9 +92,11 @@ export class DeviceListUtil { */ stopDeviceDiscovery() { try { - this.dmInstance.stopDeviceDiscovery(this.subscribeId); + if (this.dmInstance !== undefined) { + this.dmInstance.stopDeviceDiscovery(this.subscribeId); + } } catch (err) { - Logger.error(TAG, 'stopDeviceDiscovery errCode:' + err.code + ',errMessage:' + err.message); + Logger.error(TAG, 'stopDeviceDiscovery err:' + JSON.stringify(err)); } } diff --git a/Security/AccessPermission/entry/src/main/ets/common/util/Logger.ets b/Security/AccessPermission/entry/src/main/ets/common/util/Logger.ets index a221c38ae9e6c0895d9effb2972e6a46eab62bf4..417578defa6812e1da2fb475bf2a66cfcc1f9b17 100644 --- a/Security/AccessPermission/entry/src/main/ets/common/util/Logger.ets +++ b/Security/AccessPermission/entry/src/main/ets/common/util/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Security/AccessPermission/entry/src/main/ets/common/util/PermissionUtil.ets b/Security/AccessPermission/entry/src/main/ets/common/util/PermissionUtil.ets index 0ff608de15ad422bdd31f8579662c185f134fe14..0e5953a538f35932e441ee2d440a0438b6745906 100644 --- a/Security/AccessPermission/entry/src/main/ets/common/util/PermissionUtil.ets +++ b/Security/AccessPermission/entry/src/main/ets/common/util/PermissionUtil.ets @@ -48,7 +48,7 @@ export class PermissionUtil { async checkPermission() { let atManager = abilityAccessCtrl.createAtManager(); let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED; - let tokenId: number; + let tokenId: number = 0; try { let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); diff --git a/Security/AccessPermission/entry/src/main/ets/view/DeviceItem.ets b/Security/AccessPermission/entry/src/main/ets/view/DeviceItem.ets index fd847c913c20cdf7707f2e203e027a082df36b59..d6c002e1def24a46ef922c585285d6162a31aa76 100644 --- a/Security/AccessPermission/entry/src/main/ets/view/DeviceItem.ets +++ b/Security/AccessPermission/entry/src/main/ets/view/DeviceItem.ets @@ -13,13 +13,13 @@ * limitations under the License. */ -import { DeviceBean } from '../common/bean/DeviceBean'; +import { DeviceBean } from '../viewmodel/DeviceBean'; import { CommonConstants } from '../common/constants/CommonConstants'; @Component export struct DeviceItem { - private item: DeviceBean; - private index: number; + private item: DeviceBean = new DeviceBean('', ''); + private index: number = 0; build() { Column() { diff --git a/Security/AccessPermission/entry/src/main/ets/view/DeviceListDialog.ets b/Security/AccessPermission/entry/src/main/ets/view/DeviceListDialog.ets index c62b8e21a86e13efbd25244830140fbb059f601c..136f4db9647880d954161c674fb55e264c77e510 100644 --- a/Security/AccessPermission/entry/src/main/ets/view/DeviceListDialog.ets +++ b/Security/AccessPermission/entry/src/main/ets/view/DeviceListDialog.ets @@ -13,10 +13,10 @@ * limitations under the License. */ -import { DeviceBean } from '../common/bean/DeviceBean'; +import { DeviceBean } from '../viewmodel/DeviceBean'; import { DeviceListUtil } from '../common/util/DeviceListUtil'; import { DeviceItem } from './DeviceItem'; -import { CommonConstants } from '../common/constants/CommonConstants'; +import { CommonConstants, DeviceInfoInterface } from '../common/constants/CommonConstants'; @CustomDialog export struct DeviceListDialog { @@ -25,10 +25,10 @@ export struct DeviceListDialog { controller: CustomDialogController; aboutToAppear() { - this.deviceListUtil.initDmInstance((data) => { + this.deviceListUtil.initDmInstance((data: DeviceInfoInterface) => { this.deviceList.push(new DeviceBean(this.deviceListUtil.dealDeviceId(data.device.deviceId), data.device.deviceName)); - const map = new Map(); + const map: Map = new Map(); this.deviceList = this.deviceList.filter( (item: DeviceBean) => (!map.has(item.deviceId) && map.set(item.deviceId, 1))); }); @@ -58,7 +58,7 @@ export struct DeviceListDialog { ListItem() { DeviceItem({item: item, index: index}); } - }, item => JSON.stringify(item)) + }, (item: DeviceBean) => JSON.stringify(item)) } .width(CommonConstants.FULL_PERCENT) .height(this.deviceList.length > 1 ? diff --git a/Security/AccessPermission/entry/src/main/ets/common/bean/DeviceBean.ts b/Security/AccessPermission/entry/src/main/ets/viewmodel/DeviceBean.ts similarity index 100% rename from Security/AccessPermission/entry/src/main/ets/common/bean/DeviceBean.ts rename to Security/AccessPermission/entry/src/main/ets/viewmodel/DeviceBean.ts diff --git a/Security/AccessPermission/entry/src/main/module.json5 b/Security/AccessPermission/entry/src/main/module.json5 index 5e66762644c5d57431fd11a17490284db8bace53..4233bb8235cbbbbef449f06f2808f620d7c4d8ae 100644 --- a/Security/AccessPermission/entry/src/main/module.json5 +++ b/Security/AccessPermission/entry/src/main/module.json5 @@ -35,11 +35,13 @@ "requestPermissions": [ { "name" : "ohos.permission.DISTRIBUTED_DATASYNC", - "reason": "$string:reason", - "usedScene": { - "abilities": ["EntryAbility"], - "when": "inuse" - } + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } } ] } diff --git a/Security/StringCipherArkTS/README.md b/Security/StringCipherArkTS/README.md index 426cccd56d09f8b9a7ebb66b7000506c32574c6b..c05e4793889eab9725f57bcdda9ad66400a3dd40 100644 --- a/Security/StringCipherArkTS/README.md +++ b/Security/StringCipherArkTS/README.md @@ -17,13 +17,13 @@ ### 软件要求 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 ### 硬件要求 - 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +- OpenHarmony系统:3.2 Release。 ### 环境搭建 @@ -49,8 +49,6 @@ ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ └──User.ets // 用户实体类 │ │ ├──constants │ │ │ └──CommonConstants.ets // 公共常量类 │ │ └──utils @@ -63,10 +61,12 @@ │ ├──model │ │ ├──RdbModel.ets // 数据库业务处理文件 │ │ └──UserTableApi.ets // 用户表具体业务文件 -│ └──pages -│ ├──Login.ets // 登录页 -│ ├──Register.ets // 注册页 -│ └──Welcome.ets // 欢迎页 +│ ├──pages +│ │ ├──Login.ets // 登录页 +│ │ ├──Register.ets // 注册页 +│ │ └──Welcome.ets // 欢迎页 +│ └──viewmodel +│ └──User.ets // 用户实体类 └──entry/src/main/resources // 资源文件目录 ``` @@ -75,9 +75,9 @@ ```typescript // CommonConstants.ets -/** - * 创建表的SQL语句 - */ + /** + * 创建表的SQL语句 + */ static readonly CREATE_TABLE_SQL: string = 'CREATE TABLE IF NOT EXISTS user(' + 'id INTEGER PRIMARY KEY AUTOINCREMENT, ' + 'username TEXT NOT NULL, ' + @@ -92,9 +92,9 @@ import dataRdb from '@ohos.data.relationalStore'; ... export class RdbModel { + private rdbStore: dataRdb.RdbStore | null = null; + private tableName: string = ''; private sqlCreateTable: string = ''; - private columns: Array = []; - private STORE_CONFIG = { name: CommonConstants.DATABASE_NAME, securityLevel: dataRdb.SecurityLevel.S1 }; ... constructor(tableName: string, sqlCreateTable: string, columns: Array) { this.tableName = tableName; @@ -104,18 +104,17 @@ export class RdbModel { } /** - * 获取数据库操作对象rdbStore + * 获取数据库操作对象rdbStore. */ getRdbStore() { - let getPromiseRdb = dataRdb.getRdbStore(getContext(), this.STORE_CONFIG); + let getPromiseRdb = dataRdb.getRdbStore(getContext(), { name: CommonConstants.DATABASE_NAME, securityLevel: dataRdb.SecurityLevel.S1 }); getPromiseRdb.then(rdbStore => { this.rdbStore = rdbStore; this.rdbStore.executeSql(this.sqlCreateTable); - }).catch((err) => { - Logger.error("getRdbStore err." + JSON.stringify(err)); + }).catch((err: Error) => { + Logger.error(`getRdbStore err ${JSON.stringify(err)}`); }); } -} ``` 创建UserTableApi.ets文件,实例化RdbModel创建userTable对象。并对外提供可操作用户数据表的API接口,包括插入数据、根据用户名查询用户信息等方法。 @@ -123,8 +122,8 @@ export class RdbModel { ```typescript // UserTableApi.ets export class UserTableApi { - private userTable = new RdbModel(TABLE_NAME, CREATE_USER_TABLE, COLUMNS); - + private userTable = new RdbModel(TABLE_NAME, CREATE_USER_TABLE, COLUMNS); + /** * 将数据保存到数据库中 * @@ -134,14 +133,14 @@ export class UserTableApi { this.userTable.insertData(user); } - /** + /** * 根据用户名查询用户信息 * * @param username 查询的用户名 * @returns 查询结果集 */ - async queryUserByUsername(username: string) { - let resultList; + async queryUserByUsername(username: string): Promise { + let resultList: Array; // 过滤条件 let predicates = new dataRdb.RdbPredicates(TABLE_NAME); predicates.equalTo('username', username); @@ -171,7 +170,7 @@ export class UserTableApi { import cryptoFramework from '@ohos.security.cryptoFramework'; ... class AesUtil { - private globalCipher: cryptoFramework.Cipher = null; + private globalCipher: cryptoFramework.Cipher = cryptoFramework.createCipher(CommonConstants.GENERATOR_NAME; private globalKey: cryptoFramework.SymKey = null; /** @@ -194,18 +193,18 @@ class AesUtil { // 生成加解密生成器 this.globalCipher = cryptoFramework.createCipher(cipherAlgName); } catch (error) { - Logger.error(`createCipher failed, ${error.code}, ${error.message}`); + Logger.error(`createCipher failed, error is ${JSON.stringify(err)}`); } }); } // 加密 - async encrypt(content: string): Promise { + async encrypt(content: string, authTag: string): Promise { ... } - // 解密 - async decrypt(content: string): Promise { + // 解密 + async decrypt(content: string, authTag: string): Promise { ... } } @@ -231,7 +230,7 @@ class AesUtil { iv: ivBlob, aad: aadBlob, authTag: tagBlob, - algName: "GcmParamsSpec" + algName: `GcmParamsSpec` }; return gcmParamsSpec; } @@ -245,7 +244,7 @@ class AesUtil { genKeyMaterialBlob(data: Array): cryptoFramework.DataBlob { let keyMaterial = new Uint8Array(data); return { data: keyMaterial }; - } + } } ``` 在AesUtil.ets的encrypt方法中实现密码加密逻辑。由于本示例加密数据量较小,所以这里直接使用update一步完成加密操作。若数据量较大,可通过update方法分段加密。主要实现以下步骤: @@ -284,7 +283,7 @@ class AesUtil { // Uint8Array转base64 let encryptContent: string = DataTransformUtil.uint8ArrayToBase64(updateOutput.data); let authTagContent: string = DataTransformUtil.uint8ArrayToBase64(authTag.data); - let user = new User(null, null, encryptContent, authTagContent); + let user = new User(null, ``, encryptContent, authTagContent); return user; } } @@ -303,7 +302,7 @@ class AesUtil { class AesUtil { ... - /** + /** * 解密 * * @param content 解密内容 diff --git a/Security/StringCipherArkTS/entry/oh-package.json5 b/Security/StringCipherArkTS/entry/oh-package.json5 index 19b9234a98d43a4711a0fc32cef604159228d3cd..225946cb11a2c405c8dc81eea89c22f923556638 100644 --- a/Security/StringCipherArkTS/entry/oh-package.json5 +++ b/Security/StringCipherArkTS/entry/oh-package.json5 @@ -7,4 +7,4 @@ "main": "", "version": "1.0.0", "dependencies": {} -} \ No newline at end of file +} diff --git a/Security/StringCipherArkTS/entry/src/main/ets/common/constants/CommonConstants.ets b/Security/StringCipherArkTS/entry/src/main/ets/common/constants/CommonConstants.ets index c7c96259f74324aa8fab7e17eb94119d9287fd18..f99eff32c37678c04a3e88fcc0974d3b566ef662 100644 --- a/Security/StringCipherArkTS/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/Security/StringCipherArkTS/entry/src/main/ets/common/constants/CommonConstants.ets @@ -123,12 +123,12 @@ export default class CommonConstants { * The user name contains 1 to 14 characters, * including letters, digits, and underscores (_), or a combination of these characters. */ - static readonly REGEXP_NAME: RegExp = /^[\u4E00-\u9FA5A-Za-z0-9_]{1,14}$/; + static readonly REGEXP_NAME: RegExp = new RegExp(`^[\u4E00-\u9FA5A-Za-z0-9_]{1,14}$`); /** * The password is 4 - 14 digits, letters, or! @ $#% ^ & * or a combination of them. */ - static readonly REGEXP_PASSWORD: RegExp = /^[A-Za-z0-9!@$#%^&*]{4,14}$/; + static readonly REGEXP_PASSWORD: RegExp = new RegExp(`^[A-Za-z0-9!@$#%^&*]{4,14}$`); /** * Duration of prompt. diff --git a/Security/StringCipherArkTS/entry/src/main/ets/common/utils/AesUtil.ets b/Security/StringCipherArkTS/entry/src/main/ets/common/utils/AesUtil.ets index fa7cf31418c28517ec37a9269c429b111d448fc2..828ae0e127646bee11b44abcd9530fe3e17adb61 100644 --- a/Security/StringCipherArkTS/entry/src/main/ets/common/utils/AesUtil.ets +++ b/Security/StringCipherArkTS/entry/src/main/ets/common/utils/AesUtil.ets @@ -17,11 +17,11 @@ import cryptoFramework from '@ohos.security.cryptoFramework'; import CommonConstants from '../constants/CommonConstants'; import DataTransformUtil from '../utils/DataTransformUtil'; import Logger from '../utils/Logger'; -import { User } from '../bean/User'; +import { User } from '../../viewmodel/User'; class AesUtil { - private globalCipher: cryptoFramework.Cipher = null; - private globalKey: cryptoFramework.SymKey = null; + private globalCipher: cryptoFramework.Cipher = cryptoFramework.createCipher(CommonConstants.GENERATOR_NAME); + private globalKey: cryptoFramework.SymKey | null = null; /** * Constructor initialization to generate a key. @@ -42,7 +42,7 @@ class AesUtil { try { this.globalCipher = cryptoFramework.createCipher(cipherAlgName); } catch (error) { - Logger.error(`createCipher failed, ${error.code}, ${error.message}`); + Logger.error(`createCipher failed, error is ${JSON.stringify(err)}`); } }); } @@ -71,7 +71,7 @@ class AesUtil { iv: ivBlob, aad: aadBlob, authTag: tagBlob, - algName: "GcmParamsSpec" + algName: `GcmParamsSpec` }; return gcmParamsSpec; } @@ -87,7 +87,7 @@ class AesUtil { let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE; let gcmParams = await this.genGcmParamsSpec(); await this.globalCipher.init(mode, this.globalKey, gcmParams); - let plainTextBlob = { + let plainTextBlob: cryptoFramework.DataBlob = { data: DataTransformUtil.stringToUint8Array(content) }; let updateOutput: cryptoFramework.DataBlob = await this.globalCipher.update(plainTextBlob); @@ -97,7 +97,7 @@ class AesUtil { let authTag: cryptoFramework.DataBlob = await this.globalCipher.doFinal(null); let encryptContent: string = DataTransformUtil.uint8ArrayToBase64(updateOutput.data); let authTagContent: string = DataTransformUtil.uint8ArrayToBase64(authTag.data); - let user = new User(null, null, encryptContent, authTagContent); + let user = new User(null, ``, encryptContent, authTagContent); return user; } diff --git a/Security/StringCipherArkTS/entry/src/main/ets/common/utils/DataTransformUtil.ets b/Security/StringCipherArkTS/entry/src/main/ets/common/utils/DataTransformUtil.ets index d3f98b63a6220c9a44f91a8ffe5265a2aae29e3b..b6c692a8702c801c6db020417f333b7368e24f94 100644 --- a/Security/StringCipherArkTS/entry/src/main/ets/common/utils/DataTransformUtil.ets +++ b/Security/StringCipherArkTS/entry/src/main/ets/common/utils/DataTransformUtil.ets @@ -16,7 +16,7 @@ import util from '@ohos.util'; class DataTransformUtil { - private base64Helper: util.Base64Helper = null; + private base64Helper: util.Base64Helper | null= null; constructor() { this.base64Helper = new util.Base64Helper(); @@ -29,7 +29,7 @@ class DataTransformUtil { * @returns Uint8Array data. */ base64ToUint8Array(content: string): Uint8Array { - let uint8ArrayData: Uint8Array = this.base64Helper.decodeSync(content); + let uint8ArrayData: Uint8Array = (this.base64Helper as util.Base64Helper).decodeSync(content); return uint8ArrayData; } @@ -40,7 +40,7 @@ class DataTransformUtil { * @returns Base64 data. */ uint8ArrayToBase64(content: Uint8Array): string { - let base64Data: string = this.base64Helper.encodeToStringSync(content); + let base64Data: string = (this.base64Helper as util.Base64Helper).encodeToStringSync(content); return base64Data; } @@ -51,7 +51,7 @@ class DataTransformUtil { * @returns Uint8Array data. */ stringToUint8Array(content: string): Uint8Array { - let arr = []; + let arr: number[] = []; for (let i = 0, j = content.length; i < j; ++i) { arr.push(content.charCodeAt(i)); } diff --git a/Security/StringCipherArkTS/entry/src/main/ets/common/utils/Logger.ets b/Security/StringCipherArkTS/entry/src/main/ets/common/utils/Logger.ets index 5f2e7bda611d1e268602283d85c999ee190268b9..920f285349fd452e70987d2ce4854f591b77a5b2 100644 --- a/Security/StringCipherArkTS/entry/src/main/ets/common/utils/Logger.ets +++ b/Security/StringCipherArkTS/entry/src/main/ets/common/utils/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: Object[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: Object[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: Object[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: Object[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/Security/StringCipherArkTS/entry/src/main/ets/model/RdbModel.ets b/Security/StringCipherArkTS/entry/src/main/ets/model/RdbModel.ets index ba52cf9601eff9f0d9e49bc983c1c5596dcd5c1a..8736b2f577da209d7ddcd8987bdfba09687d07c9 100644 --- a/Security/StringCipherArkTS/entry/src/main/ets/model/RdbModel.ets +++ b/Security/StringCipherArkTS/entry/src/main/ets/model/RdbModel.ets @@ -16,14 +16,13 @@ import dataRdb from '@ohos.data.relationalStore'; import CommonConstants from '../common/constants/CommonConstants'; import Logger from '../common/utils/Logger'; -import { User } from '../common/bean/User'; +import { User } from '../viewmodel/User'; export class RdbModel { - private rdbStore: dataRdb.RdbStore = null; + private rdbStore: dataRdb.RdbStore | null = null; private tableName: string = ''; private sqlCreateTable: string = ''; private columns: Array = []; - private STORE_CONFIG = { name: CommonConstants.DATABASE_NAME, securityLevel: dataRdb.SecurityLevel.S1 }; constructor(tableName: string, sqlCreateTable: string, columns: Array) { this.tableName = tableName; @@ -36,11 +35,11 @@ export class RdbModel { * Obtaining rdbStore. */ getRdbStore() { - let getPromiseRdb = dataRdb.getRdbStore(getContext(), this.STORE_CONFIG); + let getPromiseRdb = dataRdb.getRdbStore(getContext(), { name: CommonConstants.DATABASE_NAME, securityLevel: dataRdb.SecurityLevel.S1 }); getPromiseRdb.then(rdbStore => { this.rdbStore = rdbStore; this.rdbStore.executeSql(this.sqlCreateTable); - }).catch((err) => { + }).catch((err: Error) => { Logger.error(`getRdbStore err ${JSON.stringify(err)}`); }); } @@ -52,8 +51,7 @@ export class RdbModel { */ insertData(user: User) { try { - let valueBucket = JSON.parse(JSON.stringify(user)); - this.rdbStore.insert(this.tableName, valueBucket); + (this.rdbStore as dataRdb.RdbStore).insert(this.tableName, JSON.parse(JSON.stringify(user))); } catch (err) { Logger.error(`insert data failed due to ${JSON.stringify(err)}`); } @@ -66,12 +64,12 @@ export class RdbModel { * @returns resultList Query result set. */ async query(predicates: dataRdb.RdbPredicates): Promise{ - let resultList; + let resultList: null | dataRdb.ResultSet = null; try { - resultList = await this.rdbStore.query(predicates, this.columns); + resultList = await (this.rdbStore as dataRdb.RdbStore).query(predicates, this.columns); } catch (err) { Logger.error(`query data failed due to ${JSON.stringify(err)}`); } - return resultList; + return resultList as dataRdb.ResultSet; } } \ No newline at end of file diff --git a/Security/StringCipherArkTS/entry/src/main/ets/model/UserTableApi.ets b/Security/StringCipherArkTS/entry/src/main/ets/model/UserTableApi.ets index cb0477bed0b39ad1213d2c31376d53bcd8f9d2e2..5fca7d9622d92817b1ae3ccdde847062937ca583 100644 --- a/Security/StringCipherArkTS/entry/src/main/ets/model/UserTableApi.ets +++ b/Security/StringCipherArkTS/entry/src/main/ets/model/UserTableApi.ets @@ -14,7 +14,7 @@ */ import dataRdb from '@ohos.data.relationalStore'; -import { User } from '../common/bean/User'; +import { User } from '../viewmodel/User'; import { RdbModel } from '../model/RdbModel' import CommonConstants from '../common/constants/CommonConstants'; import Logger from '../common/utils/Logger'; @@ -60,7 +60,7 @@ export class UserTableApi { if (!resultSet) { Logger.error(`resultSet is null or undefined`); } - let userList = []; + let userList: User[] = []; for (let i = 0; i < resultSet.rowCount; i++) { resultSet.goToNextRow(); let user = new User(resultSet.getDouble(resultSet.getColumnIndex('id')), diff --git a/Security/StringCipherArkTS/entry/src/main/ets/pages/Login.ets b/Security/StringCipherArkTS/entry/src/main/ets/pages/Login.ets index c7f779a6a2d499ffe3e402f241812b994dfd5326..b2a31e10382a222c7f7537e692633e83dba4615c 100644 --- a/Security/StringCipherArkTS/entry/src/main/ets/pages/Login.ets +++ b/Security/StringCipherArkTS/entry/src/main/ets/pages/Login.ets @@ -14,7 +14,7 @@ */ import router from '@ohos.router'; -import { User } from '../common/bean/User'; +import { User } from '../viewmodel/User'; import { UserTableApi } from '../model/UserTableApi'; import PromptUtil from '../common/utils/PromptUtil'; import AesUtil from '../common/utils/AesUtil'; @@ -124,9 +124,9 @@ struct Index { .onClick(() => { router.pushUrl({ url: CommonConstants.ROUTER_REGISTER_URL - }).catch(err => { - Logger.error(`Failed router to register page, code is ${err.code}, message is ${err.message}`); - }); + }).catch((err: Error) => { + Logger.error(`Failed router to register page, ${err}`); + }); }) } .backgroundColor($r('app.color.background')) @@ -185,7 +185,7 @@ struct Index { AesUtil.decrypt(this.userList[0]?.password, this.userList[0]?.authTag).then((data) => { this.decryptPassword = data; this.login(); - }).catch(err => { + }).catch((err: Error) => { Logger.error(`AesDecrypt err cause ${JSON.stringify(err)}`); PromptUtil.promptMessage($r('app.string.message_sys_err'), CommonConstants.PROMPT_TIME); }) @@ -202,8 +202,8 @@ struct Index { router.replaceUrl({ url: CommonConstants.ROUTER_WELCOME_URL, params: { 'username': user.username } - }).catch(err => { - Logger.error(`Failed router to welcome page, code is ${err.code}, message is ${err.message}`); + }).catch((err: Error) => { + Logger.error(`Failed router to welcome page, ${err}`); }); } else { PromptUtil.promptMessage($r('app.string.message_password_err'), CommonConstants.PROMPT_TIME); diff --git a/Security/StringCipherArkTS/entry/src/main/ets/pages/Register.ets b/Security/StringCipherArkTS/entry/src/main/ets/pages/Register.ets index d53657f1fe75cf283894523b1d713c32a8735f63..778c5eeb5775c0fb874ad60baca4790ee73c690b 100644 --- a/Security/StringCipherArkTS/entry/src/main/ets/pages/Register.ets +++ b/Security/StringCipherArkTS/entry/src/main/ets/pages/Register.ets @@ -15,7 +15,7 @@ import router from '@ohos.router'; import AesUtil from '../common/utils/AesUtil'; -import { User } from '../common/bean/User'; +import { User } from '../viewmodel/User'; import { UserTableApi } from '../model/UserTableApi'; import CommonConstants from '../common/constants/CommonConstants'; import PromptUtil from '../common/utils/PromptUtil'; @@ -196,7 +196,7 @@ struct Register { aesEncrypt() { AesUtil.encrypt(this.password).then((data: User) => { this.insertUser(data.password, data.authTag); - }).catch(err => { + }).catch((err: Error) => { Logger.error(`AesEecrypt err cause ${err}`); PromptUtil.promptMessage($r('app.string.message_sys_err'), CommonConstants.PROMPT_TIME) }); diff --git a/Security/StringCipherArkTS/entry/src/main/ets/pages/Welcome.ets b/Security/StringCipherArkTS/entry/src/main/ets/pages/Welcome.ets index e47180634dd90127289dc3e0981643435b523777..458204a1cf3eee33ff911c5bba62e15d65f2a323 100644 --- a/Security/StringCipherArkTS/entry/src/main/ets/pages/Welcome.ets +++ b/Security/StringCipherArkTS/entry/src/main/ets/pages/Welcome.ets @@ -16,10 +16,13 @@ import router from '@ohos.router'; import CommonConstants from '../common/constants/CommonConstants'; +class c1 { + username: string | null = null +} @Entry @Component struct Welcome { - @State username: string = router.getParams()['username']; + @State username: string = (router.getParams() as c1).username as string; @State message: Resource = $r('app.string.message_login_success'); build() { diff --git a/Security/StringCipherArkTS/entry/src/main/ets/common/bean/User.ets b/Security/StringCipherArkTS/entry/src/main/ets/viewmodel/User.ets similarity index 88% rename from Security/StringCipherArkTS/entry/src/main/ets/common/bean/User.ets rename to Security/StringCipherArkTS/entry/src/main/ets/viewmodel/User.ets index 604989239fcfcaf0c3155cf001fa094e9b6e4787..783976ff9bd8923772b513ddb686e42b997ed01f 100644 --- a/Security/StringCipherArkTS/entry/src/main/ets/common/bean/User.ets +++ b/Security/StringCipherArkTS/entry/src/main/ets/viewmodel/User.ets @@ -14,12 +14,12 @@ */ export class User { - id: number; + id: number | null; username: string; password: string; authTag: string; - constructor(id: number, username: string, password: string, authTag: string) { + constructor(id: number | null, username: string, password: string, authTag: string) { this.id = id; this.username = username; this.password = password; diff --git a/Security/StringCipherArkTS/hvigor/hvigor-config.json5 b/Security/StringCipherArkTS/hvigor/hvigor-config.json5 index e5bf1bf2b10d77ae8849c97d378d3831f13480b2..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/Security/StringCipherArkTS/hvigor/hvigor-config.json5 +++ b/Security/StringCipherArkTS/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.1.1", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.1.1" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/ThirdPartyComponents/ThirdPartyLibrary/README.md b/ThirdPartyComponents/ThirdPartyLibrary/README.md index 843b7cc98714b53a84935bbac02864f6d1e34154..34df0a3b3ab05afc2fff099842f64299e5088ce4 100644 --- a/ThirdPartyComponents/ThirdPartyLibrary/README.md +++ b/ThirdPartyComponents/ThirdPartyLibrary/README.md @@ -8,49 +8,50 @@ ### 相关概念 -- [Navigation](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-navigation.md):一般作为Page页面的根容器,通过属性设置来展示页面的标题、工具栏、菜单。 -- [Tabs](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabs.md):一种可以通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。 -- [Canvas](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-components-canvas-canvas.md):画布组件,用于自定义绘制图形。 -- [OpenHarmony 共享包](https://gitee.com/openharmony-tpc/docs/blob/master/OpenHarmony_npm_usage.md):OpenHarmony 共享包定义了特定的工程结构和配置文件,支持OpenHarmony页面组件相关API、资源的调用。 +- [Navigation](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-navigation.md):一般作为Page页面的根容器,通过属性设置来展示页面的标题、工具栏、菜单。 -## 环境搭建 +- [Tabs](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabs.md):一种可以通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。 + +- [Canvas](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-components-canvas-canvas.md):画布组件,用于自定义绘制图形。 + +- [OpenHarmony 共享包](https://gitee.com/openharmony-tpc/docs/blob/master/OpenHarmony_npm_usage.md):OpenHarmony 共享包定义了特定的工程结构和配置文件,支持OpenHarmony页面组件相关API、资源的调用。 -### 软件要求 +# 环境搭建 -- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release及以上版本。 -- OpenHarmony SDK版本:API version 9及以上版本。 +## 软件要求 -### 硬件要求 +- [DevEco Studio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87)版本:DevEco Studio 3.1 Release。 +- OpenHarmony SDK版本:API version 9。 -- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 -- OpenHarmony系统:3.2 Release及以上版本。 +## 硬件要求 -### 环境搭建 +- 开发板类型:[润和RK3568开发板](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-appendix-rk3568.md)。 +- OpenHarmony系统:3.2 Release。 + +## 环境搭建 完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: -1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以3.2 Release版本为例: +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。以3.2 Release版本为例: ![](figures/zh-cn_image_0000001554588725.png) -2. 搭建烧录环境。 - 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) - 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-env-win.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-3568-burn.md) -3. 搭建开发环境。 - 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 - 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 - 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#创建ets工程)创建工程(模板选择“Empty Ability”)。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md#使用真机运行应用)。 ## 代码结构解读 -本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +本篇Codelab只对核心代码进行讲解,完整代码可以直接从gitee获取。 ``` ├──entry/src/main/ets // 代码区 │ ├──common -│ │ ├──bean -│ │ │ └──ButtonList.ets // 按钮类 │ │ ├──constants // 常量文件 │ │ │ └──CommonConst.ets // 通用常量 │ │ ├──lottie @@ -66,19 +67,23 @@ │ │ ├──InnerComponent.ets // 本地库子页面 │ │ └──OuterComponent.ets // 社区库子界面 │ └──viewmodel +│ ├──ButtonList.ets // 按钮类 │ └──InnerViewModel.ets // 本地库数据获取 ├──entry/src/main/resources // 资源文件 └──library/src/main/ets // 本地库代码区 - └──components - └──MainPage - └──Buttons.ets // 本地库代码实现 + ├──components + │ └──MainPage + │ └──Buttons.ets // 本地库代码实现 + └──viewmodel + └──ButtonsViewModel.ets // 按钮数据类型 ``` -## 整体框架搭建 +# 整体框架搭建 本篇Codelab由主页面、本地库组件页面、社区库组件页面三个页面组成,主页面由Navigation作为根组件实现全局标题,由Tabs组件实现本地库和社区库页面的切换,代码如下: ```typescript +// MainPage.ets import { Outer } from '../view/OuterComponent'; import { Inner } from '../view/InnerComponent'; import { CommonConstants } from '../common/constants/CommonConst'; @@ -120,26 +125,27 @@ struct Index { 在pages文件夹下新建components文件并在此文件夹下创建两个ArkTS文件,分别命名为inner和outer,至此整体框架搭建完毕。 -## 本地库实现 +# 本地库实现 本地库主要是指未上架到ohpm中心且在项目组内共享使用的库文件,这类库需要开发者在项目中创建并开发新的Library模块,创建步骤如下: -1. 通过如下两种方法,在OpenHarmony工程中添加OpenHarmony ohpm块。 - - 方法1:鼠标移到工程目录顶部,单击鼠标右键,选择New\>Module。 - - 方法2:在菜单栏选择File \> New \> Module。 +1. 通过如下两种方法,在OpenHarmony工程中添加OpenHarmony ohpm块。 + - 方法1:鼠标移到工程目录顶部,单击鼠标右键,选择New\>Module。 + - 方法2:在菜单栏选择File \> New \> Module。 -2. 在Choose Your Ability Template界面中,选择Static Library,并单击Next。 -3. 在Configure the New Module界面中,设置新添加的模块信息,设置完成后,单击Finish完成创建。 - - Module name:新增模块的名称。 - - Language:选择开发OpenHarmony ohpm包的语言。 - - Device type:选择OpenHarmony ohpm包支持的设备类型。 - - Enable Native:是否创建一个用于调用C++代码的OpenHarmony ohpm共享模块。 +2. 在Choose Your Ability Template界面中,选择Static Library,并单击Next。 +3. 在Configure the New Module界面中,设置新添加的模块信息,设置完成后,单击Finish完成创建。 + - Module name:新增模块的名称。 + - Language:选择开发OpenHarmony ohpm包的语言。 + - Device type:选择OpenHarmony ohpm包支持的设备类型。 + - Enable Native:是否创建一个用于调用C++代码的OpenHarmony ohpm共享模块。 -4. 创建完成后,会在工程目录中生成OpenHarmony ohpm共享模块及相关文件。 +4. 创建完成后,会在工程目录中生成OpenHarmony ohpm共享模块及相关文件。 本Codelab在本地库中实现了对Button组件的简单封装,主要代码实现如下: ```typescript +// library/src/main/ets/components/MainPage/Buttons.ets @Component export struct Buttons { @Prop buttonText: string; @@ -147,24 +153,18 @@ export struct Buttons { @Prop buttonShape: string; @Prop buttonType: string; @Prop fontColor: string; - click: () => void; - - ... build() { Row() { Column() { - Button({ type: this.fetchType(this.buttonShape), stateEffect: this.stateEffect }){ + Button({ type: ButtonViewModel.fetchType(this.buttonShape), stateEffect: this.stateEffect }){ Text(this.buttonText) .fontSize($r('app.float.default_16')) .fontColor(this.fontColor || $r('app.color.white')) } .width($r('app.float.default_90')) .height($r('app.float.default_35')) - .backgroundColor(this.fetchBackgroundColor(this.buttonType)) - .onClick(() => { - this.click(); - }) + .backgroundColor(ButtonViewModel.fetchBackgroundColor(this.buttonType)) } } } @@ -175,13 +175,13 @@ export struct Buttons { 方式一:在Terminal窗口中,执行如下命令进行安装,并会在package.json中自动添加依赖。 -```typescript +``` ohpm install ../library --save ``` 方式二:在工程的oh\_package.json5中设置OpenHarmony ohpm三方包依赖,配置示例如下: -```typescript +```json "dependencies": { "@ohos/library": "file:../library" } @@ -189,15 +189,15 @@ ohpm install ../library --save 依赖设置完成后,需要执行ohpm install命令安装依赖包,依赖包会存储在工程的oh\_modules目录下。 -```typescript +``` ohpm install ``` 在完成上述步骤后,我们继续完成inner页面的开发,在inner页面中我们通过import的方式引入开发的本地库,并通过循环传入不同的参数展示不同的button,代码实现如下: ```typescript +// InnerComponent.ets import { Buttons } from '@ohos/library'; -import { BUTTON_LIST, SPACE_12, FONT_WEIGHT_400, OPACITY_6, ASPECT_RATIO_175 } from '../../common/Const'; @Component export struct Inner { @@ -207,7 +207,7 @@ export struct Inner { build() { Scroll(this.scroller) { Column({ space: CommonConstants.SPACE_12 }) { - ForEach(this.buttonList, (item) => { + ForEach(this.buttonList, (item: ButtonList) => { Column() { Flex({ direction: FlexDirection.Column, @@ -270,21 +270,21 @@ export struct Inner { 至此本地库的调用已完成。 -## 社区库调用 +# 社区库调用 社区库是指已经由贡献者上架到ohpm中心供其他开发者下载使用的库,调用这类库的方法如下: 然后通过如下两种方式设置OpenHarmony ohpm三方包依赖信息(下面步骤以@ohos/lottie三方库为例,其他库替换对应库的名字及版本号即可): -- 方式一:在Terminal窗口中,执行如下命令安装OpenHarmony ohpm三方包,DevEco Studio会自动在工程的oh\_package.json中自动添加三方包依赖。 +- 方式一:在Terminal窗口中,执行如下命令安装OpenHarmony ohpm三方包,DevEco Studio会自动在工程的oh\_package.json中自动添加三方包依赖。 - ```typescript + ``` ohpm install @ohos/lottie --save ``` -- 方式二:在工程的oh\_package.json5中设置OpenHarmony ohpm三方包依赖,配置示例如下: +- 方式二:在工程的oh\_package.json5中设置OpenHarmony ohpm三方包依赖,配置示例如下: - ```typescript + ```json "dependencies": { "@ohos/lottie": "^2.0.0" } @@ -292,16 +292,16 @@ export struct Inner { 依赖设置完成后,需要执行ohpm install命令安装依赖包,依赖包会存储在工程的oh\_modules目录下。 - ```typescript + ``` ohpm install ``` - 在完成上述步骤后,我们继续完成outer页面的开发,在outer页面中我们通过import的方式引入配置的社区库,并实现对社区库动画的调用,关键代码如下: ```typescript -import lottie from '@ohos/lottie'; -import { Logger } from '../common/utils/log/logger'; +// OuterComponent.ets +import lottie, { AnimationItem } from '@ohos/lottie'; +import Logger from '../common/utils/log/logger'; import { CommonConstants } from '../common/constants/CommonConst'; @Component @@ -309,8 +309,8 @@ export struct Outer { private renderingSettings: RenderingContextSettings = new RenderingContextSettings(true); private renderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.renderingSettings); private animateName: string = CommonConstants.ANIMATE_NAME; - private animateItem: any = null; - @State canvasTitle: Resource = undefined; + private animateItem: AnimationItem | null = null; + @State canvasTitle: Resource | undefined = undefined; ... @@ -374,8 +374,7 @@ export struct Outer { 您已经完成了本次Codelab的学习,并了解到以下知识点: -1. 如何创建及调用本地三方库。 -2. 如何调用社区三方库。 +1. 如何创建及调用本地三方库。 +2. 如何调用社区三方库。 ![](figures/zh-cn_image_0000001455125133.gif) - diff --git a/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/common/utils/log/Logger.ets b/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/common/utils/log/Logger.ets index 41b5973d80c58762f11f056af3d71d0085d21425..d4edaaaa693cf06d88ec991e732b31fd0af7b655 100644 --- a/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/common/utils/log/Logger.ets +++ b/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/common/utils/log/Logger.ets @@ -31,19 +31,19 @@ class Logger { this.domain = domain; } - debug(...args: any[]): void { + debug(...args: string[]): void { hilog.debug(this.domain, this.prefix, this.format, args); } - info(...args: any[]): void { + info(...args: string[]): void { hilog.info(this.domain, this.prefix, this.format, args); } - warn(...args: any[]): void { + warn(...args: string[]): void { hilog.warn(this.domain, this.prefix, this.format, args); } - error(...args: any[]): void { + error(...args: string[]): void { hilog.error(this.domain, this.prefix, this.format, args); } } diff --git a/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/view/InnerComponent.ets b/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/view/InnerComponent.ets index c59df50c7d18bc4074d7cf5cf0881e6a3dd87197..524fbae573665d4103b442e475d6122772d07898 100644 --- a/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/view/InnerComponent.ets +++ b/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/view/InnerComponent.ets @@ -15,7 +15,7 @@ import { Buttons } from '@ohos/library'; import InnerViewModel from '../viewmodel/InnerViewModel' -import { ButtonList } from '../common/bean/ButtonList'; +import { ButtonList } from '../viewmodel/ButtonList'; import { CommonConstants } from '../common/constants/CommonConst'; @Component @@ -26,7 +26,7 @@ export struct Inner { build() { Scroll(this.scroller) { Column({ space: CommonConstants.SPACE_12 }) { - ForEach(this.buttonList, (item) => { + ForEach(this.buttonList, (item: ButtonList) => { Column() { Flex({ direction: FlexDirection.Column, diff --git a/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/view/OuterComponent.ets b/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/view/OuterComponent.ets index e627b66bd23d7f4e47b0250572d8f834f08df10d..ce9f0ceba9e911cac6374036c32487cf07bada56 100644 --- a/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/view/OuterComponent.ets +++ b/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/view/OuterComponent.ets @@ -13,18 +13,17 @@ * limitations under the License. */ -import lottie from '@ohos/lottie'; +import lottie, { AnimationItem } from '@ohos/lottie'; import Logger from '../common/utils/log/logger'; import { CommonConstants } from '../common/constants/CommonConst'; - @Component export struct Outer { private renderingSettings: RenderingContextSettings = new RenderingContextSettings(true); private renderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.renderingSettings); private animateName: string = CommonConstants.ANIMATE_NAME; - private animateItem: any = null; - @State canvasTitle: Resource = undefined; + private animateItem: AnimationItem | null = null; + @State canvasTitle: Resource | undefined = undefined; aboutToDisappear(): void { Logger.info(CommonConstants.OUTER_TAG, `aboutToDisappear`); diff --git a/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/common/bean/ButtonList.ets b/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/viewmodel/ButtonList.ets similarity index 75% rename from ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/common/bean/ButtonList.ets rename to ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/viewmodel/ButtonList.ets index 93120e7aecc8058fd9a5679e6d9be041cf706502..44b6888c7f829e2ca62e321b45401d4e29329f57 100644 --- a/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/common/bean/ButtonList.ets +++ b/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/viewmodel/ButtonList.ets @@ -17,12 +17,12 @@ * ButtonList item information */ export class ButtonList { - title: string - subtitle: string - backgroundImage: string - buttonText: string - buttonShape: string - buttonType: string - stateEffect: boolean - fontColor: string + title: string = ''; + subtitle: string = ''; + backgroundImage: string = ''; + buttonText: string = ''; + buttonShape: string = ''; + buttonType: string = ''; + stateEffect: boolean = false; + fontColor: string = ''; } \ No newline at end of file diff --git a/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/viewmodel/InnerViewModel.ets b/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/viewmodel/InnerViewModel.ets index 52255d1410dde1d0475e40aaa4b8ac0987c3e191..95111a3f78c7043932ee79b102c860cf94dde44f 100644 --- a/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/viewmodel/InnerViewModel.ets +++ b/ThirdPartyComponents/ThirdPartyLibrary/entry/src/main/ets/viewmodel/InnerViewModel.ets @@ -13,21 +13,21 @@ * limitations under the License. */ -import { ButtonList } from '../common/bean/ButtonList'; +import { ButtonList } from './ButtonList'; class InnerViewModel { getButtonListData() { let ButtonListData: Array = []; for (let i = 0; i < BUTTON_LIST.length; i++) { let ButtonListItem = new ButtonList(); - ButtonListItem = {...BUTTON_LIST[i]}; + ButtonListItem = BUTTON_LIST[i]; ButtonListData.push(ButtonListItem); } return ButtonListData; } } -const BUTTON_LIST = [ +const BUTTON_LIST: ButtonList[] = [ { title: "普通按钮", subtitle: "用于一般界面操作", @@ -39,24 +39,24 @@ const BUTTON_LIST = [ fontColor: '' }, { - title: "强调按钮", - subtitle: "在界面上很突出,用于强调当前操作", - backgroundImage: "", - buttonText: '强调按钮', - buttonShape: 'capsule', - buttonType: 'info', - stateEffect: true, - fontColor: '#409eff' - }, { - title: "文本按钮", - subtitle: "文本按钮为纯文本按钮,点击执行操作", - backgroundImage: "", - buttonText: '文本按钮', - buttonShape: 'capsule', - buttonType: 'none', - stateEffect: true, - fontColor: '#409eff' - }]; + title: "强调按钮", + subtitle: "在界面上很突出,用于强调当前操作", + backgroundImage: "", + buttonText: '强调按钮', + buttonShape: 'capsule', + buttonType: 'info', + stateEffect: true, + fontColor: '#409eff' +}, { + title: "文本按钮", + subtitle: "文本按钮为纯文本按钮,点击执行操作", + backgroundImage: "", + buttonText: '文本按钮', + buttonShape: 'capsule', + buttonType: 'none', + stateEffect: true, + fontColor: '#409eff' +}]; let innerViewModel = new InnerViewModel(); diff --git a/ThirdPartyComponents/ThirdPartyLibrary/hvigor/hvigor-config.json5 b/ThirdPartyComponents/ThirdPartyLibrary/hvigor/hvigor-config.json5 index ff688122467308d3cd299c5b2f36be03fb84f4b0..0450bec27475c1853a73087292c8a8d946880600 100644 --- a/ThirdPartyComponents/ThirdPartyLibrary/hvigor/hvigor-config.json5 +++ b/ThirdPartyComponents/ThirdPartyLibrary/hvigor/hvigor-config.json5 @@ -1,6 +1,6 @@ { - "hvigorVersion": "2.0.0", + "hvigorVersion": "2.4.2", "dependencies": { - "@ohos/hvigor-ohos-plugin": "2.0.0" + "@ohos/hvigor-ohos-plugin": "2.4.2" } } diff --git a/ThirdPartyComponents/ThirdPartyLibrary/library/src/main/ets/viewmodel/ButtonsViewModel.ets b/ThirdPartyComponents/ThirdPartyLibrary/library/src/main/ets/viewmodel/ButtonsViewModel.ets index c51a011ee62321709983520e8e8af3f65ccb7c77..af8f33259c186ce987594cc554df7531c5a2a4e0 100644 --- a/ThirdPartyComponents/ThirdPartyLibrary/library/src/main/ets/viewmodel/ButtonsViewModel.ets +++ b/ThirdPartyComponents/ThirdPartyLibrary/library/src/main/ets/viewmodel/ButtonsViewModel.ets @@ -14,27 +14,27 @@ */ class ButtonViewModel { - fetchType(shape) { + fetchType(shape: string) { let ret: ButtonType; switch (shape) { case 'capsule': ret = ButtonType.Capsule; - break + break; case 'circle': ret = ButtonType.Circle; - break + break; case 'normal': ret = ButtonType.Normal; - break + break; default: ret = ButtonType.Capsule; - break + break; } - return ret + return ret; } - fetchBackgroundColor(type) { - let ret; + fetchBackgroundColor(type: string) { + let ret: Resource; switch (type) { case 'success': ret = $r('app.color.success');