From 424d536937e723d89ebfba8d98b1026809964b53 Mon Sep 17 00:00:00 2001 From: zhangyazhou Date: Tue, 11 Jun 2024 14:47:15 +0800 Subject: [PATCH] init --- .gitignore | 14 ++ AppScope/app.json5 | 10 ++ AppScope/resources/base/element/string.json | 8 ++ AppScope/resources/base/media/app_icon.png | Bin 0 -> 2041 bytes app/.gitignore | 7 + app/build-profile.json5 | 28 ++++ app/hvigorfile.ts | 6 + app/obfuscation-rules.txt | 18 +++ app/oh-package.json5 | 11 ++ app/src/main/ets/appability/AppAbility.ets | 41 ++++++ app/src/main/ets/bean/ConvertItem.ets | 6 + app/src/main/ets/component/ComponentConst.ts | 4 + app/src/main/ets/component/TitleBar.ets | 123 ++++++++++++++++++ app/src/main/ets/pages/Index.ets | 40 ++++++ .../ets/pages/calculate/CalculatePage.ets | 9 ++ .../main/ets/pages/convert/ConvertPage.ets | 71 ++++++++++ app/src/main/ets/pages/convert/LengthPage.ets | 13 ++ app/src/main/ets/theme/CalThemeManager.ets | 8 ++ app/src/main/ets/utils/Res.ets | 13 ++ app/src/main/ets/utils/RoutePath.ets | 13 ++ app/src/main/ets/utils/ScreenUtil.ets | 106 +++++++++++++++ app/src/main/module.json5 | 38 ++++++ .../main/resources/base/element/color.json | 8 ++ .../main/resources/base/element/string.json | 52 ++++++++ app/src/main/resources/base/media/ic_area.svg | 1 + app/src/main/resources/base/media/ic_bmi.svg | 1 + .../base/media/ic_calculator_variant.svg | 1 + .../resources/base/media/ic_chevron_left.svg | 1 + .../main/resources/base/media/ic_close.svg | 1 + .../main/resources/base/media/ic_length.svg | 1 + .../main/resources/base/media/ic_number.svg | 1 + .../main/resources/base/media/ic_refresh.svg | 1 + .../main/resources/base/media/ic_speed.svg | 1 + .../resources/base/media/ic_thermometer.svg | 1 + app/src/main/resources/base/media/ic_time.svg | 1 + .../main/resources/base/media/ic_weight.svg | 1 + app/src/main/resources/base/media/icon.png | Bin 0 -> 2041 bytes .../main/resources/base/media/startIcon.png | Bin 0 -> 4351 bytes .../resources/base/profile/main_pages.json | 6 + .../main/resources/en_US/element/string.json | 52 ++++++++ .../main/resources/zh_CN/element/string.json | 52 ++++++++ app/src/mock/mock-config.json5 | 2 + app/src/ohosTest/ets/test/Ability.test.ets | 35 +++++ app/src/ohosTest/ets/test/List.test.ets | 5 + .../ohosTest/ets/testability/TestAbility.ets | 48 +++++++ .../ohosTest/ets/testability/pages/Index.ets | 17 +++ .../ets/testrunner/OpenHarmonyTestRunner.ets | 90 +++++++++++++ app/src/ohosTest/module.json5 | 38 ++++++ .../resources/base/element/color.json | 8 ++ .../resources/base/element/string.json | 16 +++ .../ohosTest/resources/base/media/icon.png | Bin 0 -> 2041 bytes .../resources/base/profile/test_pages.json | 5 + app/src/test/List.test.ets | 5 + app/src/test/LocalUnit.test.ets | 33 +++++ build-profile.json5 | 49 +++++++ hvigor/hvigor-config.json5 | 21 +++ hvigorfile.ts | 6 + img.png | Bin 0 -> 45318 bytes oh-package.json5 | 15 +++ readme.md | 15 +++ 60 files changed, 1177 insertions(+) create mode 100644 .gitignore create mode 100644 AppScope/app.json5 create mode 100644 AppScope/resources/base/element/string.json create mode 100644 AppScope/resources/base/media/app_icon.png create mode 100644 app/.gitignore create mode 100644 app/build-profile.json5 create mode 100644 app/hvigorfile.ts create mode 100644 app/obfuscation-rules.txt create mode 100644 app/oh-package.json5 create mode 100644 app/src/main/ets/appability/AppAbility.ets create mode 100644 app/src/main/ets/bean/ConvertItem.ets create mode 100644 app/src/main/ets/component/ComponentConst.ts create mode 100644 app/src/main/ets/component/TitleBar.ets create mode 100644 app/src/main/ets/pages/Index.ets create mode 100644 app/src/main/ets/pages/calculate/CalculatePage.ets create mode 100644 app/src/main/ets/pages/convert/ConvertPage.ets create mode 100644 app/src/main/ets/pages/convert/LengthPage.ets create mode 100644 app/src/main/ets/theme/CalThemeManager.ets create mode 100644 app/src/main/ets/utils/Res.ets create mode 100644 app/src/main/ets/utils/RoutePath.ets create mode 100644 app/src/main/ets/utils/ScreenUtil.ets create mode 100644 app/src/main/module.json5 create mode 100644 app/src/main/resources/base/element/color.json create mode 100644 app/src/main/resources/base/element/string.json create mode 100644 app/src/main/resources/base/media/ic_area.svg create mode 100644 app/src/main/resources/base/media/ic_bmi.svg create mode 100644 app/src/main/resources/base/media/ic_calculator_variant.svg create mode 100644 app/src/main/resources/base/media/ic_chevron_left.svg create mode 100644 app/src/main/resources/base/media/ic_close.svg create mode 100644 app/src/main/resources/base/media/ic_length.svg create mode 100644 app/src/main/resources/base/media/ic_number.svg create mode 100644 app/src/main/resources/base/media/ic_refresh.svg create mode 100644 app/src/main/resources/base/media/ic_speed.svg create mode 100644 app/src/main/resources/base/media/ic_thermometer.svg create mode 100644 app/src/main/resources/base/media/ic_time.svg create mode 100644 app/src/main/resources/base/media/ic_weight.svg create mode 100644 app/src/main/resources/base/media/icon.png create mode 100644 app/src/main/resources/base/media/startIcon.png create mode 100644 app/src/main/resources/base/profile/main_pages.json create mode 100644 app/src/main/resources/en_US/element/string.json create mode 100644 app/src/main/resources/zh_CN/element/string.json create mode 100644 app/src/mock/mock-config.json5 create mode 100644 app/src/ohosTest/ets/test/Ability.test.ets create mode 100644 app/src/ohosTest/ets/test/List.test.ets create mode 100644 app/src/ohosTest/ets/testability/TestAbility.ets create mode 100644 app/src/ohosTest/ets/testability/pages/Index.ets create mode 100644 app/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets create mode 100644 app/src/ohosTest/module.json5 create mode 100644 app/src/ohosTest/resources/base/element/color.json create mode 100644 app/src/ohosTest/resources/base/element/string.json create mode 100644 app/src/ohosTest/resources/base/media/icon.png create mode 100644 app/src/ohosTest/resources/base/profile/test_pages.json create mode 100644 app/src/test/List.test.ets create mode 100644 app/src/test/LocalUnit.test.ets create mode 100644 build-profile.json5 create mode 100644 hvigor/hvigor-config.json5 create mode 100644 hvigorfile.ts create mode 100644 img.png create mode 100644 oh-package.json5 create mode 100644 readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12598ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +oh-package-lock.json5 +/oh-package-lock.json5 +/pack/sign diff --git a/AppScope/app.json5 b/AppScope/app.json5 new file mode 100644 index 0000000..e26ceaf --- /dev/null +++ b/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "net.devwiki.calculator", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/AppScope/resources/base/element/string.json b/AppScope/resources/base/element/string.json new file mode 100644 index 0000000..d42b85f --- /dev/null +++ b/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "Calculator" + } + ] +} diff --git a/AppScope/resources/base/media/app_icon.png b/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cd45accb1dfd2fd0da16c732c72faa6e46b26521 GIT binary patch literal 2041 zcmaJ?c~nzZ9u6@;0AXaYAVN(;Kr(@>EJ+}skOWf=BA~*l4us@ELY9{%0m5QX6pnb} z(jZF|S&pLAS}3BZAfeQSvJ_h>F2Q1PYqi?o5`;m_yjZdG$1v}l_wK#F^L^iMz2}uD z#K$>1dON~kFlWvhW+Jp=tuN9J`ZlM-rl4h+ij|^D0y9;4JOuz-EdVnB6i3R-0ulk9 zApi4zAQA>!N9@-o026$1@L`d124`3G5<@_m`0f)Ug_Ie~;HT2q<_a=HH> zDwTdfD^-cW-|_xWVP$f@93UhDN-#&khZ>jZXLTi~$0`7x3REP6pk%&^2|`c>DutjN zMJD4Zs6Z}{FOpd;*mo2zm(GzXRXiCV;4m3zNCYnu3Fy=i5;2An&Lp!#LP;bRD~1&s z%VH6UY+}r6YDgG+p34OJIZ{BTn&%4s=CT&#TBkuOhdeU@g(w#guoa*b^)73=XyI65 z7Swys6)YS}?1EeZ6b!-I+yCnIya^g0>-NLsLWd8t56GZ_S3r|ZGbR+mV2ErEb9J)X zIF!njY-D-7{qtF2(?nlQ$0}!pzt=}hc*m%%)0Jb#N_K4@IC-`Pi5DahPZN7N9rH;ol;Gc*>-Go@gXKTM{eP)iJj6CYTIi}B#zLKZYD@_;m zrXmXXsFq@~ou-z!9bHoM8*(hwl>X(zm)TDcdkF4lZm$1jP*HbnD`o1$g}_R#+bu2D zr%7Y8KdsaC-V*aem5#@*M%r^GPgu%P2e-BnBClhP2yoGFe40>);=}>{NONtkXQ01p z)OX^t2Ojhddot9eg0WTIVSTNBa}7V-^_pO595w|Hx9q?k4dMp@$G7PK*TD=y;ck6J zdGRB!_RAI2nR3%tO1IkdWp*bw*?<=pM_LZb30?!oK)s;En( z!#nnd9=cXJ<}+e{XLdx(q3&ikJISe?eSHHohk+pz+$6Cv{ytvc{QXmMn2XQ9U8rvt zrJdAn(0gpSD@N=yTrI_2^P#*zQg7MTp1)k(lv(*(KtUR6@M|2WB>2wRwC-h=wk6XF zPtSes*_JwI+^d>xW489MJw5R6=t5?{R zc|E8i?RL@p9)A3ZJAQOg`}+F;<_vnWA!KxR#g%jZ@y_1Qu#Uw)kFPw_xmZ?a^e*1{ zM|ImtqA|(CaDQ@Fyvcof`MN66&VI6m6gAyAXx`%cDx6BI{Bj#}V*Rn1(b~;Am)D2u zX7(027IO?Z2VYK^1vXXpoZ@AtH~N?0rYWwtyA15`6vEf6fk&;o-L;7zFt`5nk*iOy z`<918zB+k;EytI$FAXug)jk*e@e};4e9g__w4A5ev!!)H$yC@{?vsRqJ##X1R%xPG z&_R3oDi$MtTkVqfPj)HEUDx_7wd!y{8#1%$U*Dd0sK@=#6+!XlsE-s^1f5E`R9Wo71^b~mbVdU;Fw0LG~mUQg;xsX4QYRo3B@rH_=ry>DE8ef!c2ta8UcI#26# zF|`*4wtMHe@%#eGZw`#Yj|QWuB`eRD)b~)r9mM95p_JVG%-IdcbIX5qG#GpGD+IrS zEqxb1Rg&Dadk5#7t4j68I1f!@A$efp1?I%&d*56)yl!tkz!14<$0Od_&6cGw$WW0r zjSlQA7l*6;vgfhv!cR|RmAD$+w6j`rVf=-?-D@q>kOseUVSb*~jbAS^*1h?ZL)n(9 zDa}`4etXO6`}9;{k5E^N{rcfnV_(LPwsDg``wtyS*V<19c3!PGJ3Kqy9ksvkwbJ%Z z*N(fT0{e*Wji-Ck5!3YE0j|PZ@&z`v=kitWL$bqSt!e4bH!+(|Q)CZ30^nVPfkx{s zX{6of`p=BiPb@u@IyL!tRk>?qgBqCmo-Zlt!636g?z`s~zdfwuB7DXZHvV`Usp+%Z zo*&;Biu@MHE&2j+?j^o`Cr12u<>vOe=a&8a2hlcmFjJiDR>XnD4c4DAhZWCkiAgW{ E51q9-lK=n! literal 0 HcmV?d00001 diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..9f5b6e7 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,7 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test +oh-package-lock.json5 \ No newline at end of file diff --git a/app/build-profile.json5 b/app/build-profile.json5 new file mode 100644 index 0000000..b695582 --- /dev/null +++ b/app/build-profile.json5 @@ -0,0 +1,28 @@ +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": true, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/app/hvigorfile.ts b/app/hvigorfile.ts new file mode 100644 index 0000000..c6edcd9 --- /dev/null +++ b/app/hvigorfile.ts @@ -0,0 +1,6 @@ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/app/obfuscation-rules.txt b/app/obfuscation-rules.txt new file mode 100644 index 0000000..985b2ae --- /dev/null +++ b/app/obfuscation-rules.txt @@ -0,0 +1,18 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope \ No newline at end of file diff --git a/app/oh-package.json5 b/app/oh-package.json5 new file mode 100644 index 0000000..e3d224d --- /dev/null +++ b/app/oh-package.json5 @@ -0,0 +1,11 @@ +{ + "name": "app", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + } +} + diff --git a/app/src/main/ets/appability/AppAbility.ets b/app/src/main/ets/appability/AppAbility.ets new file mode 100644 index 0000000..af10f3a --- /dev/null +++ b/app/src/main/ets/appability/AppAbility.ets @@ -0,0 +1,41 @@ +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +export default class AppAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (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) ?? ''); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} diff --git a/app/src/main/ets/bean/ConvertItem.ets b/app/src/main/ets/bean/ConvertItem.ets new file mode 100644 index 0000000..9f53b4a --- /dev/null +++ b/app/src/main/ets/bean/ConvertItem.ets @@ -0,0 +1,6 @@ + +export class ConvertItem { + icon: Resource = $r('app.media.app_icon'); + name: ResourceStr = ''; + page: string = ''; +} \ No newline at end of file diff --git a/app/src/main/ets/component/ComponentConst.ts b/app/src/main/ets/component/ComponentConst.ts new file mode 100644 index 0000000..dc019c6 --- /dev/null +++ b/app/src/main/ets/component/ComponentConst.ts @@ -0,0 +1,4 @@ +export class ComponentConst { + + static readonly ContainerId: string = "__container__" +} \ No newline at end of file diff --git a/app/src/main/ets/component/TitleBar.ets b/app/src/main/ets/component/TitleBar.ets new file mode 100644 index 0000000..86e747e --- /dev/null +++ b/app/src/main/ets/component/TitleBar.ets @@ -0,0 +1,123 @@ +import { ComponentConst } from './ComponentConst'; + +export enum TitleBarMenuType{ + /** + * 不显示 + */ + None = 0, + /** + * 显示Icon + */ + Icon = 1, + /** + * 显示文本 + */ + Text = 2 +} + +@Preview +@Component +export struct TitleBar { + + @Prop title: ResourceStr; + + @Prop barHeight: number = 48; + @Prop menuPadding: number = 8; + + @Prop leftText: ResourceStr = ""; + @Prop leftIcon: Resource = $r("app.media.ic_chevron_left"); + @Prop leftMenuType: TitleBarMenuType = TitleBarMenuType.Icon; + + @Prop rightText: ResourceStr = ""; + @Prop rightIcon: Resource = $r("app.media.ic_close"); + @Prop rightMenuType: TitleBarMenuType = TitleBarMenuType.None; + + @Prop titleTextAlign: TextAlign = TextAlign.Start; + @Prop titleVisible: Visibility = Visibility.Visible; + + onLeftClicked?: Function; + onRightClicked?: Function; + + @Styles setWidthAndHeight() { + .height(this.barHeight).width(this.barHeight) + } + + build() { + Row() { + RelativeContainer() { + if (this.leftMenuType != TitleBarMenuType.None) { + Button() { + if (this.leftMenuType == TitleBarMenuType.Icon) { + Image(this.leftIcon) + .setWidthAndHeight() + .padding(this.menuPadding) + } else { + Text(this.leftText) + .textAlign(TextAlign.Center) + .setWidthAndHeight() + } + } + .setWidthAndHeight() + .backgroundColor(0xFFFFFF) + .type(ButtonType.Normal) + .stateEffect(true) + .onClick((event) => { + this.onLeftClicked?.(event); + }) + .alignRules({ + top: { anchor: ComponentConst.ContainerId, align: VerticalAlign.Top }, + left: { anchor: ComponentConst.ContainerId, align: HorizontalAlign.Start }, + }).id("left_menu") + } + + if (this.titleVisible == Visibility.Visible) { + Text(this.title) + .textAlign(this.titleTextAlign) + .backgroundColor(0xFFFFFF) + .padding({ + left: this.leftMenuType != TitleBarMenuType.None ? 0 : this.menuPadding, + right: this.rightMenuType != TitleBarMenuType.None ? 0 : this.menuPadding + }) + .alignRules({ + top: { anchor: ComponentConst.ContainerId, align: VerticalAlign.Top }, + left: { + anchor: this.leftMenuType != TitleBarMenuType.None ? "left_menu" : ComponentConst.ContainerId, + align: this.leftMenuType != TitleBarMenuType.None ? HorizontalAlign.End : HorizontalAlign.Start + }, + right: { + anchor: this.rightMenuType != TitleBarMenuType.None ? "right_menu" : ComponentConst.ContainerId, + align: this.rightMenuType != TitleBarMenuType.None ? HorizontalAlign.Start : HorizontalAlign.End + }, + bottom: { anchor: ComponentConst.ContainerId, align: VerticalAlign.Bottom } + }) + .id("title") + } + + if (this.rightMenuType != TitleBarMenuType.None) { + Button() { + if (this.rightMenuType == TitleBarMenuType.Icon) { + Image(this.rightIcon) + .setWidthAndHeight().padding(this.menuPadding) + } else { + Text(this.rightText) + .textAlign(TextAlign.Center) + .setWidthAndHeight() + } + } + .setWidthAndHeight() + .backgroundColor(0xFFFFFF) + .type(ButtonType.Normal) + .stateEffect(true) + .onClick((event) => { + this.onRightClicked?.(event); + }) + .alignRules({ + top: { anchor: ComponentConst.ContainerId, align: VerticalAlign.Top }, + right: { anchor: ComponentConst.ContainerId, align: HorizontalAlign.End }, + }).id("right_menu") + } + } + .width('100%').height('100%') + }.height(this.barHeight) + } +} \ No newline at end of file diff --git a/app/src/main/ets/pages/Index.ets b/app/src/main/ets/pages/Index.ets new file mode 100644 index 0000000..bf9235e --- /dev/null +++ b/app/src/main/ets/pages/Index.ets @@ -0,0 +1,40 @@ +import { CalculateView } from './calculate/CalculatePage'; +import { ConvertView, ConvertViewModel } from './convert/ConvertPage'; + +@Entry +@Component +struct Index { + @State message: string = 'Hello World'; + + @Provide convertViewModel: ConvertViewModel = new ConvertViewModel(); + + aboutToAppear(): void { + this.convertViewModel.requestRefreshHome = () =>{ + // 这里处理 Home的 逻辑调用 + } + } + + onPageShow(): void { + this.convertViewModel.onPageShow(); + } + + build() { + + Column() { + Stack({ alignContent: Alignment.TopEnd}) { + Tabs({ barPosition: BarPosition.Start}) { + TabContent() { + CalculateView(); + } + .tabBar($r("app.string.calculate")) + + TabContent() { + ConvertView(); + } + .tabBar($r("app.string.convert")) + } + } + } + .height('100%').width('100%') + } +} \ No newline at end of file diff --git a/app/src/main/ets/pages/calculate/CalculatePage.ets b/app/src/main/ets/pages/calculate/CalculatePage.ets new file mode 100644 index 0000000..15f31ad --- /dev/null +++ b/app/src/main/ets/pages/calculate/CalculatePage.ets @@ -0,0 +1,9 @@ + +@Preview +@Component +export struct CalculateView { + + build() { + Text("CalculatePage"); + } +} \ No newline at end of file diff --git a/app/src/main/ets/pages/convert/ConvertPage.ets b/app/src/main/ets/pages/convert/ConvertPage.ets new file mode 100644 index 0000000..1accabf --- /dev/null +++ b/app/src/main/ets/pages/convert/ConvertPage.ets @@ -0,0 +1,71 @@ +import { ConvertItem } from '../../bean/ConvertItem' +import { Res } from '../../utils/Res'; +import { RoutePath } from '../../utils/RoutePath'; + +export class ConvertViewModel { + + requestRefreshHome?: ()=> void; + + convertItems: ConvertItem[] = [ + { icon: Res.getImage('ic_length'), name: Res.getString('length_convert'), page: RoutePath.LengthPage }, + { icon: Res.getImage('ic_weight'), name: Res.getString('weight_convert'), page: RoutePath.WeightPage }, + { icon: Res.getImage('ic_area'), name: Res.getString('area_convert'), page: RoutePath.AreaPage }, + { icon: Res.getImage('ic_number'), name: Res.getString('number_convert'), page: RoutePath.AreaPage }, + { icon: Res.getImage('ic_speed'), name: Res.getString('speed_convert'), page: RoutePath.AreaPage }, + { icon: Res.getImage('ic_bmi'), name: Res.getString('bmi_calculate'), page: RoutePath.AreaPage }, + { icon: Res.getImage('ic_time'), name: Res.getString('time_convert'), page: RoutePath.TimePage }, + ]; + + refresh() { + + } + + onPageShow() { + + } +} + +@Preview +@Component +export struct ConvertView { + @Consume convertViewModel: ConvertViewModel; + scroller: Scroller = new Scroller(); + + build() { + Column() { + Grid(this.scroller) { + ForEach(this.convertViewModel.convertItems, (item: ConvertItem, index) => { + GridItem() { + ConvertItemView({ item: item }) + } + .rowStart(index / 3) + .columnStart(index % 3) + }) + }.columnsTemplate('1fr 1fr 1fr') + .width('100%').rowsGap(20).columnsGap(20) + }.width('100%').height('100%').padding(8) + } +} + +@Component +struct ConvertItemView { + @Prop item: ConvertItem + + build() { + Button() { + Column() { + Image(this.item.icon).width(32).height(32).objectFit(ImageFit.Contain) + + Text(this.item.name).margin({ top: 8 }) + } + .width(100) + .height(100) + .borderWidth(1) + .borderColor('#eeeeee') + .justifyContent(FlexAlign.Center) + }.type(ButtonType.Normal).backgroundColor(Color.Transparent) + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ url: this.item.page }) + }) + } +} \ No newline at end of file diff --git a/app/src/main/ets/pages/convert/LengthPage.ets b/app/src/main/ets/pages/convert/LengthPage.ets new file mode 100644 index 0000000..60ed84c --- /dev/null +++ b/app/src/main/ets/pages/convert/LengthPage.ets @@ -0,0 +1,13 @@ +import { TitleBar } from '../../component/TitleBar' +import { Res } from '../../utils/Res'; + +@Entry +@Component +export struct LengthPage { + + build() { + Column(){ + TitleBar({title: Res.getString('length_convert')}); + }.height('100%').width('100%') + } +} \ No newline at end of file diff --git a/app/src/main/ets/theme/CalThemeManager.ets b/app/src/main/ets/theme/CalThemeManager.ets new file mode 100644 index 0000000..c41862e --- /dev/null +++ b/app/src/main/ets/theme/CalThemeManager.ets @@ -0,0 +1,8 @@ + +export class CalThemeManager { + +} + +export class CalTheme { + +} \ No newline at end of file diff --git a/app/src/main/ets/utils/Res.ets b/app/src/main/ets/utils/Res.ets new file mode 100644 index 0000000..661cbab --- /dev/null +++ b/app/src/main/ets/utils/Res.ets @@ -0,0 +1,13 @@ + +export class Res { + private constructor() { + } + + static getString(name: string): Resource { + return $r(`app.string.${name}`) + } + + static getImage(name: string): Resource { + return $r(`app.media.${name}`) + } +} \ No newline at end of file diff --git a/app/src/main/ets/utils/RoutePath.ets b/app/src/main/ets/utils/RoutePath.ets new file mode 100644 index 0000000..6b98904 --- /dev/null +++ b/app/src/main/ets/utils/RoutePath.ets @@ -0,0 +1,13 @@ + +export class RoutePath { + private constructor() { + } + + static readonly AreaPage = 'pages/convert/LengthPage'; + static readonly BMIPage = 'pages/convert/LengthPage'; + static readonly LengthPage = 'pages/convert/LengthPage'; + static readonly NumberPage = 'pages/convert/LengthPage'; + static readonly SpeedPage = 'pages/convert/LengthPage'; + static readonly TimePage = 'pages/convert/LengthPage'; + static readonly WeightPage = 'pages/convert/LengthPage'; +} \ No newline at end of file diff --git a/app/src/main/ets/utils/ScreenUtil.ets b/app/src/main/ets/utils/ScreenUtil.ets new file mode 100644 index 0000000..39f9cbb --- /dev/null +++ b/app/src/main/ets/utils/ScreenUtil.ets @@ -0,0 +1,106 @@ +import window from '@ohos.window'; +import mediaquery from '@ohos.mediaquery'; + +export class ScreenUtil { + // TODO: 工具待抽离, key统一定义 + static readonly isPortraitKey: string = "xy_screen_is_portrait"; + private static instance: ScreenUtil; + public width: number = 0 + public height: number = 0 + public statusBarHeight: number = 0 + public bottomSafeHeight: number = 0 + public contentHeight: number = 0; + + public layoutWidth: number = 0 + public layoutHeight: number = 0 + + + private portraitListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(orientation: portrait)'); + + public static getInstance(): ScreenUtil { + if (!ScreenUtil.instance) { + ScreenUtil.instance = new ScreenUtil(); + } + return ScreenUtil.instance; + } + + initScreenSize(): void { + this.portraitListener.on('change', (result)=> { + AppStorage.setOrCreate(ScreenUtil.isPortraitKey, result.matches) + }) + window.getLastWindow(getContext(this)) + .then((windowClass: window.Window) => { + let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; // 以导航条避让为例 + let avoidArea = windowClass.getWindowAvoidArea(type); + this.bottomSafeHeight = px2vp(avoidArea.bottomRect.height); // 获取到导航条区域的高度 + type = window.AvoidAreaType.TYPE_SYSTEM; + avoidArea = windowClass.getWindowAvoidArea(type); + this.statusBarHeight = px2vp(avoidArea.topRect.height); + this.width = px2vp(windowClass.getWindowProperties().windowRect.width); + this.height = px2vp(windowClass.getWindowProperties().windowRect.height); + this.layoutWidth = this.width; + this.layoutHeight = this.height - this.statusBarHeight - this.bottomSafeHeight; + }) + .catch((error: Error) => { + }) + } + + setPreferredOrientation(orientation: window.Orientation): void { + window.getLastWindow(getContext(this)) + .then((windowClass: window.Window) => { + windowClass.setPreferredOrientation(orientation); + }) + .catch((error: Error) => { + }) + } + + setPreferredOrientationCallBack(orientation: window.Orientation, callback: ()=>void): void{ + window.getLastWindow(getContext(this)) + .then((windowClass: window.Window) => { + windowClass.setPreferredOrientation(orientation,callback); + AppStorage.setOrCreate(ScreenUtil.isPortraitKey, orientation == window.Orientation.PORTRAIT || orientation == window.Orientation.PORTRAIT_INVERTED); + }) + .catch((error: Error) => { + }) + } + + setWindowLayoutFullScreen(isLayoutFullScreen: boolean): void { + window.getLastWindow(getContext(this)) + .then((windowClass: window.Window) => { + windowClass.setWindowLayoutFullScreen(isLayoutFullScreen); + windowClass.setSpecificSystemBarEnabled('status', !isLayoutFullScreen); + }) + .catch((error: Error) => { + }) + } + + setWindowSystemBarProperties(systemBarProperties: window.SystemBarProperties): void { + window.getLastWindow(getContext(this)) + .then((windowClass: window.Window) => { + windowClass.setWindowSystemBarProperties(systemBarProperties, (err) => { + if (err.code) { + console.error('Failed to set the system bar properties. Cause: ' + JSON.stringify(err)); + return; + } + console.info('Succeeded in setting the system bar properties.'); + }); + }) + .catch((error: Error) => { + }) + } + + setWindowSystemBarEnable(names:Array<'status' | 'navigation'>){ + window.getLastWindow(getContext(this)) + .then((windowClass: window.Window) => { + windowClass.setWindowSystemBarEnable(names, (err) => { + if (err.code) { + console.error('Failed to set the system bar properties. Cause: ' + JSON.stringify(err)); + return; + } + console.info('Succeeded in setting the system bar properties.'); + }); + }) + .catch((error: Error) => { + }) + } +} \ No newline at end of file diff --git a/app/src/main/module.json5 b/app/src/main/module.json5 new file mode 100644 index 0000000..a955c80 --- /dev/null +++ b/app/src/main/module.json5 @@ -0,0 +1,38 @@ +{ + "module": { + "name": "app", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "AppAbility", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "AppAbility", + "srcEntry": "./ets/appability/AppAbility.ets", + "description": "$string:AppAbility_desc", + "icon": "$media:ic_calculator_variant", + "label": "$string:AppAbility_label", + "startWindowIcon": "$media:ic_calculator_variant", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/app/src/main/resources/base/element/color.json b/app/src/main/resources/base/element/color.json new file mode 100644 index 0000000..3c71296 --- /dev/null +++ b/app/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/app/src/main/resources/base/element/string.json b/app/src/main/resources/base/element/string.json new file mode 100644 index 0000000..3087e8c --- /dev/null +++ b/app/src/main/resources/base/element/string.json @@ -0,0 +1,52 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "AppAbility_desc", + "value": "description" + }, + { + "name": "AppAbility_label", + "value": "Calculator" + }, + { + "name": "calculate", + "value": "Calculate" + }, + { + "name": "convert", + "value": "Convert" + }, + { + "name": "length_convert", + "value": "Length" + }, + { + "name": "area_convert", + "value": "Area" + }, + { + "name": "weight_convert", + "value": "Weight" + }, + { + "name": "time_convert", + "value": "Time" + }, + { + "name": "number_convert", + "value": "Number" + }, + { + "name": "bmi_calculate", + "value": "BMI" + }, + { + "name": "speed_convert", + "value": "Speed" + } + ] +} \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_area.svg b/app/src/main/resources/base/media/ic_area.svg new file mode 100644 index 0000000..2367d09 --- /dev/null +++ b/app/src/main/resources/base/media/ic_area.svg @@ -0,0 +1 @@ +texture-box \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_bmi.svg b/app/src/main/resources/base/media/ic_bmi.svg new file mode 100644 index 0000000..14f4d34 --- /dev/null +++ b/app/src/main/resources/base/media/ic_bmi.svg @@ -0,0 +1 @@ +scale \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_calculator_variant.svg b/app/src/main/resources/base/media/ic_calculator_variant.svg new file mode 100644 index 0000000..0a37a93 --- /dev/null +++ b/app/src/main/resources/base/media/ic_calculator_variant.svg @@ -0,0 +1 @@ +calculator-variant \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_chevron_left.svg b/app/src/main/resources/base/media/ic_chevron_left.svg new file mode 100644 index 0000000..eb37c0b --- /dev/null +++ b/app/src/main/resources/base/media/ic_chevron_left.svg @@ -0,0 +1 @@ +chevron-left \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_close.svg b/app/src/main/resources/base/media/ic_close.svg new file mode 100644 index 0000000..c147635 --- /dev/null +++ b/app/src/main/resources/base/media/ic_close.svg @@ -0,0 +1 @@ +close \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_length.svg b/app/src/main/resources/base/media/ic_length.svg new file mode 100644 index 0000000..2e0c50b --- /dev/null +++ b/app/src/main/resources/base/media/ic_length.svg @@ -0,0 +1 @@ +ruler \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_number.svg b/app/src/main/resources/base/media/ic_number.svg new file mode 100644 index 0000000..3138592 --- /dev/null +++ b/app/src/main/resources/base/media/ic_number.svg @@ -0,0 +1 @@ +counter \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_refresh.svg b/app/src/main/resources/base/media/ic_refresh.svg new file mode 100644 index 0000000..5e1cb0a --- /dev/null +++ b/app/src/main/resources/base/media/ic_refresh.svg @@ -0,0 +1 @@ +refresh \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_speed.svg b/app/src/main/resources/base/media/ic_speed.svg new file mode 100644 index 0000000..a264639 --- /dev/null +++ b/app/src/main/resources/base/media/ic_speed.svg @@ -0,0 +1 @@ +speedometer \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_thermometer.svg b/app/src/main/resources/base/media/ic_thermometer.svg new file mode 100644 index 0000000..9859cbd --- /dev/null +++ b/app/src/main/resources/base/media/ic_thermometer.svg @@ -0,0 +1 @@ +thermometer \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_time.svg b/app/src/main/resources/base/media/ic_time.svg new file mode 100644 index 0000000..a851f1b --- /dev/null +++ b/app/src/main/resources/base/media/ic_time.svg @@ -0,0 +1 @@ +clock-time-three \ No newline at end of file diff --git a/app/src/main/resources/base/media/ic_weight.svg b/app/src/main/resources/base/media/ic_weight.svg new file mode 100644 index 0000000..8e92dc5 --- /dev/null +++ b/app/src/main/resources/base/media/ic_weight.svg @@ -0,0 +1 @@ +weight \ No newline at end of file diff --git a/app/src/main/resources/base/media/icon.png b/app/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cd45accb1dfd2fd0da16c732c72faa6e46b26521 GIT binary patch literal 2041 zcmaJ?c~nzZ9u6@;0AXaYAVN(;Kr(@>EJ+}skOWf=BA~*l4us@ELY9{%0m5QX6pnb} z(jZF|S&pLAS}3BZAfeQSvJ_h>F2Q1PYqi?o5`;m_yjZdG$1v}l_wK#F^L^iMz2}uD z#K$>1dON~kFlWvhW+Jp=tuN9J`ZlM-rl4h+ij|^D0y9;4JOuz-EdVnB6i3R-0ulk9 zApi4zAQA>!N9@-o026$1@L`d124`3G5<@_m`0f)Ug_Ie~;HT2q<_a=HH> zDwTdfD^-cW-|_xWVP$f@93UhDN-#&khZ>jZXLTi~$0`7x3REP6pk%&^2|`c>DutjN zMJD4Zs6Z}{FOpd;*mo2zm(GzXRXiCV;4m3zNCYnu3Fy=i5;2An&Lp!#LP;bRD~1&s z%VH6UY+}r6YDgG+p34OJIZ{BTn&%4s=CT&#TBkuOhdeU@g(w#guoa*b^)73=XyI65 z7Swys6)YS}?1EeZ6b!-I+yCnIya^g0>-NLsLWd8t56GZ_S3r|ZGbR+mV2ErEb9J)X zIF!njY-D-7{qtF2(?nlQ$0}!pzt=}hc*m%%)0Jb#N_K4@IC-`Pi5DahPZN7N9rH;ol;Gc*>-Go@gXKTM{eP)iJj6CYTIi}B#zLKZYD@_;m zrXmXXsFq@~ou-z!9bHoM8*(hwl>X(zm)TDcdkF4lZm$1jP*HbnD`o1$g}_R#+bu2D zr%7Y8KdsaC-V*aem5#@*M%r^GPgu%P2e-BnBClhP2yoGFe40>);=}>{NONtkXQ01p z)OX^t2Ojhddot9eg0WTIVSTNBa}7V-^_pO595w|Hx9q?k4dMp@$G7PK*TD=y;ck6J zdGRB!_RAI2nR3%tO1IkdWp*bw*?<=pM_LZb30?!oK)s;En( z!#nnd9=cXJ<}+e{XLdx(q3&ikJISe?eSHHohk+pz+$6Cv{ytvc{QXmMn2XQ9U8rvt zrJdAn(0gpSD@N=yTrI_2^P#*zQg7MTp1)k(lv(*(KtUR6@M|2WB>2wRwC-h=wk6XF zPtSes*_JwI+^d>xW489MJw5R6=t5?{R zc|E8i?RL@p9)A3ZJAQOg`}+F;<_vnWA!KxR#g%jZ@y_1Qu#Uw)kFPw_xmZ?a^e*1{ zM|ImtqA|(CaDQ@Fyvcof`MN66&VI6m6gAyAXx`%cDx6BI{Bj#}V*Rn1(b~;Am)D2u zX7(027IO?Z2VYK^1vXXpoZ@AtH~N?0rYWwtyA15`6vEf6fk&;o-L;7zFt`5nk*iOy z`<918zB+k;EytI$FAXug)jk*e@e};4e9g__w4A5ev!!)H$yC@{?vsRqJ##X1R%xPG z&_R3oDi$MtTkVqfPj)HEUDx_7wd!y{8#1%$U*Dd0sK@=#6+!XlsE-s^1f5E`R9Wo71^b~mbVdU;Fw0LG~mUQg;xsX4QYRo3B@rH_=ry>DE8ef!c2ta8UcI#26# zF|`*4wtMHe@%#eGZw`#Yj|QWuB`eRD)b~)r9mM95p_JVG%-IdcbIX5qG#GpGD+IrS zEqxb1Rg&Dadk5#7t4j68I1f!@A$efp1?I%&d*56)yl!tkz!14<$0Od_&6cGw$WW0r zjSlQA7l*6;vgfhv!cR|RmAD$+w6j`rVf=-?-D@q>kOseUVSb*~jbAS^*1h?ZL)n(9 zDa}`4etXO6`}9;{k5E^N{rcfnV_(LPwsDg``wtyS*V<19c3!PGJ3Kqy9ksvkwbJ%Z z*N(fT0{e*Wji-Ck5!3YE0j|PZ@&z`v=kitWL$bqSt!e4bH!+(|Q)CZ30^nVPfkx{s zX{6of`p=BiPb@u@IyL!tRk>?qgBqCmo-Zlt!636g?z`s~zdfwuB7DXZHvV`Usp+%Z zo*&;Biu@MHE&2j+?j^o`Cr12u<>vOe=a&8a2hlcmFjJiDR>XnD4c4DAhZWCkiAgW{ E51q9-lK=n! literal 0 HcmV?d00001 diff --git a/app/src/main/resources/base/media/startIcon.png b/app/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..366f76459ffd4494ec40d0ddd5c59385b9c5da11 GIT binary patch literal 4351 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 literal 0 HcmV?d00001 diff --git a/app/src/main/resources/base/profile/main_pages.json b/app/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000..16a5a7a --- /dev/null +++ b/app/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,6 @@ +{ + "src": [ + "pages/Index", + "pages/convert/LengthPage" + ] +} diff --git a/app/src/main/resources/en_US/element/string.json b/app/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000..2ae9b1e --- /dev/null +++ b/app/src/main/resources/en_US/element/string.json @@ -0,0 +1,52 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "AppAbility_desc", + "value": "description" + }, + { + "name": "AppAbility_label", + "value": "Calculator" + }, + { + "name": "calculate", + "value": "Calculate" + }, + { + "name": "convert", + "value": "Convert" + }, + { + "name": "length_convert", + "value": "Length" + }, + { + "name": "area_convert", + "value": "Area" + }, + { + "name": "weight_convert", + "value": "Weight" + }, + { + "name": "time_convert", + "value": "Time" + }, + { + "name": "speed_convert", + "value": "Speed" + }, + { + "name": "number_convert", + "value": "Number" + }, + { + "name": "bmi_calculate", + "value": "BMI" + } + ] +} \ No newline at end of file diff --git a/app/src/main/resources/zh_CN/element/string.json b/app/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000..8bccdcc --- /dev/null +++ b/app/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,52 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "AppAbility_desc", + "value": "description" + }, + { + "name": "AppAbility_label", + "value": "计算器" + }, + { + "name": "calculate", + "value": "计算" + }, + { + "name": "convert", + "value": "换算" + }, + { + "name": "length_convert", + "value": "长度转换" + }, + { + "name": "area_convert", + "value": "面积转换" + }, + { + "name": "weight_convert", + "value": "重量转换" + }, + { + "name": "time_convert", + "value": "时间转换" + }, + { + "name": "speed_convert", + "value": "速度转换" + }, + { + "name": "number_convert", + "value": "进制转换" + }, + { + "name": "bmi_calculate", + "value": "BMI计算" + } + ] +} \ No newline at end of file diff --git a/app/src/mock/mock-config.json5 b/app/src/mock/mock-config.json5 new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/app/src/mock/mock-config.json5 @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/app/src/ohosTest/ets/test/Ability.test.ets b/app/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000..85c78f6 --- /dev/null +++ b/app/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,35 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function abilityTest() { + describe('ActsAbilityTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }) + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }) + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }) + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }) + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }) + }) +} \ No newline at end of file diff --git a/app/src/ohosTest/ets/test/List.test.ets b/app/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000..794c7dc --- /dev/null +++ b/app/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/app/src/ohosTest/ets/testability/TestAbility.ets b/app/src/ohosTest/ets/testability/TestAbility.ets new file mode 100644 index 0000000..3682558 --- /dev/null +++ b/app/src/ohosTest/ets/testability/TestAbility.ets @@ -0,0 +1,48 @@ +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { abilityDelegatorRegistry } from '@kit.TestKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; +import { Hypium } from '@ohos/hypium'; +import testsuite from '../test/List.test'; + +export default class TestAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate'); + hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); + hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); + let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator; + abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); + let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs; + abilityDelegatorArguments = abilityDelegatorRegistry.getArguments(); + hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!'); + Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite); + } + + onDestroy() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage) { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate'); + windowStage.loadContent('testability/pages/Index', (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) ?? ''); + }); + } + + onWindowStageDestroy() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy'); + } + + onForeground() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground'); + } + + onBackground() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground'); + } +} \ No newline at end of file diff --git a/app/src/ohosTest/ets/testability/pages/Index.ets b/app/src/ohosTest/ets/testability/pages/Index.ets new file mode 100644 index 0000000..423b427 --- /dev/null +++ b/app/src/ohosTest/ets/testability/pages/Index.ets @@ -0,0 +1,17 @@ +@Entry +@Component +struct Index { + @State message: string = 'Hello World'; + + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .width('100%') + } + .height('100%') + } +} \ No newline at end of file diff --git a/app/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets b/app/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets new file mode 100644 index 0000000..0eb230c --- /dev/null +++ b/app/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets @@ -0,0 +1,90 @@ +import { abilityDelegatorRegistry, TestRunner } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { resourceManager } from '@kit.LocalizationKit'; +import { util } from '@kit.ArkTS'; + +let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator; +let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs; +let jsonPath: string = 'mock/mock-config.json'; +let tag: string = 'testTag'; + +async function onAbilityCreateCallback(data: UIAbility) { + hilog.info(0x0000, 'testTag', 'onAbilityCreateCallback, data: ${}', JSON.stringify(data)); +} + +async function addAbilityMonitorCallback(err: BusinessError) { + hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? ''); +} + +export default class OpenHarmonyTestRunner implements TestRunner { + constructor() { + } + + onPrepare() { + hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare'); + } + + async onRun() { + let tag = 'testTag'; + hilog.info(0x0000, tag, '%{public}s', 'OpenHarmonyTestRunner onRun run'); + abilityDelegatorArguments = abilityDelegatorRegistry.getArguments() + abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + let moduleName = abilityDelegatorArguments.parameters['-m']; + let context = abilityDelegator.getAppContext().getApplicationContext().createModuleContext(moduleName); + let mResourceManager = context.resourceManager; + await checkMock(abilityDelegator, mResourceManager); + const bundleName = abilityDelegatorArguments.bundleName; + const testAbilityName: string = 'TestAbility'; + let lMonitor: abilityDelegatorRegistry.AbilityMonitor = { + abilityName: testAbilityName, + onAbilityCreate: onAbilityCreateCallback, + moduleName: moduleName + }; + abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback) + const want: Want = { + bundleName: bundleName, + abilityName: testAbilityName, + moduleName: moduleName + }; + abilityDelegator.startAbility(want, (err: BusinessError, data: void) => { + hilog.info(0x0000, tag, 'startAbility : err : %{public}s', JSON.stringify(err) ?? ''); + hilog.info(0x0000, tag, 'startAbility : data : %{public}s', JSON.stringify(data) ?? ''); + }) + hilog.info(0x0000, tag, '%{public}s', 'OpenHarmonyTestRunner onRun end'); + } +} + +async function checkMock(abilityDelegator: abilityDelegatorRegistry.AbilityDelegator, resourceManager: resourceManager.ResourceManager) { + let rawFile: Uint8Array; + try { + rawFile = resourceManager.getRawFileContentSync(jsonPath); + hilog.info(0x0000, tag, 'MockList file exists'); + let mockStr: string = util.TextDecoder.create("utf-8", { ignoreBOM: true }).decodeWithStream(rawFile); + let mockMap: Record = getMockList(mockStr); + try { + abilityDelegator.setMockList(mockMap) + } catch (error) { + let code = (error as BusinessError).code; + let message = (error as BusinessError).message; + hilog.error(0x0000, tag, `abilityDelegator.setMockList failed, error code: ${code}, message: ${message}.`); + } + } catch (error) { + let code = (error as BusinessError).code; + let message = (error as BusinessError).message; + hilog.error(0x0000, tag, `ResourceManager:callback getRawFileContent failed, error code: ${code}, message: ${message}.`); + } +} + +function getMockList(jsonStr: string) { + let jsonObj: Record = JSON.parse(jsonStr); + let map: Map = new Map(Object.entries(jsonObj)); + let mockList: Record = {}; + map.forEach((value: object, key: string) => { + let realValue: string = value['source'].toString(); + mockList[key] = realValue; + }); + hilog.info(0x0000, tag, '%{public}s', 'mock-json value:' + JSON.stringify(mockList) ?? ''); + return mockList; +} \ No newline at end of file diff --git a/app/src/ohosTest/module.json5 b/app/src/ohosTest/module.json5 new file mode 100644 index 0000000..2bd86be --- /dev/null +++ b/app/src/ohosTest/module.json5 @@ -0,0 +1,38 @@ +{ + "module": { + "name": "app_test", + "type": "feature", + "description": "$string:module_test_desc", + "mainElement": "TestAbility", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:test_pages", + "abilities": [ + { + "name": "TestAbility", + "srcEntry": "./ets/testability/TestAbility.ets", + "description": "$string:TestAbility_desc", + "icon": "$media:icon", + "label": "$string:TestAbility_label", + "exported": true, + "startWindowIcon": "$media:icon", + "startWindowBackground": "$color:start_window_background", + "skills": [ + { + "actions": [ + "action.system.home" + ], + "entities": [ + "entity.system.home" + ] + } + ] + } + ] + } +} diff --git a/app/src/ohosTest/resources/base/element/color.json b/app/src/ohosTest/resources/base/element/color.json new file mode 100644 index 0000000..3c71296 --- /dev/null +++ b/app/src/ohosTest/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/app/src/ohosTest/resources/base/element/string.json b/app/src/ohosTest/resources/base/element/string.json new file mode 100644 index 0000000..65d8fa5 --- /dev/null +++ b/app/src/ohosTest/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_test_desc", + "value": "test ability description" + }, + { + "name": "TestAbility_desc", + "value": "the test ability" + }, + { + "name": "TestAbility_label", + "value": "test label" + } + ] +} \ No newline at end of file diff --git a/app/src/ohosTest/resources/base/media/icon.png b/app/src/ohosTest/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cd45accb1dfd2fd0da16c732c72faa6e46b26521 GIT binary patch literal 2041 zcmaJ?c~nzZ9u6@;0AXaYAVN(;Kr(@>EJ+}skOWf=BA~*l4us@ELY9{%0m5QX6pnb} z(jZF|S&pLAS}3BZAfeQSvJ_h>F2Q1PYqi?o5`;m_yjZdG$1v}l_wK#F^L^iMz2}uD z#K$>1dON~kFlWvhW+Jp=tuN9J`ZlM-rl4h+ij|^D0y9;4JOuz-EdVnB6i3R-0ulk9 zApi4zAQA>!N9@-o026$1@L`d124`3G5<@_m`0f)Ug_Ie~;HT2q<_a=HH> zDwTdfD^-cW-|_xWVP$f@93UhDN-#&khZ>jZXLTi~$0`7x3REP6pk%&^2|`c>DutjN zMJD4Zs6Z}{FOpd;*mo2zm(GzXRXiCV;4m3zNCYnu3Fy=i5;2An&Lp!#LP;bRD~1&s z%VH6UY+}r6YDgG+p34OJIZ{BTn&%4s=CT&#TBkuOhdeU@g(w#guoa*b^)73=XyI65 z7Swys6)YS}?1EeZ6b!-I+yCnIya^g0>-NLsLWd8t56GZ_S3r|ZGbR+mV2ErEb9J)X zIF!njY-D-7{qtF2(?nlQ$0}!pzt=}hc*m%%)0Jb#N_K4@IC-`Pi5DahPZN7N9rH;ol;Gc*>-Go@gXKTM{eP)iJj6CYTIi}B#zLKZYD@_;m zrXmXXsFq@~ou-z!9bHoM8*(hwl>X(zm)TDcdkF4lZm$1jP*HbnD`o1$g}_R#+bu2D zr%7Y8KdsaC-V*aem5#@*M%r^GPgu%P2e-BnBClhP2yoGFe40>);=}>{NONtkXQ01p z)OX^t2Ojhddot9eg0WTIVSTNBa}7V-^_pO595w|Hx9q?k4dMp@$G7PK*TD=y;ck6J zdGRB!_RAI2nR3%tO1IkdWp*bw*?<=pM_LZb30?!oK)s;En( z!#nnd9=cXJ<}+e{XLdx(q3&ikJISe?eSHHohk+pz+$6Cv{ytvc{QXmMn2XQ9U8rvt zrJdAn(0gpSD@N=yTrI_2^P#*zQg7MTp1)k(lv(*(KtUR6@M|2WB>2wRwC-h=wk6XF zPtSes*_JwI+^d>xW489MJw5R6=t5?{R zc|E8i?RL@p9)A3ZJAQOg`}+F;<_vnWA!KxR#g%jZ@y_1Qu#Uw)kFPw_xmZ?a^e*1{ zM|ImtqA|(CaDQ@Fyvcof`MN66&VI6m6gAyAXx`%cDx6BI{Bj#}V*Rn1(b~;Am)D2u zX7(027IO?Z2VYK^1vXXpoZ@AtH~N?0rYWwtyA15`6vEf6fk&;o-L;7zFt`5nk*iOy z`<918zB+k;EytI$FAXug)jk*e@e};4e9g__w4A5ev!!)H$yC@{?vsRqJ##X1R%xPG z&_R3oDi$MtTkVqfPj)HEUDx_7wd!y{8#1%$U*Dd0sK@=#6+!XlsE-s^1f5E`R9Wo71^b~mbVdU;Fw0LG~mUQg;xsX4QYRo3B@rH_=ry>DE8ef!c2ta8UcI#26# zF|`*4wtMHe@%#eGZw`#Yj|QWuB`eRD)b~)r9mM95p_JVG%-IdcbIX5qG#GpGD+IrS zEqxb1Rg&Dadk5#7t4j68I1f!@A$efp1?I%&d*56)yl!tkz!14<$0Od_&6cGw$WW0r zjSlQA7l*6;vgfhv!cR|RmAD$+w6j`rVf=-?-D@q>kOseUVSb*~jbAS^*1h?ZL)n(9 zDa}`4etXO6`}9;{k5E^N{rcfnV_(LPwsDg``wtyS*V<19c3!PGJ3Kqy9ksvkwbJ%Z z*N(fT0{e*Wji-Ck5!3YE0j|PZ@&z`v=kitWL$bqSt!e4bH!+(|Q)CZ30^nVPfkx{s zX{6of`p=BiPb@u@IyL!tRk>?qgBqCmo-Zlt!636g?z`s~zdfwuB7DXZHvV`Usp+%Z zo*&;Biu@MHE&2j+?j^o`Cr12u<>vOe=a&8a2hlcmFjJiDR>XnD4c4DAhZWCkiAgW{ E51q9-lK=n! literal 0 HcmV?d00001 diff --git a/app/src/ohosTest/resources/base/profile/test_pages.json b/app/src/ohosTest/resources/base/profile/test_pages.json new file mode 100644 index 0000000..b7e7343 --- /dev/null +++ b/app/src/ohosTest/resources/base/profile/test_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "testability/pages/Index" + ] +} diff --git a/app/src/test/List.test.ets b/app/src/test/List.test.ets new file mode 100644 index 0000000..bb5b5c3 --- /dev/null +++ b/app/src/test/List.test.ets @@ -0,0 +1,5 @@ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/app/src/test/LocalUnit.test.ets b/app/src/test/LocalUnit.test.ets new file mode 100644 index 0000000..ed22d4d --- /dev/null +++ b/app/src/test/LocalUnit.test.ets @@ -0,0 +1,33 @@ +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest',() => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/build-profile.json5 b/build-profile.json5 new file mode 100644 index 0000000..7ac5489 --- /dev/null +++ b/build-profile.json5 @@ -0,0 +1,49 @@ +{ + "app": { + "signingConfigs": [ + { + "name": "default", + "type": "HarmonyOS", + "material": { + "certpath": "pack\\sign\\Calculator.cer", + "storePassword": "0000001B5481E637034868BA817E3587B2970184D289B5D31D4C9419623B4DC7D7BB75754FCA76D10C1041", + "keyAlias": "debugKey", + "keyPassword": "0000001BD840965E928F712E6EA53F84819A89B66F13335133910D43192ABECAA48A75BA9DD3DA3C30A55A", + "profile": "pack\\sign\\Calculator.p7b", + "signAlg": "SHA256withECDSA", + "storeFile": "pack\\sign\\Calculator.p12" + } + } + ], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "4.0.0(10)", + "runtimeOS": "HarmonyOS", + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "app", + "srcPath": "./app", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/hvigor/hvigor-config.json5 b/hvigor/hvigor-config.json5 new file mode 100644 index 0000000..8c56bf6 --- /dev/null +++ b/hvigor/hvigor-config.json5 @@ -0,0 +1,21 @@ +{ + "modelVersion": "5.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "default", /* Define the build analyze mode. Value: [ "default" | "verbose" | false ]. Default: "default" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */ + } +} \ No newline at end of file diff --git a/hvigorfile.ts b/hvigorfile.ts new file mode 100644 index 0000000..f3cb9f1 --- /dev/null +++ b/hvigorfile.ts @@ -0,0 +1,6 @@ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/img.png b/img.png new file mode 100644 index 0000000000000000000000000000000000000000..531a89ee20a192b9e7c4e5915e5ea41b3901dbd2 GIT binary patch literal 45318 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

