diff --git a/OAT.xml b/OAT.xml index 30611cbba766eab49fab4b82408d046ce64f37bf..a63e46efd45bab7ac070eb494da49767cd10c210 100644 --- a/OAT.xml +++ b/OAT.xml @@ -1989,6 +1989,17 @@ Note:If the text contains special characters, please escape them according to th + + + + + + + + + + + diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/.gitignore b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..4bbbb17d2ed2bf6038a2fa1701d9e71b158278c8 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/.gitignore @@ -0,0 +1,13 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer +**/oh-package-lock.json5 \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/AppScope/app.json5 b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ed8decbdbef54ad13ba075412caa382a06134a0c --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/AppScope/app.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + { + "app": { + "bundleName": "com.samples.cardinteractioncase", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/AppScope/resources/base/element/string.json b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..cab306b2f3c614625a29738e8c50b9e53620fbb8 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "CardInteractionCase" + } + ] +} diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/AppScope/resources/base/media/app_icon.png b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/AppScope/resources/base/media/app_icon.png differ diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/README.md b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/README.md new file mode 100644 index 0000000000000000000000000000000000000000..11cd2d11a0c1fe85841e97f777200c9f46093c7f --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/README.md @@ -0,0 +1,254 @@ +# 桌面卡片进入案例 + +### 介绍 + +桌面卡片是比较常见的功能,本案例详细列举了卡片开发的大部分功能,如使用postCardAction接口快速拉起卡片提供方应用的指定UIAbility,通过message事件刷新卡片内容等,为开发者提供了卡片功能的展示。 + +### 效果预览 + +| 卡片 | 案例| +|--------|-----------| +| | | + +### 使用说明 + +1. 长按应用,添加卡片到桌面。 +2. 卡片内可滑动选择案例,点击可进入案例详情。 + +### 实现思路 + +1. 新建卡片 +2. 配置formconfig +3. 编写卡片UI代码 +4. 触发刷新事件 +5. 触发点击事件 + +### 实现步骤 + +本例涉及的关键特性和实现方案如下: + +1. 新建卡片。右键点击entry目录,选择新建->Service Widget->Dynamic Widget,其中Dynamic Widget为动态卡片,Static Widget为静态卡片。此时会生成几个文件:配置文件[```form_config.json```](entry/src/main/resources/base/profile/form_config.json);卡片Ability[```EntryFormAbility.ets```](entry/src/main/ets/entryformability/EntryFormAbility.ets);卡片组件[```CasesSwiperCard.ets```](entry/src/main/ets/widget/pages/CasesSwiperCard.ets)。 + +2. 新建卡片后,根据需要(如卡片大小,刷新时间,动态静态卡片设置)配置```form_config.json```。 + +```json5 +{ + "forms": [ + { + "name": "widget", // 卡片的名称。 + "displayName": "$string:widget_display_name", // 卡片的显示名称。 + "description": "$string:widget_desc", // 卡片的描述。 + "src": "./ets/widget/pages/CasesSwiperCard.ets", // 卡片对应的UI代码的完整路径。 + "uiSyntax": "arkts", // 卡片的类型 + "window": { // 用于定义与显示窗口相关的配置。 + "designWidth": 720, + "autoDesignWidth": true + }, + "colorMode": "auto", // 卡片的主题样式。 + "isDynamic": true, // 卡片是否为动态卡片。 + "isDefault": true, // 卡片是否为默认卡片。 + "updateEnabled": true, // 卡片是否支持周期性刷新。 + "scheduledUpdateTime": "10:30", // 卡片的定点刷新的时刻。 + "updateDuration": 1, // 卡片定时刷新的更新周期,单位为30分钟,取值为自然数。 + "defaultDimension": "6*4", // 卡片的默认外观规格。 + "supportDimensions": [ // 卡片支持的外观规格,取值范围。 + "6*4" + ] + } + ] +} +``` + +3. 编写卡片UI代码。在主文件```CasesSwiperCard.ets```中添加UI组件,需要注意的是:ArkTS卡片存在较多约束(如不支持导入共享包),较多逻辑不可在卡片中使用,在使用时需要根据文档进行操作。 + +4. 编写跳转事件:当应用未被拉起时,点击某个卡片时跳转到具体的案例页面。在```EntryAbility.ets```中补充逻辑:onCreate生命周期内获取want.parameters.params判断卡片内容的跳转。 + +```typescript +// EntryAbility.ets +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + // ... + // 桌面卡片判断跳转内容 + if (want?.parameters?.params) { + // want.parameters.params 对应 postCardAction() 中 params 内容 + let params: Record = JSON.parse(want.parameters.params as string); + this.selectPage = params.targetPage as string; + } + // ... + } +} +``` + +5. 编写跳转事件:当应用在后台时,点击某个卡片时跳转到具体的案例页面。可从onNewWant生命周期获取want.parameters.params判断卡片内容的跳转。 + +```typescript +// EntryAbility.ets +export default class EntryAbility extends UIAbility { + // 如果UIAbility已在后台运行,在收到Router事件后会触发onNewWant生命周期回调 + onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void { + if (want.parameters!['ability.params.stream'] !== undefined) { + AppStorage.setOrCreate('imageUri', want.parameters!["ability.params.stream"].toString()); + return; + } + if (want?.parameters?.params) { + // want.parameters.params 对应 postCardAction() 中 params 内容 + let params: Record = JSON.parse(want.parameters.params as string); + this.selectPage = params.targetPage as string; + if (this.currentWindowStage !== null) { + // 存在窗口时点击卡片后进行页面跳转 + this.currentWindowStage.loadContent(`pages/${this.selectPage}`, (err) => { + if (err.code) { + hilog.error(0x0000, 'testTagSelectPage', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTagSelectPage', 'Succeeded in loading the content.'); + }); + this.selectPage = ''; + } + } else { + this.selectPage = ''; + } + } +} +``` + +6. 具体跳转逻辑编写。在onWindowStageCreate生命周期内进行具体的跳转逻辑。 + +```typescript +// EntryAbility.ets +export default class EntryAbility extends UIAbility { + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + // 判断是否存在窗口可进行页面跳转 + if (this.currentWindowStage === null) { + this.currentWindowStage = windowStage; + } + // 点击卡片后进行页面跳转 + if (this.selectPage) { + windowStage.loadContent(`pages/${this.selectPage}`, (err) => { + 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.'); + }); + } else { + windowStage.loadContent('pages/Index', (err) => { + 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.'); + }); + } + } +} +``` + +7. 编写刷新事件:当定时更新或定点更新触发时,需要更新卡片内容。onUpdateForm生命周期发生在定时更新/定点更新/卡片使用方主动请求更新时,在方法内增加获取案例数据的功能。 + +```typescript +// EntryFormAbility.ets +export default class EntryFormAbility extends FormExtensionAbility { + // 获取数据并利用formProvider.updateForm更新到卡片 + async getData(formId: string) { + let detail: CASES[] = []; + let message = ''; + try { + let value = await this.context.resourceManager.getRawFileContent('CasesData.txt'); + console.log('decodeToStringdecodeToString') + message = util.TextDecoder.create().decodeToString(value); + detail = CaseCardUtils.formatData(message); + hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onFormEvent' + 'result:' + message); + hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] getData' + 'detail:' + JSON.stringify(detail)); + class FormDataClass { + public detail: CASES[] = detail; + } + let formData = new FormDataClass(); + let formInfo = formBindingData.createFormBindingData(formData); + await formProvider.updateForm(formId, formInfo); + } catch (error) { + hilog.error(DOMAIN_NUMBER, TAG, `FormAbility updateForm failed: ${JSON.stringify(error)}`); + } + } + + async onUpdateForm(formId: string): Promise { + // 若卡片支持定时更新/定点更新/卡片使用方主动请求更新功能,则提供方需要重写该方法以支持数据更新 + hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onUpdateForm'); + this.getData(formId); + } +} +``` + +8. 编写刷新事件:参数传到卡片组件内,组件接收参数。处理```CasesSwiperCard.ets```卡片内逻辑。卡片页面中使用LocalStorageProp装饰需要刷新的卡片数据。 + +```ts +let casesCardInfo = new LocalStorage(); +@Entry(casesCardInfo) +@Component +struct Widget_DynamicCard { + @LocalStorageProp('detail') detail: CASES[] = []; // 卡片对象集合 + private swiperController: SwiperController = new SwiperController(); + + build() { + // ... + } +} +``` + +### 工程结构&模块类型 + +``` +CardInteractionCase // har +|---entryability +| |---EntryAbility.ets // EntryAbility +|---entryformability +| |---EntryFormAbility.ets //EntryFormAbility +|---pages +| |---DealStrideSolution.ets // 解决相机预览花屏案例页面 +| |---EncapsulationDialog.ets // 弹窗封装案例页面 +| |---Index.ets // 首页页面 +| |---ShareButton.ets // 分享二维码按钮案例页面 +| |---SmartFill.ets // 智能填充案例页面 +| |---VideoTrimmer.ets // 视频下载保存及剪辑压缩上传案例页面 +|---widget +| |---pages +| |---CasesSwiperCard.ets // 卡片页面 +| |---utils +| |---CaseCardUtils.ets // 卡片公共方法页面 +``` + +### 参考资料 + +[创建一个ArkTS卡片](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/form/arkts-ui-widget-creation.md) + +[配置卡片的配置文件](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/form/arkts-ui-widget-configuration.md) + +[使用router事件跳转到指定UIAbility](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/form/arkts-ui-widget-event-router.md) + +[通过message事件刷新卡片内容](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/form/arkts-ui-widget-event-formextensionability.md) + +### 依赖 + +不涉及。 + +### 约束与限制 + +1.本示例仅支持标准系统上运行。 + +2.本示例已适配API version 12版本SDK。 + +3.本示例需要使用DevEco Studio 5.0.0 Release及以上版本才可编译运行。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/ > .git/info/sparse-checkout +git remote add origin https://gitee.com/openharmony/applications_app_samples.git +git pull origin master +``` diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/build-profile.json5 b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..75b75ecf59fe6a87a5ce3e128a08b691ed4c9ff3 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/build-profile.json5 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "signingConfigs": [], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compileSdkVersion": 12, + "compatibleSdkVersion": 12, + "runtimeOS": "OpenHarmony", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/code-linter.json5 b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..8cf470bcb958127332f7f5e660ace33eeeaeddaa --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/code-linter.json5 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + { + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/.gitignore b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/build-profile.json5 b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4e956928b47b71f85916d920e894e1272a61d125 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/build-profile.json5 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + { + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/hvigorfile.ts b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6edcd90486dd5a853cf7d34c8647f08414ca7a3 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/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/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/obfuscation-rules.txt b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# 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://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/oh-package.json5 b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a180a649c86955e4fc3b32fd470fb0478c87f6ad --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + { + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/entryability/EntryAbility.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..5e99b8bc1383a1c7c82051ae779b9a151b0f2e55 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { Router, window } from '@kit.ArkUI'; + +const TAG = 'EntryAbility' + +export default class EntryAbility extends UIAbility { + private selectPage: string = ''; + private currentWindowStage: window.WindowStage | null = null; + + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + // 桌面卡片判断跳转内容 + if (want?.parameters?.params) { + // want.parameters.params 对应 postCardAction() 中 params 内容 + let params: Record = JSON.parse(want.parameters.params as string); + this.selectPage = params.targetPage as string; + } + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + // 如果UIAbility已在后台运行,在收到Router事件后会触发onNewWant生命周期回调 + onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void { + if (want.parameters!['ability.params.stream'] !== undefined) { + AppStorage.setOrCreate('imageUri', want.parameters!['ability.params.stream'].toString()); + return; + } + if (want?.parameters?.params) { + // want.parameters.params 对应 postCardAction() 中 params 内容 + let params: Record = JSON.parse(want.parameters.params as string); + this.selectPage = params.targetPage as string; + if (this.currentWindowStage !== null) { + // 存在窗口时点击卡片后进行页面跳转 + this.currentWindowStage.loadContent(`pages/${this.selectPage}`, (err) => { + if (err.code) { + hilog.error(0x0000, 'testTagSelectPage', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTagSelectPage', 'Succeeded in loading the content.'); + }); + this.selectPage = ''; + } + } else { + this.selectPage = ''; + } + } + + 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'); + // 判断是否存在窗口可进行页面跳转 + if (this.currentWindowStage === null) { + this.currentWindowStage = windowStage; + } + // 点击卡片后进行页面跳转 + if (this.selectPage) { + windowStage.loadContent(`pages/${this.selectPage}`, (err) => { + 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.'); + }); + } else { + windowStage.loadContent('pages/Index', (err) => { + 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.'); + }); + } + } + + 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'); + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..29feaca7669174be5c2b0e2366529ee94ab7e726 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/entryformability/EntryFormAbility.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/entryformability/EntryFormAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..98e25627bb819fbe919cb58e8531e49ffc586c66 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/entryformability/EntryFormAbility.ets @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit'; +import { Configuration, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { CASES, CaseCardUtils } from '../widget/utils/CaseCardUtils'; +import { util } from '@kit.ArkTS'; +import { BusinessError } from '@kit.BasicServicesKit'; + + +const TAG: string = 'EntryFormAbility'; +const DOMAIN_NUMBER: number = 0xFF00; + +export default class EntryFormAbility extends FormExtensionAbility { + // 获取数据并利用formProvider.updateForm更新到卡片 + async getData(formId: string) { + let detail: CASES[] = []; + let message = ''; + try { + let value = await this.context.resourceManager.getRawFileContent('CasesData.txt'); + console.log('decodeToStringdecodeToString') + message = util.TextDecoder.create().decodeToString(value); + detail = CaseCardUtils.formatData(message); + hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onFormEvent' + 'result:' + message); + hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] getData' + 'detail:' + JSON.stringify(detail)); + class FormDataClass { + public detail: CASES[] = detail; + } + let formData = new FormDataClass(); + let formInfo = formBindingData.createFormBindingData(formData); + await formProvider.updateForm(formId, formInfo); + } catch (error) { + hilog.error(DOMAIN_NUMBER, TAG, `FormAbility updateForm failed: ${JSON.stringify(error)}`); + } + } + + onCastToNormalForm(formId: string): void { + // 使用方将临时卡片转换为常态卡片触发,提供方需要做相应的处理 + hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onCastToNormalForm' + formId); + } + + async onUpdateForm(formId: string): Promise { + // 若卡片支持定时更新/定点更新/卡片使用方主动请求更新功能,则提供方需要重写该方法以支持数据更新 + hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onUpdateForm'); + this.getData(formId); + } + + onChangeFormVisibility(newStatus: Record): void { + // 使用方发起可见或者不可见通知触发,提供方需要做相应的处理,仅系统应用生效 + hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onChangeFormVisibility'); + } + + + async onFormEvent(formId: string, message: string): Promise { + this.getData(formId); + } + + onRemoveForm(formId: string): void { + // 删除卡片实例数据 + hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onRemoveForm'); + // 删除之前持久化的卡片实例数据 + // 此接口请根据实际情况实现,具体请参考:FormExtAbility Stage模型卡片实例 + } + + onConfigurationUpdate(config: Configuration) { + // 当前formExtensionAbility存活时更新系统配置信息时触发的回调。 + // 需注意:formExtensionAbility创建后10秒内无操作将会被清理。 + hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onConfigurationUpdate:' + JSON.stringify(config)); + } + + onAcquireFormState(want: Want) { + // 卡片提供方接收查询卡片状态通知接口,默认返回卡片初始状态。 + return formInfo.FormState.READY; + } +} diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/DealStrideSolution.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/DealStrideSolution.ets new file mode 100644 index 0000000000000000000000000000000000000000..e82520bd7b7ce27306b0bc1192a7eaff7a85cf0f --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/DealStrideSolution.ets @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Entry +@Component +struct DealStrideSolution { + @State message: string = '解决相机预览花屏案例'; + + build() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + Image($r('app.media.deal_stride_solution')) + .width(300) + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/EncapsulationDialog.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/EncapsulationDialog.ets new file mode 100644 index 0000000000000000000000000000000000000000..ab9569d6c4fc30afe02374703795c170b93d96c7 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/EncapsulationDialog.ets @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Entry +@Component +struct EncapsulationDialog { + @State message: string = '弹窗封装'; + + build() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + Image($r('app.media.encapsulation_dialog')) + .width(300) + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/Index.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..a524a899a549432640d35fe5f53c3316a08dbfc7 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Entry +@Component +struct Index { + @State message: string = 'Hello World'; + + build() { + RelativeContainer() { + Text(this.message) + .id('HelloWorld') + .fontSize(50) + .fontWeight(FontWeight.Bold) + .alignRules({ + center: { anchor: '__container__', align: VerticalAlign.Center }, + middle: { anchor: '__container__', align: HorizontalAlign.Center } + }) + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/ShareButton.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/ShareButton.ets new file mode 100644 index 0000000000000000000000000000000000000000..0554c315bda11d9c11239093bae586130a444f34 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/ShareButton.ets @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Entry +@Component +struct ShareButton { + @State message: string = '分享二维码按钮案例'; + + build() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + Image($r('app.media.share_button')) + .width(300) + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/SmartFill.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/SmartFill.ets new file mode 100644 index 0000000000000000000000000000000000000000..e5e0b0646eb1cb816a24f9c581c8b7b2c598a1bc --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/SmartFill.ets @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Entry +@Component +struct SmartFill { + @State message: string = '智能填充案例'; + + build() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + Image($r('app.media.smart_fill')) + .width(300) + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/VideoTrimmer.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/VideoTrimmer.ets new file mode 100644 index 0000000000000000000000000000000000000000..3e4b3dad006714a185f48d2e734ef4110d5c6d2e --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/pages/VideoTrimmer.ets @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Entry +@Component +struct VideoTrimmer { + @State message: string = '视频下载保存及剪辑压缩上传'; + + build() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + Image($r('app.media.video_trimmer')) + .width(300) + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/widget/pages/CasesSwiperCard.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/widget/pages/CasesSwiperCard.ets new file mode 100644 index 0000000000000000000000000000000000000000..448823eb2cd366494f31ec0c920b0e06a6ef721d --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/widget/pages/CasesSwiperCard.ets @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// 自定义卡片对象格式 +interface CASES { + name: string, + url: string, + describe: string, + img: string +} + +const ACTION_TYPE_ROUTER: string = 'router'; +const ACTION_TYPE_MESSAGE: string = 'message'; +const ABILITY_NAME: string = 'EntryAbility'; + +let casesCardInfo = new LocalStorage(); + +@Entry(casesCardInfo) +@Component +struct Widget_DynamicCard { + @LocalStorageProp('detail') detail: CASES[] = []; // 卡片对象集合 + private swiperController: SwiperController = new SwiperController(); + + aboutToAppear(): void { + postCardAction(this, { + action: ACTION_TYPE_MESSAGE, + params: { + method: $r('app.string.widget_message_content') + } + }) + } + + build() { + Column() { + Stack() { + if (this.detail.length) { + Swiper(this.swiperController) { + ForEach(this.detail, (item: CASES) => { + Stack() { + Image($r(`app.media.${item.img}`))// 案例图片 + .width('100%') + .height('100%') + Stack() { + Column() + .width('100%') + .height(50) + .backgroundColor(Color.Black) + .opacity(0.6) + Text(item.name) // 案例名称 + .width('100%') + .fontSize($r('app.integer.widget_name_fontsize')) + .fontColor(Color.White) + .fontWeight(FontWeight.Medium) + .textAlign(TextAlign.Center) + } + } + .alignContent(Alignment.Bottom) + .width($r('app.string.widget_display_full_width_percent')) + .height($r('app.string.widget_display_full_height_percent')) + .onClick(() => { + // 点击卡片进入对应案例 + postCardAction(this, { + action: ACTION_TYPE_ROUTER, + abilityName: ABILITY_NAME, + params: { targetPage: item.url } + }); + }) + }) + } + .autoPlay(true) + } + } + .width($r('app.string.widget_display_full_width_percent')) + .height($r('app.string.widget_display_full_height_percent')) + } + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/widget/utils/CaseCardUtils.ets b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/widget/utils/CaseCardUtils.ets new file mode 100644 index 0000000000000000000000000000000000000000..f0893560e94ecf9478ea7b3534a35d4c07af6a2d --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/ets/widget/utils/CaseCardUtils.ets @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// 自定义卡片对象格式 +export interface CASES { + name: string, + url: string, + describe: string, + img: string +} + +const CASES_MAX_LENGTH: number = 5; // 卡片展示最大案例数 + +export class CaseCardUtils { + // 案例字符串格式化 + public static formatData(data: string) { + let result: CASES[] = []; + if (data.indexOf('**下面是详细的案例列表:**') > -1) { + let casesArray: string[] = data.split('**下面是详细的案例列表:**')[1].split('####'); + for (let i = 1; i <= CASES_MAX_LENGTH; i++) { + const cases: CASES = { + name: CaseCardUtils.nameFormat(casesArray[i]), + url: CaseCardUtils.urlFormat(casesArray[i]), + describe: CaseCardUtils.introduceFormat(casesArray[i]), + img: CaseCardUtils.imageFormat(casesArray[i]) + } + result.push(cases); + } + } + return result; + } + + // 案例图片地址格式化 + public static imageFormat(casesTexts: string): string { + let casesText: string = casesTexts; + let reg1 = /]*>/i; + let reg2 = /\/base\/media\/[^.]*/; + const matches1 = casesText.match(reg1); + const matches2 = matches1?.[0].match(reg2); + casesText = matches2?.[0].replace(/\/base\/media\//, '') || ''; + return casesText; + } + + // 案例名称格式化 + public static nameFormat(casesText: string): string { + const part1: string[] = casesText.split('.'); + if (part1.length > 1) { + const part2: string[] = part1[1].split('('); + const part3: string[] = part1[1].split('('); + if (part2.length > 1) { + return part2[0].trim(); + } else if (part3.length > 1) { + return part3[0].trim(); + } + } + return ''; + } + + // 案例概述格式化 + public static introduceFormat(casesTexts: string): string { + let casesText: string = casesTexts; + let reg1 = /\[([^\]]*)]\(([^)]*)\)/g; + let reg2 = /]*>/gi; + const matches1 = casesText.matchAll(reg1); + for (const match1 of matches1) { + casesText = casesText.replace(match1[0], match1[1]); + } + const matches2 = casesText.matchAll(reg2); + for (const match2 of matches2) { + casesText = casesText.replace(match2[0], ''); + } + casesText = casesText.replace(/\s+/g, '').replace('详细说明文档', ''); + return casesText; + } + + // 案例地址格式化 + public static urlFormat(casesText: string): string { + const part1: string[] = casesText.split('CommonAppDevelopment/feature/'); + const part2: string[] = part1[1]?.split('/') || []; + if (part2.length > 1) { + return part2[0].trim(); + } + return ''; + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/module.json5 b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5d85ae43a715b4c87a6431a5ee959ed462e82770 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/module.json5 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + { + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET" + }, + { + "name": "ohos.permission.GET_NETWORK_INFO" + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ,{ + "name": "EntryFormAbility", + "srcEntry": "./ets/entryformability/EntryFormAbility.ets", + "label": "$string:EntryFormAbility_label", + "description": "$string:EntryFormAbility_desc", + "type": "form", + "metadata": [ + { + "name": "ohos.extension.form", + "resource": "$profile:form_config" + } + ] + }] + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/color.json b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..6d2ce43ae455acf8a25670b46dd69c53a40fe20c --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/color.json @@ -0,0 +1,11 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ,{ + "name": "item_title_font", + "value": "#E6000000" + }] +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/float.json b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..840cbf2e42e3af4c917754cd09ba95bf6653c58f --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/float.json @@ -0,0 +1,8 @@ +{ + "float": [ + { + "name": "font_size", + "value": "14fp" + } + ] +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/integer.json b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/integer.json new file mode 100644 index 0000000000000000000000000000000000000000..ee61ead9e3992687909e7f95dda867791071fc1f --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/integer.json @@ -0,0 +1,16 @@ +{ + "integer": [ + { + "name": "widget_display_margin", + "value": 15 + }, + { + "name": "widget_name_fontsize", + "value": 18 + }, + { + "name": "widget_describe_fontsize", + "value": 15 + } + ] +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/string.json b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..0dff1125acce742e718bdbb2b8ac0169dc6c24a1 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/element/string.json @@ -0,0 +1,60 @@ +{ + "string": [ + { + "name": "widget_desc", + "value": "This is a service widget." + }, + { + "name": "widget_display_name", + "value": "widget" + }, + { + "name": "widget_display_full_width_percent", + "value": "100%" + }, + { + "name": "widget_display_full_height_percent", + "value": "100%" + }, + { + "name": "widget_display_part_width_percent", + "value": "50%" + }, + { + "name": "widget_form_ability_name", + "value": "100%" + }, + { + "name": "widget_message_content", + "value": "getData" + }, + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "CardInteractionCase" + }, + { + "name": "EntryFormAbility_desc", + "value": "form_description" + }, + { + "name": "EntryFormAbility_label", + "value": "form_label" + }, + { + "name": "casesSwiper_desc", + "value": "This is a service widget." + }, + { + "name": "casesSwiper_display_name", + "value": "widget" + } + ] +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/background.png b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/background.png differ diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/deal_stride_solution.gif b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/deal_stride_solution.gif new file mode 100644 index 0000000000000000000000000000000000000000..ab665f626e0b17a685b6628a67849a62b0a411b2 Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/deal_stride_solution.gif differ diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/encapsulation_dialog.gif b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/encapsulation_dialog.gif new file mode 100644 index 0000000000000000000000000000000000000000..e51268bbc01c9806a8d62221d2b063afe08b7b1a Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/encapsulation_dialog.gif differ diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/foreground.png b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/foreground.png differ diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/layered_image.json b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/share_button.gif b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/share_button.gif new file mode 100644 index 0000000000000000000000000000000000000000..bb071b372ca8c81b878a90d36fd55ea0ed4cb56d Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/share_button.gif differ diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/smart_fill.gif b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/smart_fill.gif new file mode 100644 index 0000000000000000000000000000000000000000..7bbd275dfe66e542bfa7f3ef5dd8e301d323aa89 Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/smart_fill.gif differ diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/startIcon.png b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/startIcon.png differ diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/video_trimmer.gif b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/video_trimmer.gif new file mode 100644 index 0000000000000000000000000000000000000000..23529d3559838f8dd0f95786de1f19b488e0976a Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/media/video_trimmer.gif differ diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/profile/backup_config.json b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/profile/form_config.json b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/profile/form_config.json new file mode 100644 index 0000000000000000000000000000000000000000..47c437293dff041d0b5c8ad04fa94f2f67148b83 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/profile/form_config.json @@ -0,0 +1,26 @@ +{ + "forms": [ + { + "name": "casesSwiper", + "displayName": "$string:casesSwiper_display_name", + "description": "$string:casesSwiper_desc", + "src": "./ets/widget/pages/CasesSwiperCard.ets", + "uiSyntax": "arkts", + "window": { + "designWidth": 720, + "autoDesignWidth": true + }, + "colorMode": "auto", + "isDynamic": true, + "isDefault": true, + "updateEnabled": false, + "scheduledUpdateTime": "10:30", + "updateDuration": 1, + "defaultDimension": "6*4", + "supportDimensions": [ + "6*4", + "4*4" + ] + } + ] +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/profile/main_pages.json b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..69afc908ea84490c34577ad8e9f0e5bccd24e835 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,10 @@ +{ + "src": [ + "pages/Index", + "pages/DealStrideSolution", + "pages/EncapsulationDialog", + "pages/ShareButton", + "pages/SmartFill", + "pages/VideoTrimmer" + ] +} diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/dark/element/color.json b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/rawfile/CasesData.txt b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/rawfile/CasesData.txt new file mode 100644 index 0000000000000000000000000000000000000000..8a502344169714440882ad72a9f6fd68e7d8ee37 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/entry/src/main/resources/rawfile/CasesData.txt @@ -0,0 +1,46 @@ +cases_detail +**下面是详细的案例列表:** +#### 180.分享二维码按钮案例(2025/01/22更新) + +本示例介绍如何在应用中,通过url自动生成二维码,并通过Share Kit的接口拉起系统分享。[详细说明文档](./CommonAppDevelopment/feature/ShareButton/README.md) + + + +#### 179.智能填充案例(2025/01/23更新) + +本示例介绍了使用智能填充自动补充表单的功能。 +该场景多用于需要使用多个填充相同表单的场景。[详细说明文档](./CommonAppDevelopment/feature/SmartFill/README.md) + + + +#### 178.弹窗封装(2025/01/23更新) + +本示例介绍如何封装弹窗,以及如何使用这种封装后的弹窗 +[详细说明文档](./CommonAppDevelopment/feature/EncapsulationDialog/README.md) + + + +#### 177.视频下载保存及剪辑压缩上传(2025/01/23更新) + +本示例主要介绍从网上下载视频到相册,以及从相册中选择视频进行剪辑、压缩、以及上传到服务器进行保存。从相册中选择一个视频保存到沙箱中,再使用FFmpeg命令对沙箱中的视频进行压缩、剪辑。最后使用request.agent将剪辑后的视频上传到服务器进行保存。 +[详细说明文档](./CommonAppDevelopment/feature/VideoTrimmer/README.md) + + + +#### 176.解决相机预览花屏案例(2025/01/21更新) + +本示例用于开发者在使用相机服务时,如果仅用于预览流展示,通常使用XComponent组件实现,如果需要获取每帧图像做二次处理(例如获取每帧图像完成二维码识别或人脸识别场景),可以通过ImageReceiver中imageArrival事件监听预览流每帧数据,解析图像内容。在解析图像内容时,如果未考虑stride,直接通过使用width*height读取图像内容去解析图像,会导致相机预览异常,从而出现相机预览花屏的现象。当预览流图像stride与width不一致时,需要对stride进行无效像素的去除处理。[详细说明文档](./CommonAppDevelopment/feature/DealStrideSolution/README.md) + + + +#### 166.自定义地址选择组件(1125更新) + +本示例介绍如何使用bindSheet,changeIndex,onAreaChange实现带切换动效的自定义地址选择组件。[详细说明文档](./CommonAppDevelopment/feature/customaddresspicker/README.md) + + + +### 公共能力层 + +公共功能层用于存放公共基础能力,集中了例如公共UI组件、数据管理、外部交互以及工具库等的共享功能。应用与元服务都可以共享和调用这些公共能力。 + +公共能力层为上层的基础特性层和产品定制层提供稳定可靠的功能支持,确保整个应用/元服务的稳定性和可维护性。 diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/hvigor/hvigor-config.json5 b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..88350a7e3c739a98ae26bee1ec4bb25a12175d30 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + { + "modelVersion": "5.0.1", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/hvigorfile.ts b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3cb9f1a87a81687554a76283af8df27d8bda775 --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/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/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/oh-package.json5 b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..87fd23ee937818091c08f0d203d079a91d3cf11b --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + { + "modelVersion": "5.0.1", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +} diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/ohosTest.md b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..0e999bdfeb734594389779edc2b3a2a3e09b2bcb --- /dev/null +++ b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/ohosTest.md @@ -0,0 +1,9 @@ +# 桌面卡片进入案例 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| ---- | ------------ | ---------- |---------| -------- | -------- | +| 添加卡片到桌面。 | 安装应用,回到桌面。 | 长按应用,点击服务卡片,选择卡片点击添加到桌面。 | 对应卡片被添加到桌面。 | 否 | 通过 | +| 卡片内容正确展示 | 卡片被添加到桌面 | 在卡片上左右滑动,观察卡片显示是否正常。 | 卡片内容正确显示 | 否 | 通过 | +| 点击卡片内容,正确跳转 | 卡片内容正确展示 | 点击卡片内任意案例,跳转到应用内对应的案例页面 | 点击卡片内容,正确跳转 | 否 | 通过 | diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/screenshots/devices/Case.jpg b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/screenshots/devices/Case.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0e6587de080cafc649b3e7d91d1845e61e88aa48 Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/screenshots/devices/Case.jpg differ diff --git a/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/screenshots/devices/Widget.jpg b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/screenshots/devices/Widget.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8e8b9f3d24a42ee4745f658b194030fa0567ccc7 Binary files /dev/null and b/code/SuperFeature/Widget/ArkTSCard/CardInteractionCase/screenshots/devices/Widget.jpg differ