1D%-qq7%k7r2l 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 T^1@D<27Y`z{XI^*ho}7oEKfiP literal 0 HcmV?d00001 diff --git a/oh-package.json5 b/oh-package.json5 new file mode 100644 index 0000000..e26aa53 --- /dev/null +++ b/oh-package.json5 @@ -0,0 +1,15 @@ +{ + "modelVersion": "5.0.0", + "name": "calculator", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.15", + "@ohos/hamock": "1.0.0-rc" + } +} \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..0b7a77a --- /dev/null +++ b/readme.md @@ -0,0 +1,15 @@ +# 项目说明 + +本项目代码地址为: [Harmony/Calculator - Calculator - DevWiki Gitea](https://git.devwiki.net/Harmony/Calculator),同时会同步到: +- Gitee: [DevWiki/Calculate](https://gitee.com/devwiki/Calculate) +- Github: [Dev-Wiki/Calculator](https://github.com/Dev-Wiki/Calculator) + +## 1. 功能说明 + +## 2. 代码划分 +项目包含以下几个模块: +- [pages](/app/src/main/ets/pages) : 页面部分 + - [pages/calculate](/app/src/main/ets/pages/calculate) : 计算器部分 + - [pages/convert](/app/src/main/ets/pages/convert) : 换算部分 +- [component](/app/src/main/ets/component) : 自定义组件 +- [utils](/app/src/main/ets/utils) : 工具类