-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathArkTs-SWE-bench-Exp.json
More file actions
342 lines (342 loc) · 279 KB
/
Copy pathArkTs-SWE-bench-Exp.json
File metadata and controls
342 lines (342 loc) · 279 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
[
{
"instance_id": "ArkTs_Exp_001",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "a96b50e0",
"problem_statement": "鸿蒙世界体验-Penkit闪退修复:当前工程在启动应用体验-Penkit功能按钮时出现了闪退,然后大概定位到是products/phone/src/main/ets/entryability/EntryAbility.ets不完善引起的,请尝试修复当前闪退问题。",
"hints_text": "",
"patch": "diff --git b/products/phone/src/main/ets/entryability/EntryAbility.ets a/products/phone/src/main/ets/entryability/EntryAbility.ets\nindex b437603..a1bca7f 100644\n--- b/products/phone/src/main/ets/entryability/EntryAbility.ets\n+++ a/products/phone/src/main/ets/entryability/EntryAbility.ets\n@@ -27,6 +27,7 @@ import {\n WebUtil,\n WindowUtil,\n } from '@ohos/common';\n+import GlobalUIAbilityContext from '../util/ContextConfig';\n import { UpdateFormData } from '../util/UpdateFormData';\n \n const TAG = '[EntryAbility]';\n@@ -63,6 +64,7 @@ export default class EntryAbility extends UIAbility {\n // Main window is created, set main page for this ability\n Logger.info(TAG, 'Ability onWindowStageCreate');\n // Use for penkit component\n+ GlobalUIAbilityContext.setContext(this.context);\n AppStorage.setOrCreate(StorageKey.HOME_PAGE_CONTEXT, new PageContext());\n AppStorage.setOrCreate(StorageKey.SAMPLE_PAGE_CONTEXT, new PageContext());\n AppStorage.setOrCreate(StorageKey.COMPONENT_PAGE_CONTEXT, new PageContext());\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "issue_fix"
},
{
"instance_id": "ArkTs_Exp_002",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "43ac9610",
"problem_statement": "Sample详情页HDS导航栏避让:修复Sample详情页HDS导航栏避让的问题。出错文件features/devpractices/src/main/ets/view/PracticeDetailView.ets",
"hints_text": "",
"patch": "diff --git b/features/devpractices/src/main/ets/view/PracticeDetailView.ets a/features/devpractices/src/main/ets/view/PracticeDetailView.ets\nindex a082248..159e78a 100644\n--- b/features/devpractices/src/main/ets/view/PracticeDetailView.ets\n+++ a/features/devpractices/src/main/ets/view/PracticeDetailView.ets\n@@ -84,7 +84,7 @@ export struct SampleDetailView {\n .layoutWeight(1)\n .width('100%')\n .padding({\n- top: CommonConstants.NAVIGATION_HEIGHT,\n+ top: CommonConstants.NAVIGATION_HEIGHT + (VersionUtil.canUseHds() ? this.globalInfoModel.statusBarHeight : 0),\n bottom: this.globalInfoModel.naviIndicatorHeight,\n })\n .indicator(this.sampleDetailState.sampleCount > 1)\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "issue_fix"
},
{
"instance_id": "ArkTs_Exp_003",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "f02c38a3",
"problem_statement": "【需求描述】:删除首页下方组件列表中的文本Text组件,包括相关代码、文件和引用",
"hints_text": "",
"patch": "diff --git a/common/src/main/resources/rawfile/mockdata/component-page.json b/common/src/main/resources/rawfile/mockdata/component-page.json\nindex 5f7207f..6af9010 100644\n--- a/common/src/main/resources/rawfile/mockdata/component-page.json\n+++ b/common/src/main/resources/rawfile/mockdata/component-page.json\n@@ -51,16 +51,6 @@\n \"cardImage\": \"image/component/card/text.png\",\n \"version\": 1000000,\n \"cardContents\": [\n- {\n- \"id\": 10,\n- \"type\": 1,\n- \"cardId\": 1,\n- \"mediaType\": 1,\n- \"mediaUrl\": \"image/component/icon/text/text.png\",\n- \"title\": \"Text\",\n- \"subTitle\": \"文本\",\n- \"tagIds\": []\n- },\n {\n \"id\": 42,\n \"type\": 1,\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets b/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\nindex 2358159..ec57156 100644\n--- a/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\n@@ -100,9 +100,6 @@ import { TextPickerDialogDescriptor } from './textpickerdialogview/viewmodel/Tex\n import { TextToSpeechBuilder } from './texttospeech/component/TextToSpeechBuilder'\n import { TextToSpeechCodeGenerator } from './texttospeech/viewmodel/TextToSpeechCodeGenerator'\n import { TextToSpeechDescriptor } from './texttospeech/viewmodel/TextToSpeechDescriptor'\n-import { TextBuilder } from './textview/component/TextBuilder'\n-import { TextCodeGenerator } from './textview/viewmodel/TextCodeGenerator'\n-import { TextDescriptor } from './textview/viewmodel/TextDescriptor'\n import { ToggleBuilder } from './toggleview/component/ToggleBuilder'\n import { ToggleCodeGenerator } from './toggleview/viewmodel/ToggleCodeGenerator'\n import { ToggleDescriptor } from './toggleview/viewmodel/ToggleDescriptor'\n@@ -158,11 +155,6 @@ export const componentDetailConfig: Record<string, ConfigInterface> = {\n codeGenerate: new ProgressCodeGenerator(),\n attributeFilter: new ProgressAttributeFilter(),\n },\n- 'Text': {\n- previewComponentBuilder: wrapBuilder(TextBuilder),\n- descriptor: () => new TextDescriptor(),\n- codeGenerate: new TextCodeGenerator(),\n- },\n 'TextArea': {\n previewComponentBuilder: wrapBuilder(TextAreaBuilder),\n descriptor: () => new TextAreaDescriptor(),\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/component/TextBuilder.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/component/TextBuilder.ets\ndeleted file mode 100644\nindex 58f70c8..0000000\n--- a/features/componentlibrary/src/main/ets/componentdetailview/textview/component/TextBuilder.ets\n+++ /dev/null\n@@ -1,24 +0,0 @@\n-/*\n- * Copyright (c) 2024 Huawei Device Co., Ltd.\n- * Licensed under the Apache License, Version 2.0 (the \"License\");\n- * you may not use this file except in compliance with the License.\n- * You may obtain a copy of the License at\n- *\n- * http://www.apache.org/licenses/LICENSE-2.0\n- *\n- * Unless required by applicable law or agreed to in writing, software\n- * distributed under the License is distributed on an \"AS IS\" BASIS,\n- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n- * See the License for the specific language governing permissions and\n- * limitations under the License.\n- */\n-\n-import type { DescriptorWrapper } from '../../../viewmodel/DescriptorWrapper';\n-import type { TextDescriptor } from '../viewmodel/TextDescriptor';\n-import { TextAttributeModifier } from '../viewmodel/TextAttributeModifier';\n-\n-@Builder\n-export function TextBuilder($$: DescriptorWrapper) {\n- Text($r('app.string.textview_text'))\n- .attributeModifier(new TextAttributeModifier($$.descriptor as TextDescriptor))\n-}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets\ndeleted file mode 100644\nindex 3eafed3..0000000\n--- a/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets\n+++ /dev/null\n@@ -1,46 +0,0 @@\n-/*\n- * Copyright (c) 2024 Huawei Device Co., Ltd.\n- * Licensed under the Apache License, Version 2.0 (the \"License\");\n- * you may not use this file except in compliance with the License.\n- * You may obtain a copy of the License at\n- *\n- * http://www.apache.org/licenses/LICENSE-2.0\n- *\n- * Unless required by applicable law or agreed to in writing, software\n- * distributed under the License is distributed on an \"AS IS\" BASIS,\n- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n- * See the License for the specific language governing permissions and\n- * limitations under the License.\n- */\n-\n-import { CommonColorMapping, CommonNumberMapping } from '../../common/entity/CommonMapData';\n-\n-class TextMapping {\n- public readonly code: string;\n- public readonly value: Length;\n-\n- constructor(code: string, value: Length) {\n- this.code = code;\n- this.value = value;\n- }\n-}\n-\n-export const fontSizeMapData: Map<string, TextMapping> = new Map([\n- ['Default', new TextMapping('16', $r('sys.float.ohos_id_text_size_body1'))],\n-]);\n-\n-export const fontColorMapData: Map<string, CommonColorMapping> = new Map([\n- ['Default', new CommonColorMapping('rgba(0,85,255)', 'rgba(0,85,255)')],\n-]);\n-\n-export const opacityMapData: Map<string, CommonNumberMapping> = new Map([\n- ['Default', new CommonNumberMapping('1', 1)],\n-]);\n-\n-export const letterSpacingMapData: Map<string, CommonNumberMapping> = new Map([\n- ['Default', new CommonNumberMapping('0', 0)],\n-]);\n-\n-export const textShadowRadiusMapData: Map<string, CommonNumberMapping> = new Map([\n- ['Default', new CommonNumberMapping('0', 0)],\n-]);\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets\ndeleted file mode 100644\nindex 6b7aba8..0000000\n--- a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets\n+++ /dev/null\n@@ -1,30 +0,0 @@\n-/*\n- * Copyright (c) 2024 Huawei Device Co., Ltd.\n- * Licensed under the Apache License, Version 2.0 (the \"License\");\n- * you may not use this file except in compliance with the License.\n- * You may obtain a copy of the License at\n- *\n- * http://www.apache.org/licenses/LICENSE-2.0\n- *\n- * Unless required by applicable law or agreed to in writing, software\n- * distributed under the License is distributed on an \"AS IS\" BASIS,\n- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n- * See the License for the specific language governing permissions and\n- * limitations under the License.\n- */\n-\n-import { CommonAttributeModifier } from '../../../viewmodel/CommonAttributeModifier';\n-import type { TextDescriptor } from './TextDescriptor';\n-\n-@Observed\n-export class TextAttributeModifier extends CommonAttributeModifier<TextDescriptor, TextAttribute> {\n- applyNormalAttribute(instance: TextAttribute): void {\n- this.assignAttribute((descriptor => descriptor.fontWeight), (val) => instance.fontWeight(val));\n- this.assignAttribute((descriptor => descriptor.fontSize), (val) => instance.fontSize(Number(val)));\n- this.assignAttribute((descriptor => descriptor.fontColor), (val) => instance.fontColor(val));\n- this.assignAttribute((descriptor => descriptor.opacity), (val) => instance.opacity(val));\n- this.assignAttribute((descriptor => descriptor.letterSpacing), (val) => instance.letterSpacing(val));\n- this.assignAttribute((descriptor => descriptor.textShadowRadius), (val) => instance.textShadow({ radius: val,\n- color: $r('sys.color.ohos_id_color_foreground')}));\n- }\n-}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets\ndeleted file mode 100644\nindex 5c84076..0000000\n--- a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets\n+++ /dev/null\n@@ -1,75 +0,0 @@\n-/*\n- * Copyright (c) 2024 Huawei Device Co., Ltd.\n- * Licensed under the Apache License, Version 2.0 (the \"License\");\n- * you may not use this file except in compliance with the License.\n- * You may obtain a copy of the License at\n- *\n- * http://www.apache.org/licenses/LICENSE-2.0\n- *\n- * Unless required by applicable law or agreed to in writing, software\n- * distributed under the License is distributed on an \"AS IS\" BASIS,\n- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n- * See the License for the specific language governing permissions and\n- * limitations under the License.\n- */\n-\n-import type { OriginAttribute } from '../../../viewmodel/Attribute';\n-import { CommonCodeGenerator } from '../../../viewmodel/CommonCodeGenerator';\n-import { fontWeightMapData } from '../../common/entity/CommonMapData';\n-import {\n- fontColorMapData,\n- fontSizeMapData,\n- letterSpacingMapData,\n- opacityMapData,\n- textShadowRadiusMapData,\n-} from '../entity/TextAttributeMapping';\n-\n-export class TextCodeGenerator implements CommonCodeGenerator {\n- private fontWeight: string = fontWeightMapData.get('Default')!.code;\n- private fontSize: string = fontSizeMapData.get('Default')!.code;\n- private fontColor: string = fontColorMapData.get('Default')!.code;\n- private opacity: string = opacityMapData.get('Default')!.code;\n- private letterSpacing: string = letterSpacingMapData.get('Default')!.code;\n- private textShadowRadius: string = textShadowRadiusMapData.get('Default')!.code;\n-\n- public generate(attributes: OriginAttribute[]): string {\n- const text = '开发者你好';\n- attributes.forEach((attribute) => {\n- switch (attribute.name) {\n- case 'fontWeight':\n- this.fontWeight =\n- fontWeightMapData.get(attribute.currentValue)?.code ?? fontWeightMapData.get('Default')!.code;\n- break;\n- case 'fontColor':\n- this.fontColor = attribute.currentValue;\n- break;\n- case 'fontSize':\n- this.fontSize = attribute.currentValue;\n- break;\n- case 'opacity':\n- this.opacity = Number(attribute.currentValue).toString();\n- break;\n- case 'letterSpacing':\n- this.letterSpacing = attribute.currentValue;\n- break;\n- case 'textShadowRadius':\n- this.textShadowRadius = attribute.currentValue;\n- break;\n- default:\n- break;\n- }\n- });\n- return `@Component\n-struct TextComponent {\n- build() {\n- Text('${text}')\n- .fontSize(${this.fontSize})\n- .fontColor('${this.fontColor}')\n- .fontWeight(${this.fontWeight})\n- .opacity(${this.opacity})\n- .letterSpacing(${this.letterSpacing})\n- .textShadow({ radius: ${this.textShadowRadius} })\n- }\n-}`;\n- }\n-}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets\ndeleted file mode 100644\nindex 770cb82..0000000\n--- a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets\n+++ /dev/null\n@@ -1,63 +0,0 @@\n-/*\n- * Copyright (c) 2024 Huawei Device Co., Ltd.\n- * Licensed under the Apache License, Version 2.0 (the \"License\");\n- * you may not use this file except in compliance with the License.\n- * You may obtain a copy of the License at\n- *\n- * http://www.apache.org/licenses/LICENSE-2.0\n- *\n- * Unless required by applicable law or agreed to in writing, software\n- * distributed under the License is distributed on an \"AS IS\" BASIS,\n- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n- * See the License for the specific language governing permissions and\n- * limitations under the License.\n- */\n-\n-import type { OriginAttribute } from '../../../viewmodel/Attribute';\n-import { CommonDescriptor } from '../../../viewmodel/CommonDescriptor';\n-import { fontWeightMapData } from '../../common/entity/CommonMapData';\n-import {\n- fontColorMapData,\n- fontSizeMapData,\n- letterSpacingMapData,\n- opacityMapData,\n- textShadowRadiusMapData,\n-} from '../entity/TextAttributeMapping';\n-\n-@Observed\n-export class TextDescriptor extends CommonDescriptor {\n- public fontWeight: FontWeight = fontWeightMapData.get('Default')!.value as FontWeight;\n- public fontSize: number | string = fontSizeMapData.get('Default')!.value as number;\n- public fontColor: ResourceColor = fontColorMapData.get('Default')!.value as string;\n- public opacity: number = opacityMapData.get('Default')!.value as number;\n- public letterSpacing: number = letterSpacingMapData.get('Default')!.value as number;\n- public textShadowRadius: number = textShadowRadiusMapData.get('Default')!.value as number;\n-\n- public convert(attributes: OriginAttribute[]): void {\n- attributes.forEach((attribute) => {\n- switch (attribute.name) {\n- case 'fontWeight':\n- this.fontWeight = (fontWeightMapData.get(attribute.currentValue)?.value ??\n- fontWeightMapData.get('Default')!.value) as FontWeight;\n- break;\n- case 'fontColor':\n- this.fontColor = attribute.currentValue;\n- break;\n- case 'fontSize':\n- this.fontSize = Number(attribute.currentValue);\n- break;\n- case 'opacity':\n- this.opacity = Number(attribute.currentValue);\n- break;\n- case 'letterSpacing':\n- this.letterSpacing = Number(attribute.currentValue);\n- break;\n- case 'textShadowRadius':\n- this.textShadowRadius = Number(attribute.currentValue);\n- break;\n- default:\n- break;\n- }\n- });\n- }\n-}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/resources/base/element/string.json b/features/componentlibrary/src/main/resources/base/element/string.json\nindex 9492418..f0dea6e 100644\n--- a/features/componentlibrary/src/main/resources/base/element/string.json\n+++ b/features/componentlibrary/src/main/resources/base/element/string.json\n@@ -28,10 +28,6 @@\n \"name\": \"text_placeholder\",\n \"value\": \"Please enter text.\"\n },\n- {\n- \"name\": \"textview_text\",\n- \"value\": \"Hello, Developer\"\n- },\n {\n \"name\": \"textarea_text\",\n \"value\": \"I have a cute teddy bear. It's quite chubby, so fat that its belly looks like it's about to burst! The clothes it wears are beautiful, and the clothes are colorful, with purple, pink, and yellow, very beautiful!\"\ndiff --git a/features/componentlibrary/src/main/resources/en_US/element/string.json b/features/componentlibrary/src/main/resources/en_US/element/string.json\nindex d0ed39c..9f7ef5d 100644\n--- a/features/componentlibrary/src/main/resources/en_US/element/string.json\n+++ b/features/componentlibrary/src/main/resources/en_US/element/string.json\n@@ -28,10 +28,6 @@\n \"name\": \"text_placeholder\",\n \"value\": \"Please enter text.\"\n },\n- {\n- \"name\": \"textview_text\",\n- \"value\": \"Hello, Developer\"\n- },\n {\n \"name\": \"camera_picker_button\",\n \"value\": \"Safe Use of Cameras\"\ndiff --git a/features/componentlibrary/src/main/resources/zh_CN/element/string.json b/features/componentlibrary/src/main/resources/zh_CN/element/string.json\nindex 3483e31..5d16b8d 100644\n--- a/features/componentlibrary/src/main/resources/zh_CN/element/string.json\n+++ b/features/componentlibrary/src/main/resources/zh_CN/element/string.json\n@@ -28,10 +28,6 @@\n \"name\": \"text_placeholder\",\n \"value\": \"请输入文字\"\n },\n- {\n- \"name\": \"textview_text\",\n- \"value\": \"开发者你好\"\n- },\n {\n \"name\": \"textarea_text\",\n \"value\": \"我有一只可爱的玩具熊。它长得很胖,胖得肚子都要爆炸了!它穿的衣服都很漂亮,而且衣服上五颜六色,有紫的、有粉的、还有黄的,非常漂亮!\"\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_004",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "5a8d5062",
"problem_statement": "【需求描述】:在首页文本类组件下方第一个,添加文本(Text)组件,位于单行文本输入(TextInput)上方,实现要求:参考其他文本类组件布局样式,包含预览区域和调整区域,预览区域默认显示'开发者你好',调整区域包括字重、字号、文字阴影、字间距。",
"hints_text": "",
"patch": "diff --git a/common/src/main/resources/rawfile/mockdata/component-page.json b/common/src/main/resources/rawfile/mockdata/component-page.json\nindex 6af9010..5f7207f 100644\n--- a/common/src/main/resources/rawfile/mockdata/component-page.json\n+++ b/common/src/main/resources/rawfile/mockdata/component-page.json\n@@ -51,6 +51,16 @@\n \"cardImage\": \"image/component/card/text.png\",\n \"version\": 1000000,\n \"cardContents\": [\n+ {\n+ \"id\": 10,\n+ \"type\": 1,\n+ \"cardId\": 1,\n+ \"mediaType\": 1,\n+ \"mediaUrl\": \"image/component/icon/text/text.png\",\n+ \"title\": \"Text\",\n+ \"subTitle\": \"文本\",\n+ \"tagIds\": []\n+ },\n {\n \"id\": 42,\n \"type\": 1,\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets b/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\nindex ec57156..2358159 100644\n--- a/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\n@@ -100,6 +100,9 @@ import { TextPickerDialogDescriptor } from './textpickerdialogview/viewmodel/Tex\n import { TextToSpeechBuilder } from './texttospeech/component/TextToSpeechBuilder'\n import { TextToSpeechCodeGenerator } from './texttospeech/viewmodel/TextToSpeechCodeGenerator'\n import { TextToSpeechDescriptor } from './texttospeech/viewmodel/TextToSpeechDescriptor'\n+import { TextBuilder } from './textview/component/TextBuilder'\n+import { TextCodeGenerator } from './textview/viewmodel/TextCodeGenerator'\n+import { TextDescriptor } from './textview/viewmodel/TextDescriptor'\n import { ToggleBuilder } from './toggleview/component/ToggleBuilder'\n import { ToggleCodeGenerator } from './toggleview/viewmodel/ToggleCodeGenerator'\n import { ToggleDescriptor } from './toggleview/viewmodel/ToggleDescriptor'\n@@ -155,6 +158,11 @@ export const componentDetailConfig: Record<string, ConfigInterface> = {\n codeGenerate: new ProgressCodeGenerator(),\n attributeFilter: new ProgressAttributeFilter(),\n },\n+ 'Text': {\n+ previewComponentBuilder: wrapBuilder(TextBuilder),\n+ descriptor: () => new TextDescriptor(),\n+ codeGenerate: new TextCodeGenerator(),\n+ },\n 'TextArea': {\n previewComponentBuilder: wrapBuilder(TextAreaBuilder),\n descriptor: () => new TextAreaDescriptor(),\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/component/TextBuilder.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/component/TextBuilder.ets\nnew file mode 100644\nindex 0000000..58f70c8\n--- /dev/null\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/textview/component/TextBuilder.ets\n@@ -0,0 +1,24 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import type { DescriptorWrapper } from '../../../viewmodel/DescriptorWrapper';\n+import type { TextDescriptor } from '../viewmodel/TextDescriptor';\n+import { TextAttributeModifier } from '../viewmodel/TextAttributeModifier';\n+\n+@Builder\n+export function TextBuilder($$: DescriptorWrapper) {\n+ Text($r('app.string.textview_text'))\n+ .attributeModifier(new TextAttributeModifier($$.descriptor as TextDescriptor))\n+}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets\nnew file mode 100644\nindex 0000000..3eafed3\n--- /dev/null\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets\n@@ -0,0 +1,46 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { CommonColorMapping, CommonNumberMapping } from '../../common/entity/CommonMapData';\n+\n+class TextMapping {\n+ public readonly code: string;\n+ public readonly value: Length;\n+\n+ constructor(code: string, value: Length) {\n+ this.code = code;\n+ this.value = value;\n+ }\n+}\n+\n+export const fontSizeMapData: Map<string, TextMapping> = new Map([\n+ ['Default', new TextMapping('16', $r('sys.float.ohos_id_text_size_body1'))],\n+]);\n+\n+export const fontColorMapData: Map<string, CommonColorMapping> = new Map([\n+ ['Default', new CommonColorMapping('rgba(0,85,255)', 'rgba(0,85,255)')],\n+]);\n+\n+export const opacityMapData: Map<string, CommonNumberMapping> = new Map([\n+ ['Default', new CommonNumberMapping('1', 1)],\n+]);\n+\n+export const letterSpacingMapData: Map<string, CommonNumberMapping> = new Map([\n+ ['Default', new CommonNumberMapping('0', 0)],\n+]);\n+\n+export const textShadowRadiusMapData: Map<string, CommonNumberMapping> = new Map([\n+ ['Default', new CommonNumberMapping('0', 0)],\n+]);\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets\nnew file mode 100644\nindex 0000000..6b7aba8\n--- /dev/null\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets\n@@ -0,0 +1,30 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { CommonAttributeModifier } from '../../../viewmodel/CommonAttributeModifier';\n+import type { TextDescriptor } from './TextDescriptor';\n+\n+@Observed\n+export class TextAttributeModifier extends CommonAttributeModifier<TextDescriptor, TextAttribute> {\n+ applyNormalAttribute(instance: TextAttribute): void {\n+ this.assignAttribute((descriptor => descriptor.fontWeight), (val) => instance.fontWeight(val));\n+ this.assignAttribute((descriptor => descriptor.fontSize), (val) => instance.fontSize(Number(val)));\n+ this.assignAttribute((descriptor => descriptor.fontColor), (val) => instance.fontColor(val));\n+ this.assignAttribute((descriptor => descriptor.opacity), (val) => instance.opacity(val));\n+ this.assignAttribute((descriptor => descriptor.letterSpacing), (val) => instance.letterSpacing(val));\n+ this.assignAttribute((descriptor => descriptor.textShadowRadius), (val) => instance.textShadow({ radius: val,\n+ color: $r('sys.color.ohos_id_color_foreground')}));\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets\nnew file mode 100644\nindex 0000000..5c84076\n--- /dev/null\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets\n@@ -0,0 +1,75 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import type { OriginAttribute } from '../../../viewmodel/Attribute';\n+import { CommonCodeGenerator } from '../../../viewmodel/CommonCodeGenerator';\n+import { fontWeightMapData } from '../../common/entity/CommonMapData';\n+import {\n+ fontColorMapData,\n+ fontSizeMapData,\n+ letterSpacingMapData,\n+ opacityMapData,\n+ textShadowRadiusMapData,\n+} from '../entity/TextAttributeMapping';\n+\n+export class TextCodeGenerator implements CommonCodeGenerator {\n+ private fontWeight: string = fontWeightMapData.get('Default')!.code;\n+ private fontSize: string = fontSizeMapData.get('Default')!.code;\n+ private fontColor: string = fontColorMapData.get('Default')!.code;\n+ private opacity: string = opacityMapData.get('Default')!.code;\n+ private letterSpacing: string = letterSpacingMapData.get('Default')!.code;\n+ private textShadowRadius: string = textShadowRadiusMapData.get('Default')!.code;\n+\n+ public generate(attributes: OriginAttribute[]): string {\n+ const text = '开发者你好';\n+ attributes.forEach((attribute) => {\n+ switch (attribute.name) {\n+ case 'fontWeight':\n+ this.fontWeight =\n+ fontWeightMapData.get(attribute.currentValue)?.code ?? fontWeightMapData.get('Default')!.code;\n+ break;\n+ case 'fontColor':\n+ this.fontColor = attribute.currentValue;\n+ break;\n+ case 'fontSize':\n+ this.fontSize = attribute.currentValue;\n+ break;\n+ case 'opacity':\n+ this.opacity = Number(attribute.currentValue).toString();\n+ break;\n+ case 'letterSpacing':\n+ this.letterSpacing = attribute.currentValue;\n+ break;\n+ case 'textShadowRadius':\n+ this.textShadowRadius = attribute.currentValue;\n+ break;\n+ default:\n+ break;\n+ }\n+ });\n+ return `@Component\n+struct TextComponent {\n+ build() {\n+ Text('${text}')\n+ .fontSize(${this.fontSize})\n+ .fontColor('${this.fontColor}')\n+ .fontWeight(${this.fontWeight})\n+ .opacity(${this.opacity})\n+ .letterSpacing(${this.letterSpacing})\n+ .textShadow({ radius: ${this.textShadowRadius} })\n+ }\n+}`;\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets\nnew file mode 100644\nindex 0000000..770cb82\n--- /dev/null\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets\n@@ -0,0 +1,63 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import type { OriginAttribute } from '../../../viewmodel/Attribute';\n+import { CommonDescriptor } from '../../../viewmodel/CommonDescriptor';\n+import { fontWeightMapData } from '../../common/entity/CommonMapData';\n+import {\n+ fontColorMapData,\n+ fontSizeMapData,\n+ letterSpacingMapData,\n+ opacityMapData,\n+ textShadowRadiusMapData,\n+} from '../entity/TextAttributeMapping';\n+\n+@Observed\n+export class TextDescriptor extends CommonDescriptor {\n+ public fontWeight: FontWeight = fontWeightMapData.get('Default')!.value as FontWeight;\n+ public fontSize: number | string = fontSizeMapData.get('Default')!.value as number;\n+ public fontColor: ResourceColor = fontColorMapData.get('Default')!.value as string;\n+ public opacity: number = opacityMapData.get('Default')!.value as number;\n+ public letterSpacing: number = letterSpacingMapData.get('Default')!.value as number;\n+ public textShadowRadius: number = textShadowRadiusMapData.get('Default')!.value as number;\n+\n+ public convert(attributes: OriginAttribute[]): void {\n+ attributes.forEach((attribute) => {\n+ switch (attribute.name) {\n+ case 'fontWeight':\n+ this.fontWeight = (fontWeightMapData.get(attribute.currentValue)?.value ??\n+ fontWeightMapData.get('Default')!.value) as FontWeight;\n+ break;\n+ case 'fontColor':\n+ this.fontColor = attribute.currentValue;\n+ break;\n+ case 'fontSize':\n+ this.fontSize = Number(attribute.currentValue);\n+ break;\n+ case 'opacity':\n+ this.opacity = Number(attribute.currentValue);\n+ break;\n+ case 'letterSpacing':\n+ this.letterSpacing = Number(attribute.currentValue);\n+ break;\n+ case 'textShadowRadius':\n+ this.textShadowRadius = Number(attribute.currentValue);\n+ break;\n+ default:\n+ break;\n+ }\n+ });\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/resources/base/element/string.json b/features/componentlibrary/src/main/resources/base/element/string.json\nindex f0dea6e..9492418 100644\n--- a/features/componentlibrary/src/main/resources/base/element/string.json\n+++ b/features/componentlibrary/src/main/resources/base/element/string.json\n@@ -28,6 +28,10 @@\n \"name\": \"text_placeholder\",\n \"value\": \"Please enter text.\"\n },\n+ {\n+ \"name\": \"textview_text\",\n+ \"value\": \"Hello, Developer\"\n+ },\n {\n \"name\": \"textarea_text\",\n \"value\": \"I have a cute teddy bear. It's quite chubby, so fat that its belly looks like it's about to burst! The clothes it wears are beautiful, and the clothes are colorful, with purple, pink, and yellow, very beautiful!\"\ndiff --git a/features/componentlibrary/src/main/resources/en_US/element/string.json b/features/componentlibrary/src/main/resources/en_US/element/string.json\nindex 9f7ef5d..d0ed39c 100644\n--- a/features/componentlibrary/src/main/resources/en_US/element/string.json\n+++ b/features/componentlibrary/src/main/resources/en_US/element/string.json\n@@ -28,6 +28,10 @@\n \"name\": \"text_placeholder\",\n \"value\": \"Please enter text.\"\n },\n+ {\n+ \"name\": \"textview_text\",\n+ \"value\": \"Hello, Developer\"\n+ },\n {\n \"name\": \"camera_picker_button\",\n \"value\": \"Safe Use of Cameras\"\ndiff --git a/features/componentlibrary/src/main/resources/zh_CN/element/string.json b/features/componentlibrary/src/main/resources/zh_CN/element/string.json\nindex 5d16b8d..3483e31 100644\n--- a/features/componentlibrary/src/main/resources/zh_CN/element/string.json\n+++ b/features/componentlibrary/src/main/resources/zh_CN/element/string.json\n@@ -28,6 +28,10 @@\n \"name\": \"text_placeholder\",\n \"value\": \"请输入文字\"\n },\n+ {\n+ \"name\": \"textview_text\",\n+ \"value\": \"开发者你好\"\n+ },\n {\n \"name\": \"textarea_text\",\n \"value\": \"我有一只可爱的玩具熊。它长得很胖,胖得肚子都要爆炸了!它穿的衣服都很漂亮,而且衣服上五颜六色,有紫的、有粉的、还有黄的,非常漂亮!\"\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "medium",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_005",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "e153711f",
"problem_statement": "【需求描述】:删除首页组件库中文本Text组件中的调整字间距的功能",
"hints_text": "",
"patch": "diff --git a/common/src/main/resources/rawfile/mockdata/file-data.json b/common/src/main/resources/rawfile/mockdata/file-data.json\nindex ef290dc..0f04e33 100644\n--- a/common/src/main/resources/rawfile/mockdata/file-data.json\n+++ b/common/src/main/resources/rawfile/mockdata/file-data.json\n@@ -343,13 +343,6 @@\n \"defaultProperty\": \"0\",\n \"propertyValues\": \"{ \\\"left\\\":0, \\\"right\\\":20, \\\"step\\\": 1 }\"\n },\n- {\n- \"propertyName\": \"letterSpacing\",\n- \"propertyDesc\": \"字间距\",\n- \"displayType\": \"number\",\n- \"defaultProperty\": \"0\",\n- \"propertyValues\": \"{ \\\"left\\\":0, \\\"right\\\":20, \\\"step\\\": 1 }\"\n- },\n {\n \"propertyName\": \"fontColor\",\n \"propertyDesc\": \"颜色\",\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets\nindex 3eafed3..a2a9546 100644\n--- a/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets\n@@ -37,10 +37,6 @@ export const opacityMapData: Map<string, CommonNumberMapping> = new Map([\n ['Default', new CommonNumberMapping('1', 1)],\n ]);\n \n-export const letterSpacingMapData: Map<string, CommonNumberMapping> = new Map([\n- ['Default', new CommonNumberMapping('0', 0)],\n-]);\n-\n export const textShadowRadiusMapData: Map<string, CommonNumberMapping> = new Map([\n ['Default', new CommonNumberMapping('0', 0)],\n ]);\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets\nindex 6b7aba8..55ae805 100644\n--- a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets\n@@ -23,7 +23,6 @@ export class TextAttributeModifier extends CommonAttributeModifier<TextDescripto\n this.assignAttribute((descriptor => descriptor.fontSize), (val) => instance.fontSize(Number(val)));\n this.assignAttribute((descriptor => descriptor.fontColor), (val) => instance.fontColor(val));\n this.assignAttribute((descriptor => descriptor.opacity), (val) => instance.opacity(val));\n- this.assignAttribute((descriptor => descriptor.letterSpacing), (val) => instance.letterSpacing(val));\n this.assignAttribute((descriptor => descriptor.textShadowRadius), (val) => instance.textShadow({ radius: val,\n color: $r('sys.color.ohos_id_color_foreground')}));\n }\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets\nindex 5c84076..15d30a5 100644\n--- a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets\n@@ -19,7 +19,6 @@ import { fontWeightMapData } from '../../common/entity/CommonMapData';\n import {\n fontColorMapData,\n fontSizeMapData,\n- letterSpacingMapData,\n opacityMapData,\n textShadowRadiusMapData,\n } from '../entity/TextAttributeMapping';\n@@ -29,7 +28,6 @@ export class TextCodeGenerator implements CommonCodeGenerator {\n private fontSize: string = fontSizeMapData.get('Default')!.code;\n private fontColor: string = fontColorMapData.get('Default')!.code;\n private opacity: string = opacityMapData.get('Default')!.code;\n- private letterSpacing: string = letterSpacingMapData.get('Default')!.code;\n private textShadowRadius: string = textShadowRadiusMapData.get('Default')!.code;\n \n public generate(attributes: OriginAttribute[]): string {\n@@ -49,9 +47,6 @@ export class TextCodeGenerator implements CommonCodeGenerator {\n case 'opacity':\n this.opacity = Number(attribute.currentValue).toString();\n break;\n- case 'letterSpacing':\n- this.letterSpacing = attribute.currentValue;\n- break;\n case 'textShadowRadius':\n this.textShadowRadius = attribute.currentValue;\n break;\n@@ -67,7 +62,6 @@ struct TextComponent {\n .fontColor('${this.fontColor}')\n .fontWeight(${this.fontWeight})\n .opacity(${this.opacity})\n- .letterSpacing(${this.letterSpacing})\n .textShadow({ radius: ${this.textShadowRadius} })\n }\n }`;\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets\nindex 770cb82..01158f3 100644\n--- a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets\n@@ -19,7 +19,6 @@ import { fontWeightMapData } from '../../common/entity/CommonMapData';\n import {\n fontColorMapData,\n fontSizeMapData,\n- letterSpacingMapData,\n opacityMapData,\n textShadowRadiusMapData,\n } from '../entity/TextAttributeMapping';\n@@ -30,7 +29,6 @@ export class TextDescriptor extends CommonDescriptor {\n public fontSize: number | string = fontSizeMapData.get('Default')!.value as number;\n public fontColor: ResourceColor = fontColorMapData.get('Default')!.value as string;\n public opacity: number = opacityMapData.get('Default')!.value as number;\n- public letterSpacing: number = letterSpacingMapData.get('Default')!.value as number;\n public textShadowRadius: number = textShadowRadiusMapData.get('Default')!.value as number;\n \n public convert(attributes: OriginAttribute[]): void {\n@@ -49,9 +47,6 @@ export class TextDescriptor extends CommonDescriptor {\n case 'opacity':\n this.opacity = Number(attribute.currentValue);\n break;\n- case 'letterSpacing':\n- this.letterSpacing = Number(attribute.currentValue);\n- break;\n case 'textShadowRadius':\n this.textShadowRadius = Number(attribute.currentValue);\n break;\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_006",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "376fedfc",
"problem_statement": "【需求描述】:添加首页下方组件中的文本Text组件中的字间距功能,通过滑块横向滑动调节字间距大小,可以调整预览区域的字间距",
"hints_text": "",
"patch": "diff --git b/common/src/main/resources/rawfile/mockdata/file-data.json a/common/src/main/resources/rawfile/mockdata/file-data.json\nindex 0f04e33..ef290dc 100644\n--- b/common/src/main/resources/rawfile/mockdata/file-data.json\n+++ a/common/src/main/resources/rawfile/mockdata/file-data.json\n@@ -343,6 +343,13 @@\n \"defaultProperty\": \"0\",\n \"propertyValues\": \"{ \\\"left\\\":0, \\\"right\\\":20, \\\"step\\\": 1 }\"\n },\n+ {\n+ \"propertyName\": \"letterSpacing\",\n+ \"propertyDesc\": \"字间距\",\n+ \"displayType\": \"number\",\n+ \"defaultProperty\": \"0\",\n+ \"propertyValues\": \"{ \\\"left\\\":0, \\\"right\\\":20, \\\"step\\\": 1 }\"\n+ },\n {\n \"propertyName\": \"fontColor\",\n \"propertyDesc\": \"颜色\",\ndiff --git b/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets a/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets\nindex a2a9546..3eafed3 100644\n--- b/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets\n+++ a/features/componentlibrary/src/main/ets/componentdetailview/textview/entity/TextAttributeMapping.ets\n@@ -37,6 +37,10 @@ export const opacityMapData: Map<string, CommonNumberMapping> = new Map([\n ['Default', new CommonNumberMapping('1', 1)],\n ]);\n \n+export const letterSpacingMapData: Map<string, CommonNumberMapping> = new Map([\n+ ['Default', new CommonNumberMapping('0', 0)],\n+]);\n+\n export const textShadowRadiusMapData: Map<string, CommonNumberMapping> = new Map([\n ['Default', new CommonNumberMapping('0', 0)],\n ]);\n\\ No newline at end of file\ndiff --git b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets\nindex 55ae805..6b7aba8 100644\n--- b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets\n+++ a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextAttributeModifier.ets\n@@ -23,6 +23,7 @@ export class TextAttributeModifier extends CommonAttributeModifier<TextDescripto\n this.assignAttribute((descriptor => descriptor.fontSize), (val) => instance.fontSize(Number(val)));\n this.assignAttribute((descriptor => descriptor.fontColor), (val) => instance.fontColor(val));\n this.assignAttribute((descriptor => descriptor.opacity), (val) => instance.opacity(val));\n+ this.assignAttribute((descriptor => descriptor.letterSpacing), (val) => instance.letterSpacing(val));\n this.assignAttribute((descriptor => descriptor.textShadowRadius), (val) => instance.textShadow({ radius: val,\n color: $r('sys.color.ohos_id_color_foreground')}));\n }\ndiff --git b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets\nindex 15d30a5..5c84076 100644\n--- b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets\n+++ a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextCodeGenerator.ets\n@@ -19,6 +19,7 @@ import { fontWeightMapData } from '../../common/entity/CommonMapData';\n import {\n fontColorMapData,\n fontSizeMapData,\n+ letterSpacingMapData,\n opacityMapData,\n textShadowRadiusMapData,\n } from '../entity/TextAttributeMapping';\n@@ -28,6 +29,7 @@ export class TextCodeGenerator implements CommonCodeGenerator {\n private fontSize: string = fontSizeMapData.get('Default')!.code;\n private fontColor: string = fontColorMapData.get('Default')!.code;\n private opacity: string = opacityMapData.get('Default')!.code;\n+ private letterSpacing: string = letterSpacingMapData.get('Default')!.code;\n private textShadowRadius: string = textShadowRadiusMapData.get('Default')!.code;\n \n public generate(attributes: OriginAttribute[]): string {\n@@ -47,6 +49,9 @@ export class TextCodeGenerator implements CommonCodeGenerator {\n case 'opacity':\n this.opacity = Number(attribute.currentValue).toString();\n break;\n+ case 'letterSpacing':\n+ this.letterSpacing = attribute.currentValue;\n+ break;\n case 'textShadowRadius':\n this.textShadowRadius = attribute.currentValue;\n break;\n@@ -62,6 +67,7 @@ struct TextComponent {\n .fontColor('${this.fontColor}')\n .fontWeight(${this.fontWeight})\n .opacity(${this.opacity})\n+ .letterSpacing(${this.letterSpacing})\n .textShadow({ radius: ${this.textShadowRadius} })\n }\n }`;\ndiff --git b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets\nindex 01158f3..770cb82 100644\n--- b/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets\n+++ a/features/componentlibrary/src/main/ets/componentdetailview/textview/viewmodel/TextDescriptor.ets\n@@ -19,6 +19,7 @@ import { fontWeightMapData } from '../../common/entity/CommonMapData';\n import {\n fontColorMapData,\n fontSizeMapData,\n+ letterSpacingMapData,\n opacityMapData,\n textShadowRadiusMapData,\n } from '../entity/TextAttributeMapping';\n@@ -29,6 +30,7 @@ export class TextDescriptor extends CommonDescriptor {\n public fontSize: number | string = fontSizeMapData.get('Default')!.value as number;\n public fontColor: ResourceColor = fontColorMapData.get('Default')!.value as string;\n public opacity: number = opacityMapData.get('Default')!.value as number;\n+ public letterSpacing: number = letterSpacingMapData.get('Default')!.value as number;\n public textShadowRadius: number = textShadowRadiusMapData.get('Default')!.value as number;\n \n public convert(attributes: OriginAttribute[]): void {\n@@ -47,6 +49,9 @@ export class TextDescriptor extends CommonDescriptor {\n case 'opacity':\n this.opacity = Number(attribute.currentValue);\n break;\n+ case 'letterSpacing':\n+ this.letterSpacing = Number(attribute.currentValue);\n+ break;\n case 'textShadowRadius':\n this.textShadowRadius = Number(attribute.currentValue);\n break;\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_007",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "10639a96",
"problem_statement": "【需求描述】:删除首页底部组件中的AI抠图组件,包含代码、引用和资源文件",
"hints_text": "",
"patch": "diff --git a/common/src/main/resources/rawfile/mockdata/component-page.json b/common/src/main/resources/rawfile/mockdata/component-page.json\nindex 5f7207f..777028b 100644\n--- a/common/src/main/resources/rawfile/mockdata/component-page.json\n+++ b/common/src/main/resources/rawfile/mockdata/component-page.json\n@@ -329,27 +329,6 @@\n }\n ]\n },\n- {\n- \"id\": 12,\n- \"cardTitle\": \"AI抠图\",\n- \"cardSubTitle\": \"开箱即用的AI能力\",\n- \"cardType\": 1,\n- \"cardStyleType\": 3,\n- \"cardImage\": \"image/component/card/enable_analyzer.png\",\n- \"version\": 1000000,\n- \"cardContents\": [\n- {\n- \"id\": 32,\n- \"type\": 1,\n- \"cardId\": 12,\n- \"mediaType\": 1,\n- \"mediaUrl\": \"image/component/icon/enable_analyzer.png\",\n- \"title\": \"AI Matting\",\n- \"subTitle\": \"AI抠图\",\n- \"tagIds\": []\n- }\n- ]\n- },\n {\n \"id\": 9,\n \"cardTitle\": \"给页面添加弹窗\",\ndiff --git a/common/src/main/resources/rawfile/mockdata/file-data.json b/common/src/main/resources/rawfile/mockdata/file-data.json\nindex ef290dc..cb88d4b 100644\n--- a/common/src/main/resources/rawfile/mockdata/file-data.json\n+++ b/common/src/main/resources/rawfile/mockdata/file-data.json\n@@ -953,19 +953,6 @@\n }\n ]\n },\n- {\n- \"id\": 32,\n- \"componentName\": \"AI Matting\",\n- \"subTitle\": \"AI抠图\",\n- \"componentType\": 1,\n- \"props\": [],\n- \"recommendList\": [\n- {\n- \"articleType\": 1,\n- \"url\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-image#draggable9\"\n- }\n- ]\n- },\n {\n \"id\": 33,\n \"componentName\": \"ActionSheet\",\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets b/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\nindex 2358159..7cb5a56 100644\n--- a/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\n@@ -47,8 +47,6 @@ import { GridDescriptor } from './grid/viewmodel/GridDescriptor'\n import { ImageBuilder } from './Image/component/ImageBuilder'\n import { ImageCodeGenerator } from './Image/viewmodel/ImageCodeGenerator'\n import { ImageDescriptor } from './Image/viewmodel/ImageDescriptor'\n-import { AIImageBuilder } from './imageaianalyzer/component/AIImageBuilder'\n-import { AIImageCodeGenerator } from './imageaianalyzer/viewmodel/AIImageCodeGenerator'\n import { ListBuilder } from './list/component/ListBuilder'\n import { ListCodeGenerator } from './list/viewmodel/ListCodeGenerator'\n import { ListDescriptor } from './list/viewmodel/ListDescriptor'\n@@ -293,11 +291,6 @@ export const componentDetailConfig: Record<string, ConfigInterface> = {\n descriptor: () => new CommonDescriptor(),\n codeGenerate: new PhotoViewPickerCodeGenerator(),\n },\n- 'AI Matting': {\n- previewComponentBuilder: wrapBuilder(AIImageBuilder),\n- descriptor: () => new CommonDescriptor(),\n- codeGenerate: new AIImageCodeGenerator(),\n- },\n }\n \n export interface ConfigInterface {\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/imageaianalyzer/component/AIImageBuilder.ets b/features/componentlibrary/src/main/ets/componentdetailview/imageaianalyzer/component/AIImageBuilder.ets\ndeleted file mode 100644\nindex 27f45c9..0000000\n--- a/features/componentlibrary/src/main/ets/componentdetailview/imageaianalyzer/component/AIImageBuilder.ets\n+++ /dev/null\n@@ -1,22 +0,0 @@\n-/*\n- * Copyright (c) 2024 Huawei Device Co., Ltd.\n- * Licensed under the Apache License, Version 2.0 (the \"License\");\n- * you may not use this file except in compliance with the License.\n- * You may obtain a copy of the License at\n- *\n- * http://www.apache.org/licenses/LICENSE-2.0\n- *\n- * Unless required by applicable law or agreed to in writing, software\n- * distributed under the License is distributed on an \"AS IS\" BASIS,\n- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n- * See the License for the specific language governing permissions and\n- * limitations under the License.\n- */\n-\n-import type { DescriptorWrapper } from '../../../viewmodel/DescriptorWrapper';\n-import { AIImageComponent } from './AIImageComponent';\n-\n-@Builder\n-export function AIImageBuilder($$: DescriptorWrapper) {\n- AIImageComponent()\n-}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/imageaianalyzer/component/AIImageComponent.ets b/features/componentlibrary/src/main/ets/componentdetailview/imageaianalyzer/component/AIImageComponent.ets\ndeleted file mode 100644\nindex 7298d63..0000000\n--- a/features/componentlibrary/src/main/ets/componentdetailview/imageaianalyzer/component/AIImageComponent.ets\n+++ /dev/null\n@@ -1,132 +0,0 @@\n-/*\n- * Copyright (c) 2024 Huawei Device Co., Ltd.\n- * Licensed under the Apache License, Version 2.0 (the \"License\");\n- * you may not use this file except in compliance with the License.\n- * You may obtain a copy of the License at\n- *\n- * http://www.apache.org/licenses/LICENSE-2.0\n- *\n- * Unless required by applicable law or agreed to in writing, software\n- * distributed under the License is distributed on an \"AS IS\" BASIS,\n- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n- * See the License for the specific language governing permissions and\n- * limitations under the License.\n- */\n-\n-import { Popup } from '@kit.ArkUI';\n-import { BusinessError } from '@kit.BasicServicesKit';\n-import { image } from '@kit.ImageKit';\n-import { GlobalInfoModel, Logger, PreferenceManager, StorageKey } from '@ohos/common';\n-import { DetailPageConstant } from '../../../constant/DetailPageConstant';\n-import { CommonStorageKey } from '../../common/entity/CommonStorageKey';\n-\n-const TAG: string = '[AIImageComponent]';\n-\n-@Component\n-export struct AIImageComponent {\n- @StorageProp(StorageKey.GLOBAL_INFO) globalInfoModel: GlobalInfoModel = AppStorage.get(StorageKey.GLOBAL_INFO)!;\n- @State imagePixelMap?: image.PixelMap = undefined;\n- @State showPopup: boolean = true;\n- @State imageWidth: number = 0;\n- @State imageHeight: number = 0;\n-\n- async aboutToAppear() {\n- this.showPopup = PreferenceManager.getInstance().getValue<boolean>(CommonStorageKey.KEY_MATTING_TIP) ?? true;\n- this.imagePixelMap = await this.getPixmapFromMedia($r('app.media.image_ai'));\n- }\n-\n- aboutToDisappear(): void {\n- this.imagePixelMap?.release();\n- }\n-\n- @Builder\n- MyPopup() {\n- Row() {\n- Popup({\n- title: {\n- text: $r('app.string.aiMatting'),\n- },\n- message: {\n- text: $r('app.string.aiMatting_tip')\n- },\n- showClose: true,\n- onClose: () => {\n- this.showPopup = false;\n- },\n- buttons: [\n- {\n- text: $r('app.string.confirmTip'),\n- action: () => {\n- this.showPopup = false;\n- },\n- },\n- {\n- text: $r('app.string.cancelTip'),\n- action: () => {\n- PreferenceManager.getInstance().setValue(CommonStorageKey.KEY_MATTING_TIP, false);\n- this.showPopup = false;\n- },\n- }\n- ],\n- })\n- }\n- .onKeyPreIme((keyEvent: KeyEvent) => {\n- if ((keyEvent?.keyText === 'KEYCODE_DPAD_RIGHT' || keyEvent?.keyText === 'KEYCODE_DPAD_LEFT') &&\n- keyEvent.type === KeyType.Down) {\n- return true;\n- }\n- return false;\n- })\n- }\n-\n- build() {\n- Stack({ alignContent: Alignment.Center }) {\n- Image(this.imagePixelMap ?? $r('app.media.image_ai'))\n- .enableAnalyzer(true)\n- .width(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_SM ? '100%' : '90%')\n- .height(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_SM ? '100%' : this.imageHeight)\n- .objectFit(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_SM ? ImageFit.Fill : ImageFit.Contain)\n- .borderRadius($r('sys.float.corner_radius_level8'))\n- .draggable(false)\n- .onAreaChange((_oldValue: Area, newValue: Area) => {\n- this.imageWidth = newValue.width as number;\n- this.imageHeight = this.imageWidth * 0.56 as number;\n- })\n- .bindPopup(this.showPopup, {\n- builder: this.MyPopup(),\n- width: $r('app.float.popup_width_large'),\n- backgroundBlurStyle: BlurStyle.COMPONENT_ULTRA_THICK,\n- radius: ($r('sys.float.corner_radius_level4')),\n- offset: { y: DetailPageConstant.IMAGE_POPUP_OFFSET_Y },\n- placement: Placement.Bottom,\n- showInSubWindow: true,\n- onStateChange: (event) => {\n- if (!event.isVisible) {\n- this.showPopup = false;\n- }\n- },\n- focusable: true,\n- })\n- }\n- .width('100%')\n- .height('100%')\n- }\n-\n- private async getPixmapFromMedia(resource: Resource) {\n- let createPixelMap: image.PixelMap;\n- try {\n- const unit8Array = await this.getUIContext().getHostContext()!.resourceManager?.getMediaContent(resource.id);\n- const imageSource = image.createImageSource(unit8Array.buffer.slice(0, unit8Array.buffer.byteLength));\n- createPixelMap = await imageSource.createPixelMap({\n- desiredPixelFormat: image.PixelMapFormat.RGBA_8888,\n- });\n- await imageSource.release();\n- this.imagePixelMap?.release();\n- } catch (err) {\n- const error: BusinessError = err as BusinessError;\n- Logger.error(TAG, `Get pixmapFromMedia error, the code is ${error.code}, the message is ${error.message}`);\n- return;\n- }\n- return createPixelMap;\n- }\n-}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/imageaianalyzer/viewmodel/AIImageCodeGenerator.ets b/features/componentlibrary/src/main/ets/componentdetailview/imageaianalyzer/viewmodel/AIImageCodeGenerator.ets\ndeleted file mode 100644\nindex 34c7415..0000000\n--- a/features/componentlibrary/src/main/ets/componentdetailview/imageaianalyzer/viewmodel/AIImageCodeGenerator.ets\n+++ /dev/null\n@@ -1,76 +0,0 @@\n-/*\n- * Copyright (c) 2024 Huawei Device Co., Ltd.\n- * Licensed under the Apache License, Version 2.0 (the \"License\");\n- * you may not use this file except in compliance with the License.\n- * You may obtain a copy of the License at\n- *\n- * http://www.apache.org/licenses/LICENSE-2.0\n- *\n- * Unless required by applicable law or agreed to in writing, software\n- * distributed under the License is distributed on an \"AS IS\" BASIS,\n- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n- * See the License for the specific language governing permissions and\n- * limitations under the License.\n- */\n-\n-import type { OriginAttribute } from '../../../viewmodel/Attribute';\n-import { CommonCodeGenerator } from '../../../viewmodel/CommonCodeGenerator';\n-\n-export class AIImageCodeGenerator implements CommonCodeGenerator {\n- public generate(_attributes: OriginAttribute[]): string {\n- return `import { image } from '@kit.ImageKit';\n-import type { BusinessError } from '@kit.BasicServicesKit';\n-\n-@Component\n-export struct AIImageComponent {\n- @State imagePixelMap?: image.PixelMap = undefined;\n-\n- async aboutToAppear() {\n- // 图片资源替换项目src/main/resources/base/media路径下资源\n- this.imagePixelMap = await this.getPixmapFromMedia($r(\"app.media.image_ai\"));\n- }\n-\n- aboutToDisappear(): void {\n- this.imagePixelMap?.release();\n- }\n-\n- build() {\n- Column() {\n- Stack({ alignContent: Alignment.Center }) {\n- // 图片资源替换项目src/main/resources/base/media路径下资源\n- Image(this.imagePixelMap ?? $r(\"app.media.image_ai\"))\n- .enableAnalyzer(true)\n- .width('100%')\n- .height('100%')\n- .objectFit(ImageFit.Contain)\n- .borderRadius($r('sys.float.corner_radius_level8'))\n- .draggable(false)\n- }\n- .width('80%')\n- }\n- .justifyContent(FlexAlign.Center)\n- .alignItems(HorizontalAlign.Center)\n- .width('100%')\n- .height('100%')\n- }\n-\n- private async getPixmapFromMedia(resource: Resource) {\n- let createPixelMap: image.PixelMap;\n- try {\n- const unit8Array = await this.getUIContext().getHostContext()!.resourceManager?.getMediaContent(resource.id);\n- const imageSource = image.createImageSource(unit8Array.buffer.slice(0, unit8Array.buffer.byteLength));\n- createPixelMap = await imageSource.createPixelMap({\n- desiredPixelFormat: image.PixelMapFormat.RGBA_8888,\n- });\n- await imageSource.release();\n- this.imagePixelMap?.release();\n- } catch (err) {\n- const error: BusinessError = err as BusinessError;\n- console.error(\\`Get pixmapFromMedia error, the code is \\${error.code}, the message is \\${error.message}\\`);\n- return;\n- }\n- return createPixelMap;\n- }\n-}`\n- }\n-}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/resources/base/element/string.json b/features/componentlibrary/src/main/resources/base/element/string.json\nindex 9492418..510625f 100644\n--- a/features/componentlibrary/src/main/resources/base/element/string.json\n+++ b/features/componentlibrary/src/main/resources/base/element/string.json\n@@ -124,14 +124,6 @@\n \"name\": \"hexagon\",\n \"value\": \"hexagon\"\n },\n- {\n- \"name\": \"aiMatting\",\n- \"value\": \"AIMatting\"\n- },\n- {\n- \"name\": \"aiMatting_tip\",\n- \"value\": \"Long press the object in the picture to use the AI function to automatically cut out the picture, come and experience it!\"\n- },\n {\n \"name\": \"alert_dialog_tip\",\n \"value\": \"Click Alert Dialog\"\ndiff --git a/features/componentlibrary/src/main/resources/en_US/element/string.json b/features/componentlibrary/src/main/resources/en_US/element/string.json\nindex d0ed39c..5af1c3f 100644\n--- a/features/componentlibrary/src/main/resources/en_US/element/string.json\n+++ b/features/componentlibrary/src/main/resources/en_US/element/string.json\n@@ -120,13 +120,6 @@\n {\n \"name\": \"hexagon\",\n \"value\": \"hexagon\"\n- },{\n- \"name\": \"aiMatting\",\n- \"value\": \"AIMatting\"\n- },\n- {\n- \"name\": \"aiMatting_tip\",\n- \"value\": \"Long press the object in the picture to use the AI function to automatically cut out the picture, come and experience it!\"\n },\n {\n \"name\": \"alert_dialog_tip\",\ndiff --git a/features/componentlibrary/src/main/resources/zh_CN/element/string.json b/features/componentlibrary/src/main/resources/zh_CN/element/string.json\nindex 3483e31..313fb0d 100644\n--- a/features/componentlibrary/src/main/resources/zh_CN/element/string.json\n+++ b/features/componentlibrary/src/main/resources/zh_CN/element/string.json\n@@ -124,14 +124,6 @@\n \"name\": \"hexagon\",\n \"value\": \"六边形\"\n },\n- {\n- \"name\": \"aiMatting\",\n- \"value\": \"AI抠图\"\n- },\n- {\n- \"name\": \"aiMatting_tip\",\n- \"value\": \"长按图片中物体可使用AI功能自动抠图,快来体验吧!\"\n- },\n {\n \"name\": \"alert_dialog_tip\",\n \"value\": \"点击警告弹窗\"\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_008",
"repo": "internal_green/HMOSWorldClient",
"base_commit": "9d0e4ce3",
"problem_statement": "HMOS代码工坊新增服务卡片, 需求描述:在“HMOS代码工坊”应用中新增原子化服务卡片,支持用户通过桌面快捷交互获取“最佳实践”文章推荐。入口逻辑:用户长按桌面图标 -> 弹出快捷菜单 (Shortcut Menu) -> 点击“服务卡片” -> 跳转至卡片选择界面 -> 添加“最佳实践文章抢先看”卡片。\n\n交互逻辑:\n\n卡片需支持横向滑动 。\n\n初始状态:显示第 1 个卡片。\n\n交互动作:支持向左滑动手势切换至第 2 个卡片。\n\nUI 规范:第 2 个卡片标题必须固定显示为:“HMOS代码工坊:最佳实践文章抢先看”。",
"hints_text": "",
"patch": "diff --git a/common/Index.ets b/common/Index.ets\nindex d3eff651..131905e8 100644\n--- a/common/Index.ets\n+++ b/common/Index.ets\n@@ -108,4 +108,6 @@ export { AgreementBasicInfo, AgreementName, AgreementType } from './src/main/ets\n \n export { AgreementContentPage } from './src/main/ets/agreementservice/page/AgreementContentPage';\n \n-export { AgreementServiceConstant } from './src/main/ets/agreementservice/constant/AgreementServiceConstant';\n\\ No newline at end of file\n+export { AgreementServiceConstant } from './src/main/ets/agreementservice/constant/AgreementServiceConstant';\n+\n+export { ArticleListItem } from './src/main/ets/model/ArticleListItem';\n\\ No newline at end of file\ndiff --git a/common/src/main/ets/model/ArticleListItem.ets b/common/src/main/ets/model/ArticleListItem.ets\nnew file mode 100644\nindex 00000000..49580cca\n--- /dev/null\n+++ b/common/src/main/ets/model/ArticleListItem.ets\n@@ -0,0 +1,22 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the License);\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an AS IS BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+export class ArticleListItem {\n+ public title: string = '';\n+ public id: number = 0;\n+ public isArticle?: boolean = true;\n+ public detailsUrl: string = '';\n+ public name: string = '';\n+}\n\\ No newline at end of file\ndiff --git a/common/src/main/ets/util/PullUpManager.ets b/common/src/main/ets/util/PullUpManager.ets\nindex 1caad549..b22d6b45 100644\n--- a/common/src/main/ets/util/PullUpManager.ets\n+++ b/common/src/main/ets/util/PullUpManager.ets\n@@ -15,6 +15,7 @@\n \n import { Want } from '@kit.AbilityKit';\n import { StorageKey } from '../constant/CommonEnums';\n+import { ArticleListItem } from '../model/ArticleListItem';\n import { PageContext } from '../routermanager/PageContext';\n import Logger from './Logger';\n \n@@ -34,6 +35,14 @@ export class PullUpManager {\n if (PullUpManager.isShortCutPullUp(want)) {\n AppStorage.setOrCreate<WantParams>(StorageKey.WANT_PARAMETERS, want.parameters);\n PullUpManager.navigationToHome();\n+ } else if (PullUpManager.isArticleServiceCard(want)) {\n+ try {\n+ AppStorage.setOrCreate<WantParams>(StorageKey.WANT_PARAMETERS,\n+ JSON.parse(want.parameters?.['params'] as string));\n+ } catch (error) {\n+ Logger.error(TAG, `Parse fail, cause: ${error}`)\n+ }\n+ PullUpManager.navigationToHome();\n }\n }\n \n@@ -56,16 +65,29 @@ export class PullUpManager {\n return false;\n }\n \n+ private static isArticleServiceCard(want: Want): boolean {\n+ if (want.parameters && want.parameters?.['formId']) {\n+ const articleServiceWantParams: WantParams = JSON.parse(want.parameters['params'] as string);\n+ Logger.info(TAG, want.parameters['params']);\n+ const isFromArticleServiceCard: string =\n+ Reflect.get(articleServiceWantParams, 'isFromArticleServiceCard') as string;\n+ return isFromArticleServiceCard === 'true';\n+ }\n+ return false;\n+ }\n+\n private static navigationToHome(): void {\n const pageContext: PageContext | undefined = AppStorage.get(StorageKey.HOME_PAGE_CONTEXT);\n const componentPageContext: PageContext | undefined = AppStorage.get(StorageKey.COMPONENT_PAGE_CONTEXT);\n const samplePageContext: PageContext | undefined = AppStorage.get(StorageKey.SAMPLE_PAGE_CONTEXT);\n const explorationPageContext: PageContext | undefined = AppStorage.get(StorageKey.EXPLORATION_PAGE_CONTEXT);\n+ const minePageContext: PageContext | undefined = AppStorage.get(StorageKey.MINE_PAGE_CONTEXT);\n pageContext?.popPageByIndex(0);\n // Adapt the PC situation.\n componentPageContext?.clear();\n samplePageContext?.clear();\n explorationPageContext?.clear();\n+ minePageContext?.clear();\n }\n }\n \n@@ -75,4 +97,10 @@ export class WantParams {\n */\n public shortCutKey?: string = '';\n public isFromShortCut?: string = '';\n+ /**\n+ * Service Card.\n+ */\n+ public formId?: string;\n+ public isFromArticleServiceCard?: string;\n+ public articleInfo?: ArticleListItem;\n }\n\\ No newline at end of file\ndiff --git a/products/phone/obfuscation-rules.txt b/products/phone/obfuscation-rules.txt\nindex ae15d770..12e973a3 100644\n--- a/products/phone/obfuscation-rules.txt\n+++ b/products/phone/obfuscation-rules.txt\n@@ -23,4 +23,8 @@\n \n # white list for PenKit Context file\n -keep\n-./src/main/ets/util/ContextConfig.ts\n\\ No newline at end of file\n+./src/main/ets/util/ContextConfig.ts\n+\n+-keep-property-name\n+articleInfo\n+isFromArticleServiceCard\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/ets/entryability/EntryAbility.ets b/products/phone/src/main/ets/entryability/EntryAbility.ets\nindex 7be53827..0302f966 100644\n--- a/products/phone/src/main/ets/entryability/EntryAbility.ets\n+++ b/products/phone/src/main/ets/entryability/EntryAbility.ets\n@@ -29,12 +29,16 @@ import {\n WindowUtil,\n } from '@ohos/common';\n import GlobalUIAbilityContext from '../util/ContextConfig';\n+import { UpdateFormData } from '../util/UpdateFormData';\n \n const TAG = '[EntryAbility]';\n \n export default class EntryAbility extends UIAbility {\n onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {\n Logger.info(TAG, `Ability onCreate launchReason: ${launchParam.launchReason}`);\n+ if (want.parameters?.['formId'] && want.parameters?.['params']) {\n+ UpdateFormData.update(want.parameters?.['formId'] as string);\n+ }\n PullUpManager.pullUpApp(want);\n AppStorage.setOrCreate(StorageKey.COLOR_MODE, this.context.config.colorMode);\n AppStorage.setOrCreate(StorageKey.LANGUAGE, this.context.config.language);\n@@ -47,6 +51,9 @@ export default class EntryAbility extends UIAbility {\n \n onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {\n Logger.info(TAG, `onNewWant launchReason: ${launchParam.launchReason}`);\n+ if (want.parameters?.['formId'] && want.parameters?.['params']) {\n+ UpdateFormData.update(want.parameters?.['formId'] as string);\n+ }\n PullUpManager.pullUpApp(want);\n }\n \ndiff --git a/products/phone/src/main/ets/phoneformability/PhoneFormAbility.ets b/products/phone/src/main/ets/phoneformability/PhoneFormAbility.ets\nindex 31c8c13a..fe062391 100644\n--- a/products/phone/src/main/ets/phoneformability/PhoneFormAbility.ets\n+++ b/products/phone/src/main/ets/phoneformability/PhoneFormAbility.ets\n@@ -15,12 +15,23 @@\n \n import type { Want } from '@kit.AbilityKit';\n import { formBindingData, FormExtensionAbility, formInfo } from '@kit.FormKit';\n+import { Logger } from '@ohos/common';\n+import { UpdateFormData } from '../util/UpdateFormData';\n+\n+const TAG: string = '[PhoneFormAbility]';\n \n export default class PhoneFormAbility extends FormExtensionAbility {\n onAddForm(want: Want) {\n- // Called to return a FormBindingData object.\n- const formData = '';\n- return formBindingData.createFormBindingData(formData);\n+ if (!want || !want.parameters) {\n+ Logger.error(TAG, 'FormAbility onAddForm want or want.parameters is undefined.');\n+ return formBindingData.createFormBindingData('');\n+ }\n+ const formName: string = want.parameters?.[formInfo.FormParam.NAME_KEY] as string;\n+ const formId: string = want.parameters[formInfo.FormParam.IDENTITY_KEY] as string;\n+ if (formName === 'ArticleServiceCard') {\n+ return UpdateFormData.init(formId);\n+ }\n+ return formBindingData.createFormBindingData('');\n }\n \n onCastToNormalForm(formId: string) {\n@@ -30,6 +41,7 @@ export default class PhoneFormAbility extends FormExtensionAbility {\n \n onUpdateForm(formId: string) {\n // Called to notify the form provider to update a specified form.\n+ UpdateFormData.update(formId);\n }\n \n onFormEvent(formId: string, message: string) {\n@@ -38,6 +50,7 @@ export default class PhoneFormAbility extends FormExtensionAbility {\n \n onRemoveForm(formId: string) {\n // Called to notify the form provider that a specified form has been destroyed.\n+ UpdateFormData.removeDataOfFormId(formId);\n }\n \n onAcquireFormState(want: Want) {\ndiff --git a/products/phone/src/main/ets/util/UpdateFormData.ets b/products/phone/src/main/ets/util/UpdateFormData.ets\nnew file mode 100644\nindex 00000000..d45a6ee8\n--- /dev/null\n+++ b/products/phone/src/main/ets/util/UpdateFormData.ets\n@@ -0,0 +1,72 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { formBindingData, formProvider } from '@kit.FormKit';\n+import { BusinessError } from '@kit.BasicServicesKit';\n+import { ArticleListItem, Logger } from '@ohos/common';\n+import {\n+ AddFormData,\n+ ArticleServiceCardVM,\n+ InitEvent,\n+ RemoveFormData,\n+ UpdateDataEvent,\n+} from '../widget/viewmodel/ArticleServiceCardVM';\n+\n+const TAG: string = '[UpdateFormData]';\n+\n+export class UpdateFormData {\n+ private static viewModel: ArticleServiceCardVM = ArticleServiceCardVM.getInstance();\n+\n+ /**\n+ * Invoke the viewModel to reconstruct the form data by formId.\n+ *\n+ * @param formId\n+ */\n+ public static update(formId: string): void {\n+ UpdateFormData.viewModel.sendEvent(new UpdateDataEvent(formId));\n+ const formData: Record<string, string | ArticleListItem[]> = {\n+ 'cardList': UpdateFormData.viewModel.getState().cardList,\n+ }\n+ Logger.info(TAG, `click to check updateForm, formId: ${formId}`);\n+ const formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(formData);\n+ formProvider.updateForm(formId, formInfo).then(() => {\n+ Logger.info(TAG, 'updateForm success.');\n+ }).catch((error: BusinessError) => {\n+ Logger.error(TAG, `updateForm fail, code: ${error?.code}, message: ${error?.message}`);\n+ })\n+ }\n+\n+ /**\n+ * Init the viewModel, if this cardList length not equal 0, don't need InitEvent.\n+ *\n+ * @param formId\n+ * @returns formBindingData.FormBindingData\n+ */\n+ public static init(formId: string): formBindingData.FormBindingData {\n+ if (UpdateFormData.viewModel.getState().cardList.length === 0) {\n+ UpdateFormData.viewModel.sendEvent(new InitEvent());\n+ }\n+ UpdateFormData.viewModel.sendEvent(new AddFormData(formId, UpdateFormData.viewModel.getState().cardList));\n+ const cardData: Record<string, string | ArticleListItem[]> = {\n+ 'formId': formId,\n+ 'cardList': UpdateFormData.viewModel.getState().cardList,\n+ }\n+ return formBindingData.createFormBindingData(cardData);\n+ }\n+\n+ public static removeDataOfFormId(formId: string): void {\n+ UpdateFormData.viewModel.sendEvent(new RemoveFormData(formId));\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/ets/viewmodel/MainPageViewModel.ets b/products/phone/src/main/ets/viewmodel/MainPageViewModel.ets\nindex e1b8de25..6cc3e6ce 100644\n--- a/products/phone/src/main/ets/viewmodel/MainPageViewModel.ets\n+++ b/products/phone/src/main/ets/viewmodel/MainPageViewModel.ets\n@@ -13,18 +13,22 @@\n * limitations under the License.\n */\n \n-import { BaseState, BaseVM, WantParams } from '@ohos/common';\n-import { TabBarType } from '@ohos/commonbusiness';\n+import { ArticleListItem, BaseState, BaseVM, GlobalInfoModel, PageContext, StorageKey, WantParams } from '@ohos/common';\n+import { ArticleDetailParams, TabBarType } from '@ohos/commonbusiness';\n \n export class MainPageViewModel extends BaseVM<BaseState> {\n+ private globalInfoModel: GlobalInfoModel = AppStorage.get(StorageKey.GLOBAL_INFO)!;\n+\n public constructor() {\n super(new BaseState())\n }\n \n public sendEvent(event: JumpToPageEvent): number {\n- // Short cut entry.\n if (event.wantParams.shortCutKey) {\n return this.navigateToModuleHome(event.wantParams.shortCutKey)\n+ } else if (event.wantParams.formId) {\n+ this.navigateToArticleDetail(event.wantParams.articleInfo);\n+ return TabBarType.PRACTICE;\n }\n return TabBarType.HOME;\n }\n@@ -41,6 +45,23 @@ export class MainPageViewModel extends BaseVM<BaseState> {\n return TabBarType.HOME;\n }\n }\n+\n+ private navigateToArticleDetail(articleInfo?: ArticleListItem) {\n+ if (articleInfo) {\n+ const pageContext: PageContext | undefined = this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL ?\n+ AppStorage.get(StorageKey.EXPLORATION_PAGE_CONTEXT) : AppStorage.get(StorageKey.HOME_PAGE_CONTEXT);\n+ const articleParams: ArticleDetailParams = {\n+ id: articleInfo.id,\n+ isArticle: articleInfo.isArticle ?? true,\n+ title: articleInfo.title,\n+ detailsUrl: articleInfo.detailsUrl\n+ }\n+ pageContext?.openPage({\n+ routerName: 'ArticleDetailView',\n+ param: articleParams,\n+ })\n+ }\n+ }\n }\n \n export class JumpToPageEvent {\ndiff --git a/products/phone/src/main/ets/widget/component/CardComponent.ets b/products/phone/src/main/ets/widget/component/CardComponent.ets\nnew file mode 100644\nindex 00000000..2679564a\n--- /dev/null\n+++ b/products/phone/src/main/ets/widget/component/CardComponent.ets\n@@ -0,0 +1,78 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { CommonConstants } from '@ohos/common';\n+import { CardListParameter } from '../viewmodel/CardListParameter';\n+\n+@Component\n+export struct CardListComponent {\n+ @BuilderParam customBuilderParam: () => void = this.customBuilder;\n+ @Link cardListParameter: CardListParameter;\n+ onClickProcess: Function = () => {\n+ };\n+\n+ @Builder\n+ customBuilder() {\n+ }\n+\n+ build() {\n+ if (this.cardListParameter !== undefined) {\n+ Column() {\n+ Row() {\n+ Row() {\n+ Image(this.cardListParameter.logo)\n+ .width($r('app.float.list_logo_size_sm'))\n+ .aspectRatio(1)\n+ Text(this.cardListParameter.title)\n+ .fontSize($r('sys.float.Body_M'))\n+ .fontWeight(FontWeight.Bold)\n+ .fontColor(this.cardListParameter.titleColor)\n+ .maxLines(1)\n+ .textOverflow({ overflow: TextOverflow.Ellipsis })\n+ .margin({ left: $r('sys.float.padding_level2') })\n+ }\n+\n+ Blank()\n+ if (this.cardListParameter.subTitle) {\n+ Row() {\n+ Text(this.cardListParameter.subTitle)\n+ .fontSize($r('sys.float.Body_S'))\n+ .fontColor(this.cardListParameter.subTitleColor)\n+ .maxLines(1)\n+ .textOverflow({ overflow: TextOverflow.Ellipsis })\n+ SymbolGlyph(this.cardListParameter.rightArrowIcon)\n+ .fontColor([$r('sys.color.icon_tertiary')])\n+ .fontSize($r('sys.float.Body_M'))\n+ }\n+ .onClick(() => this.onClickProcess())\n+ }\n+ }\n+ .margin({\n+ top: $r('sys.float.padding_level6')\n+ })\n+ .width(CommonConstants.FULL_PERCENT)\n+\n+ this.customBuilderParam()\n+ }\n+ .backgroundImage(this.cardListParameter.backgroundImage)\n+ .backgroundImageSize(this.cardListParameter.backgroundImageSize)\n+ .backgroundColor(this.cardListParameter.backgroundColor)\n+ .padding({\n+ left: $r('sys.float.padding_level8'),\n+ right: $r('sys.float.padding_level8'),\n+ })\n+ }\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/ets/widget/model/AllArticleLists.ets b/products/phone/src/main/ets/widget/model/AllArticleLists.ets\nnew file mode 100644\nindex 00000000..d24cff03\n--- /dev/null\n+++ b/products/phone/src/main/ets/widget/model/AllArticleLists.ets\n@@ -0,0 +1,79 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the License);\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an AS IS BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { ArticleListItem } from '@ohos/common';\n+\n+export const allArticleLists: ArticleListItem[] = [\n+ {\n+ id: 1,\n+ title: '小窗口大世界,智享实况窗服务',\n+ detailsUrl: 'articlecols/articles/live-window-service/index.html',\n+ name: '开发实践'\n+ },\n+ {\n+ id: 2,\n+ title: 'Picker安心取,用户主导安全新体验',\n+ detailsUrl: 'articlecols/articles/native-safety/index.html',\n+ name: '开发实践'\n+ },\n+ {\n+ id: 3,\n+ title: '一镜到底,畅享无界丝滑视觉之旅',\n+ detailsUrl: 'articlecols/articles/shared-element-transition/index.html',\n+ name: '开发实践'\n+ },\n+ {\n+ id: 4,\n+ title: '跨设备互联,打造无缝流转极致体验',\n+ detailsUrl: 'articlecols/articles/app-continuation/index.html',\n+ name: '开发实践'\n+ },\n+ {\n+ id: 5,\n+ title: 'AI识图,开启智能图像处理新纪元',\n+ detailsUrl: 'articlecols/articles/smart-visual-recognition/index.html',\n+ name: '开发实践'\n+ },\n+ {\n+ id: 18,\n+ title: '多端UX设计',\n+ detailsUrl: 'articlecols/articles/native-ux-design/index.html',\n+ name: '应用体验设计'\n+ },\n+ {\n+ id: 22,\n+ title: '应用UX体验标准',\n+ detailsUrl: 'articlecols/articles/ux-guidelines/index.html',\n+ name: '应用体验设计'\n+ },\n+ {\n+ id: 7,\n+ title: 'UX动效设计',\n+ detailsUrl: 'articlecols/articles/design-animation/index.html',\n+ name: '应用体验设计'\n+ },\n+ {\n+ id: 8,\n+ title: '分层架构设计',\n+ detailsUrl: 'articlecols/articles/layered-architecture-design/index.html',\n+ name: '功能开发'\n+ },\n+ {\n+ id: 12,\n+ title: 'HMOS代码工坊一多开发实践',\n+ detailsUrl: 'articlecols/articles/multi-adaptation/index.html',\n+ name: '功能开发'\n+ }\n+];\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/ets/widget/pages/ArticleServiceCard.ets b/products/phone/src/main/ets/widget/pages/ArticleServiceCard.ets\nnew file mode 100644\nindex 00000000..73c21157\n--- /dev/null\n+++ b/products/phone/src/main/ets/widget/pages/ArticleServiceCard.ets\n@@ -0,0 +1,88 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { ArticleListItem, CommonConstants } from '@ohos/common';\n+import { CardListComponent } from '../component/CardComponent';\n+import { CardListParameter } from '../viewmodel/CardListParameter';\n+\n+@Entry\n+@Component\n+struct ArticleServiceCard {\n+ @LocalStorageProp('cardList') cardList: ArticleListItem[] = [];\n+ @LocalStorageProp('formId') formId: string = '';\n+ @State cardListParameter: CardListParameter = new CardListParameter($r('sys.color.ohos_id_color_background'),\n+ $r('app.string.hmos_app_name'), $r('app.media.list_card_bg'), ImageSize.Cover, $r('sys.color.font_emphasize'),\n+ $r('app.media.list_card_logo'),\n+ $r('app.string.card_list_subtitle'), $r('sys.color.font_tertiary'), $r('sys.symbol.chevron_right'));\n+ private readonly orderImageArray: Resource[] =\n+ [$r('app.media.first_order'), $r('app.media.second_order'), $r('app.media.third_order')];\n+ private readonly ACTION_TYPE: string = 'router';\n+ private readonly ABILITY_NAME: string = 'EntryAbility';\n+\n+ @Builder\n+ cardListBuilder() {\n+ Column() {\n+ ForEach(this.cardList, (item: ArticleListItem, index: number) => {\n+ Row() {\n+ Row() {\n+ Image(this.orderImageArray[index])\n+ .width($r('app.float.order_image_size'))\n+ .objectFit(ImageFit.Cover)\n+ Text(item.title)\n+ .maxLines(1)\n+ .textOverflow({ overflow: TextOverflow.Ellipsis })\n+ .fontSize($r('sys.float.Body_M'))\n+ .fontColor($r('sys.color.font_primary'))\n+ .margin({ left: $r('sys.float.padding_level4'), right: $r('sys.float.padding_level4') })\n+ }\n+\n+ Text(item.name)\n+ .fontSize($r('sys.float.Body_S'))\n+ .fontColor($r('sys.color.font_tertiary'))\n+ }\n+ .alignItems(VerticalAlign.Center)\n+ .flexGrow(1)\n+ .onClick(() => this.onClickProcess(item))\n+ })\n+ }\n+ .alignItems(HorizontalAlign.Start)\n+ .width(CommonConstants.FULL_PERCENT)\n+ .layoutWeight(1)\n+ .padding({ top: $r('sys.float.padding_level5'), bottom: $r('sys.float.padding_level5') })\n+ }\n+\n+ build() {\n+ Row() {\n+ CardListComponent({ cardListParameter: this.cardListParameter, onClickProcess: this.onClickProcess }) {\n+ this.cardListBuilder()\n+ }\n+ }\n+ .height(CommonConstants.FULL_PERCENT)\n+ .width(CommonConstants.FULL_PERCENT)\n+ .onClick(() => this.onClickProcess())\n+ }\n+\n+ private onClickProcess = (articleInfo?: ArticleListItem) => {\n+ postCardAction(this, {\n+ action: this.ACTION_TYPE,\n+ abilityName: this.ABILITY_NAME,\n+ params: {\n+ formId: this.formId,\n+ articleInfo: articleInfo,\n+ isFromArticleServiceCard: 'true',\n+ }\n+ })\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/ets/widget/viewmodel/ArticleServiceCardState.ets b/products/phone/src/main/ets/widget/viewmodel/ArticleServiceCardState.ets\nnew file mode 100644\nindex 00000000..f7c3f89d\n--- /dev/null\n+++ b/products/phone/src/main/ets/widget/viewmodel/ArticleServiceCardState.ets\n@@ -0,0 +1,26 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { ArticleListItem } from '@ohos/common';\n+\n+export class ArticleServiceCardState {\n+ public cardList: ArticleListItem[];\n+ public formDataRecord: Map<string, ArticleListItem[]>;\n+\n+ constructor(cardList: ArticleListItem[], formDataRecord: Map<string, ArticleListItem[]>) {\n+ this.cardList = cardList;\n+ this.formDataRecord = formDataRecord;\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/ets/widget/viewmodel/ArticleServiceCardVM.ets b/products/phone/src/main/ets/widget/viewmodel/ArticleServiceCardVM.ets\nnew file mode 100644\nindex 00000000..35bf3639\n--- /dev/null\n+++ b/products/phone/src/main/ets/widget/viewmodel/ArticleServiceCardVM.ets\n@@ -0,0 +1,117 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { ArticleListItem, BaseVM, BaseVMEvent, Logger } from '@ohos/common';\n+import { allArticleLists } from '../model/AllArticleLists';\n+import { ArticleServiceCardState } from './ArticleServiceCardState';\n+\n+const TAG: string = '[ArticleServiceCardVM]';\n+\n+export class ArticleServiceCardVM extends BaseVM<ArticleServiceCardState> {\n+ private static instance: ArticleServiceCardVM;\n+\n+ private constructor(cardList: ArticleListItem[]) {\n+ super(new ArticleServiceCardState(cardList, new Map()));\n+ }\n+\n+ public static getInstance() {\n+ if (!ArticleServiceCardVM.instance) {\n+ ArticleServiceCardVM.instance = new ArticleServiceCardVM([]);\n+ }\n+ return ArticleServiceCardVM.instance;\n+ }\n+\n+ sendEvent(event: BaseVMEvent | InitEvent): void {\n+ if (event instanceof InitEvent) {\n+ this.init();\n+ } else if (event instanceof UpdateDataEvent) {\n+ this.updateData(event.formId);\n+ } else if (event instanceof AddFormData) {\n+ this.addFormData(event.formId, event.data);\n+ } else if (event instanceof RemoveFormData) {\n+ this.removeFormData(event.formId);\n+ }\n+ }\n+\n+ private init(): void {\n+ this.state.cardList = this.getRandomThreeArticle([]);\n+ }\n+\n+ private updateData(formId: string): void {\n+ const currentDataOfFormId: ArticleListItem[] = this.state.formDataRecord.get(formId) ?? [];\n+ Logger.info(TAG, `The currentDataOfFormId is ${JSON.stringify(currentDataOfFormId)} in updateData.`);\n+ this.removeFormData(formId);\n+ const newDataOfFormId: ArticleListItem[] = this.getRandomThreeArticle(currentDataOfFormId);\n+ this.state.cardList = newDataOfFormId;\n+ this.addFormData(formId, newDataOfFormId);\n+ }\n+\n+ private getRandomThreeArticle(exclude: ArticleListItem[]): ArticleListItem[] {\n+ const articles = [...allArticleLists];\n+ const selected: ArticleListItem[] = [];\n+ exclude.forEach((item: ArticleListItem) => {\n+ const index: number = articles.findIndex((article: ArticleListItem) => article.id === item.id);\n+ articles.splice(index, 1);\n+ })\n+ while (selected.length < 3) {\n+ const randomIndex = Math.floor(Math.random() * articles.length);\n+ const articleInfo: ArticleListItem = articles[randomIndex];\n+ if (selected.filter((item: ArticleListItem) => item.id === articleInfo.id).length === 0) {\n+ selected.push(articleInfo);\n+ articles.splice(randomIndex, 1);\n+ }\n+ }\n+ return selected;\n+ }\n+\n+ private addFormData(formId: string, data: ArticleListItem[]) {\n+ this.state.formDataRecord.set(formId, data);\n+ }\n+\n+ private removeFormData(formId: string) {\n+ if (this.state.formDataRecord.has(formId)) {\n+ this.state.formDataRecord.delete(formId);\n+ }\n+ }\n+}\n+\n+export class InitEvent implements BaseVMEvent {\n+}\n+\n+export class UpdateDataEvent implements BaseVMEvent {\n+ public readonly formId: string = '';\n+\n+ constructor(formId: string) {\n+ this.formId = formId;\n+ }\n+}\n+\n+export class AddFormData implements BaseVMEvent {\n+ public readonly formId: string = '';\n+ public readonly data: ArticleListItem[] = [];\n+\n+ constructor(formId: string, data: ArticleListItem[]) {\n+ this.formId = formId;\n+ this.data = data;\n+ }\n+}\n+\n+export class RemoveFormData implements BaseVMEvent {\n+ public readonly formId: string = '';\n+\n+ constructor(formId: string) {\n+ this.formId = formId;\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/ets/widget/viewmodel/CardListParameter.ets b/products/phone/src/main/ets/widget/viewmodel/CardListParameter.ets\nnew file mode 100644\nindex 00000000..79fd524a\n--- /dev/null\n+++ b/products/phone/src/main/ets/widget/viewmodel/CardListParameter.ets\n@@ -0,0 +1,67 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+export class CardListParameter {\n+ /**\n+ * Card background color.\n+ */\n+ public backgroundColor: ResourceColor = '';\n+ /**\n+ * Background image.\n+ */\n+ public backgroundImage: ResourceStr = '';\n+ /**\n+ * ImageSize of background image.\n+ */\n+ public backgroundImageSize?: ImageSize = ImageSize.Auto;\n+ /**\n+ * Card list title.\n+ */\n+ public title: ResourceStr = '';\n+ /**\n+ * Card list title color.\n+ */\n+ public titleColor: ResourceColor = $r('sys.color.comp_background_primary');\n+ /**\n+ * Logo icon.\n+ */\n+ public logo: ResourceStr = '';\n+ /**\n+ * Card list subtitle.\n+ */\n+ public subTitle?: ResourceStr = '';\n+ /**\n+ * Card list subtitle color.\n+ */\n+ public subTitleColor?: ResourceColor;\n+ /**\n+ * Card list arrow icon.\n+ */\n+ public rightArrowIcon?: Resource;\n+\n+ constructor(backgroundColor: ResourceColor, title: ResourceStr, backgroundImage: ResourceStr,\n+ backgroundImageSize: ImageSize, titleColor: ResourceColor, logo: ResourceStr, subTitle?: ResourceStr,\n+ subTitleColor?: ResourceColor, rightArrowIcon?: Resource) {\n+ this.backgroundColor = backgroundColor;\n+ this.title = title;\n+ this.backgroundImage = backgroundImage;\n+ this.backgroundImageSize = backgroundImageSize;\n+ this.titleColor = titleColor;\n+ this.logo = logo;\n+ this.subTitle = subTitle;\n+ this.subTitleColor = subTitleColor;\n+ this.rightArrowIcon = rightArrowIcon;\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/resources/base/element/float.json b/products/phone/src/main/resources/base/element/float.json\nindex f07174a1..d9059b66 100644\n--- a/products/phone/src/main/resources/base/element/float.json\n+++ b/products/phone/src/main/resources/base/element/float.json\n@@ -23,6 +23,18 @@\n {\n \"name\": \"app_icon_width\",\n \"value\": \"24vp\"\n+ },\n+ {\n+ \"name\": \"list_logo_size_sm\",\n+ \"value\": \"14vp\"\n+ },\n+ {\n+ \"name\": \"list_divider_margin\",\n+ \"value\": \"6vp\"\n+ },\n+ {\n+ \"name\": \"order_image_size\",\n+ \"value\": \"16vp\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/resources/base/element/string.json b/products/phone/src/main/resources/base/element/string.json\nindex 4d69d393..b7caf664 100644\n--- a/products/phone/src/main/resources/base/element/string.json\n+++ b/products/phone/src/main/resources/base/element/string.json\n@@ -123,6 +123,14 @@\n {\n \"name\": \"article_cases\",\n \"value\": \"article cases\"\n+ },\n+ {\n+ \"name\": \"ArticleServiceCard_desc\",\n+ \"value\": \"Best Practice Article.\"\n+ },\n+ {\n+ \"name\": \"card_list_subtitle\",\n+ \"value\": \"More\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/resources/base/profile/form_config.json b/products/phone/src/main/resources/base/profile/form_config.json\nindex 67ca29e9..47411ba1 100644\n--- a/products/phone/src/main/resources/base/profile/form_config.json\n+++ b/products/phone/src/main/resources/base/profile/form_config.json\n@@ -20,6 +20,27 @@\n \"supportDimensions\": [\n \"2*2\"\n ]\n+ },\n+ {\n+ \"name\": \"ArticleServiceCard\",\n+ \"displayName\": \"$string:widget_display_name\",\n+ \"description\": \"$string:ArticleServiceCard_desc\",\n+ \"src\": \"./ets/widget/pages/ArticleServiceCard.ets\",\n+ \"uiSyntax\": \"arkts\",\n+ \"updateEnabled\": true,\n+ \"updateDuration\": 1,\n+ \"window\": {\n+ \"designWidth\": 720,\n+ \"autoDesignWidth\": true\n+ },\n+ \"colorMode\": \"auto\",\n+ \"isDynamic\": true,\n+ \"isDefault\": false,\n+ \"scheduledUpdateTime\": \"10:30\",\n+ \"defaultDimension\": \"2*4\",\n+ \"supportDimensions\": [\n+ \"2*4\"\n+ ]\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/resources/en_US/element/string.json b/products/phone/src/main/resources/en_US/element/string.json\nindex 4d69d393..fe0aa2f0 100644\n--- a/products/phone/src/main/resources/en_US/element/string.json\n+++ b/products/phone/src/main/resources/en_US/element/string.json\n@@ -123,6 +123,14 @@\n {\n \"name\": \"article_cases\",\n \"value\": \"article cases\"\n+ },\n+ {\n+ \"name\": \"card_list_subtitle\",\n+ \"value\": \"More\"\n+ },\n+ {\n+ \"name\": \"ArticleServiceCard_desc\",\n+ \"value\": \"Best Practice Article.\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/resources/zh_CN/element/string.json b/products/phone/src/main/resources/zh_CN/element/string.json\nindex b559b97d..41723599 100644\n--- a/products/phone/src/main/resources/zh_CN/element/string.json\n+++ b/products/phone/src/main/resources/zh_CN/element/string.json\n@@ -123,6 +123,14 @@\n {\n \"name\": \"article_cases\",\n \"value\": \"技术文章\"\n+ },\n+ {\n+ \"name\": \"card_list_subtitle\",\n+ \"value\": \"更多文章\"\n+ },\n+ {\n+ \"name\": \"ArticleServiceCard_desc\",\n+ \"value\": \"最佳实践文章抢先看.\"\n }\n ]\n }\n\\ No newline at end of file\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "hard",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_009",
"repo": "internal_green/HMOSWorldClient",
"base_commit": "602b2e64",
"problem_statement": "在设置中的关于页面添加返回功能,点击左上角BackButton可以进行返回,并且旁边显示'关于'Text文本",
"hints_text": "",
"patch": "diff --git a/features/mine/src/main/ets/view/MineSettingsView.ets b/features/mine/src/main/ets/view/MineSettingsView.ets\nindex 5ac67807..7d6a90ee 100644\n--- a/features/mine/src/main/ets/view/MineSettingsView.ets\n+++ b/features/mine/src/main/ets/view/MineSettingsView.ets\n@@ -87,7 +87,8 @@ export struct MineSettingsView {\n autoCancel: false,\n alignment: DialogAlignment.Center,\n onWillDismiss: () => {\n- Logger.info(TAG, `Intercept the PRESS_BACK[three-key back, left/right swipe, keyboard ESC events] events, and the TOUCH_OUTSIDE layer events.`);\n+ Logger.info(TAG,\n+ `Intercept the PRESS_BACK[three-key back, left/right swipe, keyboard ESC events] events, and the TOUCH_OUTSIDE layer events.`);\n },\n });\n \n@@ -115,9 +116,17 @@ export struct MineSettingsView {\n \n private registerPageBuilder(): void {\n const aboutPage: NavPageRegisterOptions =\n- { navPathName: 'aboutPage', builder: this.settingsAboutPageBuilder.bind(this) };\n+ {\n+ navPathName: 'aboutPage',\n+ pageTitle: $r('app.string.about'),\n+ builder: this.settingsAboutPageBuilder.bind(this),\n+ };\n const webSheetPage: NavPageRegisterOptions =\n- { navPathName: 'webSheetPage', customStyle: true, builder: this.webSheetPageBuilder.bind(this) };\n+ {\n+ navPathName: 'webSheetPage',\n+ customStyle: true,\n+ builder: this.webSheetPageBuilder.bind(this),\n+ };\n MainNavPageRegistry.getMainNavPageRegistry()!.register([webSheetPage, aboutPage]);\n }\n \ndiff --git a/features/mine/src/main/ets/view/SettingsAboutView.ets b/features/mine/src/main/ets/view/SettingsAboutView.ets\nindex 9e59221f..dc9d184c 100644\n--- a/features/mine/src/main/ets/view/SettingsAboutView.ets\n+++ b/features/mine/src/main/ets/view/SettingsAboutView.ets\n@@ -114,18 +114,15 @@ export struct SettingsAboutView {\n @Builder\n settingAboutBuilder() {\n PafAbout({\n- navigationTitle: $r('app.string.about'),\n appImg: $r('app.media.app_icon'),\n appName: $r('app.string.app_name'),\n versionString: AppStorage.get<BundleInfoData>('BundleInfoData')?.versionName as string,\n versionMessage: this.versionMessage,\n items: this.listItems,\n footnotes: $footnotes,\n- customBackPressedCallback: () => {\n- this.sheetShowConfig?.getPathStacks().pop();\n- return false;\n- },\n- hideTitleBar: false,\n+ isModal: true,\n+ fullPage: true,\n+ hideTitleBar: true,\n isNav: false,\n })\n }\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_010",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "9014c22f",
"problem_statement": "【需求描述】:样例页面开发样例sample点击'下载体验'按钮后,提供取消下载的按钮,进度百分比后面显示'取消'",
"hints_text": "",
"patch": "diff --git a/common/src/main/ets/constant/CommonEnums.ets b/common/src/main/ets/constant/CommonEnums.ets\nindex 000da3c..e25ae12 100644\n--- a/common/src/main/ets/constant/CommonEnums.ets\n+++ b/common/src/main/ets/constant/CommonEnums.ets\n@@ -73,5 +73,6 @@ export enum StorageKey {\n EXPLORATION_PAGE_CONTEXT = 'hmos_world_ExplorationPageContext',\n HOME_PAGE_CONTEXT = 'hmos_world_PageContext',\n MINE_PAGE_CONTEXT = 'hmos_world_MinePageContext',\n- WANT_PARAMETERS = 'hmos_world_WantParams'\n+ WANT_PARAMETERS = 'hmos_world_WantParams',\n+ LANGUAGE = 'hmos_world_SystemLanguage',\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/ets/common/SampleConstant.ets b/features/devpractices/src/main/ets/common/SampleConstant.ets\nindex 0a352e2..4417bc3 100644\n--- a/features/devpractices/src/main/ets/common/SampleConstant.ets\n+++ b/features/devpractices/src/main/ets/common/SampleConstant.ets\n@@ -17,6 +17,10 @@ export class SampleConstant {\n public static SCROLL_MARGIN_SM: number = -16;\n public static SCROLL_MARGIN_MD: number = -24;\n public static SCROLL_MARGIN_LG: number = -32;\n+\n+ // Download Cancel\n+ public static readonly DOWNLOAD_CANCEL_CN: string = '取消';\n+ public static readonly DOWNLOAD_CANCEL_EN: string = 'cancel';\n }\n \n export enum SampleTypeEnum {\ndiff --git a/features/devpractices/src/main/ets/component/SampleCard.ets b/features/devpractices/src/main/ets/component/SampleCard.ets\nindex 150718d..b6e95c2 100644\n--- a/features/devpractices/src/main/ets/component/SampleCard.ets\n+++ b/features/devpractices/src/main/ets/component/SampleCard.ets\n@@ -27,6 +27,7 @@ import {\n type GlobalInfoModel,\n StorageKey,\n } from '@ohos/common';\n+import { SampleConstant } from '../common/SampleConstant';\n import { SampleDetailConstant } from '../constant/CommonConstants';\n import {\n BindSheetEvent,\n@@ -36,6 +37,7 @@ import {\n ChangeCardStatusEvent\n } from '../viewmodel/SampleDetailPageVM';\n import type { SampleCardData } from '../viewmodel/SampleDetailState';\n+import { i18n } from '@kit.LocalizationKit';\n \n const TAG = '[SampleCard]';\n \n@@ -223,8 +225,9 @@ export struct SampleCard {\n .style({\n borderColor: $r('sys.color.background_emphasize'),\n borderWidth: $r('sys.float.border_larger'),\n- content: `${this.sampleCard.downloadProgress}%`,\n- font: { size: $r('sys.float.Body_S'), style: FontStyle.Normal, weight: FontWeight.Medium },\n+ content: `${this.sampleCard.downloadProgress}% ${i18n.System.getSystemLanguage() === 'zh-Hans' ?\n+ SampleConstant.DOWNLOAD_CANCEL_CN : SampleConstant.DOWNLOAD_CANCEL_EN}`,\n+ font: { size: $r('sys.float.Body_M'), style: FontStyle.Normal, weight: FontWeight.Medium },\n fontColor: $r('sys.color.font_primary'),\n })\n } else {\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_011",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "f855bc6f",
"problem_statement": "【需求描述】:1、组件库接入华为分享,通过三方应用(如微信、Welink等)实现代码文本的分享\n2、Sample接入华为分享,通过三方应用(如微信、Welink等)实现代码下载链接的分享",
"hints_text": "",
"patch": "diff --git a/features/componentlibrary/src/main/ets/component/CodePreviewComponent.ets b/features/componentlibrary/src/main/ets/component/CodePreviewComponent.ets\nindex 65e6066..1c9d0c1 100644\n--- a/features/componentlibrary/src/main/ets/component/CodePreviewComponent.ets\n+++ b/features/componentlibrary/src/main/ets/component/CodePreviewComponent.ets\n@@ -72,6 +72,7 @@ export struct CodePreviewComponent {\n iconResource: $r('sys.symbol.share'),\n } as ResourceInterface,\n () => {\n+ this.handleShare();\n }, 5);\n private bottomIconItems: ItemData[] = [\n new ItemData(\n@@ -249,6 +250,25 @@ export struct CodePreviewComponent {\n }\n }\n \n+ private handleShare(): void {\n+ const context = this.getUIContext().getHostContext() as common.UIAbilityContext;\n+ const shareDescription = ResourceUtil.getResourceString(context, $r('app.string.share_description'));\n+ const shareData: systemShare.SharedData = new systemShare.SharedData({\n+ utd: utd.UniformDataType.PLAIN_TEXT,\n+ content: this.code,\n+ title: this.componentName,\n+ description: shareDescription\n+ });\n+\n+ const controller: systemShare.ShareController = new systemShare.ShareController(shareData);\n+ controller.show(context, {\n+ selectionMode: systemShare.SelectionMode.SINGLE,\n+ previewMode: systemShare.SharePreviewMode.DEFAULT\n+ }).catch((error: BusinessError) => {\n+ Logger.error(TAG, `Component code sharing error. Code: ${error.code}, message: ${error.message}`);\n+ });\n+ }\n+\n copyText(text: string) {\n try {\n const pasteboardData: pasteboard.PasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text);\ndiff --git a/features/componentlibrary/src/main/resources/base/element/string.json b/features/componentlibrary/src/main/resources/base/element/string.json\nindex d4d8e85..9492418 100644\n--- a/features/componentlibrary/src/main/resources/base/element/string.json\n+++ b/features/componentlibrary/src/main/resources/base/element/string.json\n@@ -331,6 +331,10 @@\n {\n \"name\": \"design_practice\",\n \"value\": \"Design Practice\"\n+ },\n+ {\n+ \"name\": \"share_description\",\n+ \"value\": \"Text\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/resources/en_US/element/string.json b/features/componentlibrary/src/main/resources/en_US/element/string.json\nindex 9a0107e..d0ed39c 100644\n--- a/features/componentlibrary/src/main/resources/en_US/element/string.json\n+++ b/features/componentlibrary/src/main/resources/en_US/element/string.json\n@@ -331,6 +331,10 @@\n {\n \"name\": \"design_practice\",\n \"value\": \"Design Practice\"\n+ },\n+ {\n+ \"name\": \"share_description\",\n+ \"value\": \"Text\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/resources/zh_CN/element/string.json b/features/componentlibrary/src/main/resources/zh_CN/element/string.json\nindex 8686f6a..3483e31 100644\n--- a/features/componentlibrary/src/main/resources/zh_CN/element/string.json\n+++ b/features/componentlibrary/src/main/resources/zh_CN/element/string.json\n@@ -331,6 +331,10 @@\n {\n \"name\": \"design_practice\",\n \"value\": \"设计实践\"\n+ },\n+ {\n+ \"name\": \"share_description\",\n+ \"value\": \"文本\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/ets/component/SampleCard.ets b/features/devpractices/src/main/ets/component/SampleCard.ets\nindex 1b2dc78..150718d 100644\n--- a/features/devpractices/src/main/ets/component/SampleCard.ets\n+++ b/features/devpractices/src/main/ets/component/SampleCard.ets\n@@ -59,6 +59,24 @@ export struct SampleCard {\n WebUtil.removeNode(this.sampleCard.originalUrl);\n }\n \n+ private handleShare(): void {\n+ if (canIUse('SystemCapability.Collaboration.SystemShare')) {\n+ const shareData: systemShare.SharedData = new systemShare.SharedData({\n+ utd: utd.UniformDataType.HYPERLINK,\n+ content: this.sampleCard.originalUrl,\n+ title: this.sampleCard.title,\n+ description: this.sampleCard.originalUrl\n+ });\n+ let controller: systemShare.ShareController = new systemShare.ShareController(shareData);\n+ controller.show(this.context, {\n+ selectionMode: systemShare.SelectionMode.SINGLE,\n+ previewMode: systemShare.SharePreviewMode.DEFAULT\n+ }).catch((error: BusinessError) => {\n+ Logger.error(TAG, `Sample link sharing error. Code: ${error.code}, message: ${error.message}`);\n+ });\n+ }\n+ }\n+\n @Builder\n TitleComponent() {\n Row() {\n@@ -78,6 +96,7 @@ export struct SampleCard {\n .height($r('app.float.back_button_height'))\n .aspectRatio(1)\n .backgroundColor(this.backIconBgColor)\n+ .onClick(() => this.handleShare())\n .onHover((isHover: boolean) => {\n this.backIconBgColor = isHover ? $r('sys.color.comp_background_tertiary') : Color.Transparent;\n })\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "medium",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_015",
"repo": "internal_green/HMOSWorldClient",
"base_commit": "7d5000e5",
"problem_statement": "组件库item上新tag, 需求描述:给首页组件库中的单行文本输入图标左上角加一个'new'标签, 具体展现形式参考项目已有的",
"hints_text": "",
"patch": "diff --git a/features/commonbusiness/src/main/ets/component/TagLabel.ets b/features/commonbusiness/src/main/ets/component/TagLabel.ets\nindex 61bf2748..9e8894c7 100644\n--- a/features/commonbusiness/src/main/ets/component/TagLabel.ets\n+++ b/features/commonbusiness/src/main/ets/component/TagLabel.ets\n@@ -18,6 +18,7 @@ import { TagEnum } from '@ohos/common';\n @Component\n export struct TagTipLabel {\n tags: number[] = [];\n+ isSmall: boolean = false;\n newSymbol: Resource = $r('app.media.big_new');\n \n build() {\n@@ -25,7 +26,11 @@ export struct TagTipLabel {\n ForEach(this.tags, (item: number) => {\n if (item === TagEnum.NEW) {\n Image(this.newSymbol)\n- .size({\n+ .objectFit(ImageFit.Contain)\n+ .size(this.isSmall ? {\n+ width: $r('app.float.new_tag_width_sm'),\n+ height: $r('app.float.new_tag_height_sm'),\n+ } : {\n width: $r('app.float.new_tag_width'),\n height: $r('app.float.new_tag_height'),\n })\ndiff --git a/features/componentlibrary/src/main/ets/component/ComponentItem.ets b/features/componentlibrary/src/main/ets/component/ComponentItem.ets\ndeleted file mode 100644\nindex e69de29b..00000000\ndiff --git a/features/componentlibrary/src/main/ets/component/ComponentItemList.ets b/features/componentlibrary/src/main/ets/component/ComponentItemList.ets\nindex 7685d6c2..cea2a713 100644\n--- a/features/componentlibrary/src/main/ets/component/ComponentItemList.ets\n+++ b/features/componentlibrary/src/main/ets/component/ComponentItemList.ets\n@@ -15,7 +15,8 @@\n \n import { TextModifier } from '@kit.ArkUI';\n import { HdsListItemCard, PrefixCustomBuilder, SuffixButton, SuffixCustomBuilder, } from '@kit.UIDesignKit';\n-import { CommonConstants, ResourceUtil, VersionUtil } from '@ohos/common';\n+import { CommonConstants, ResourceUtil, TagEnum, VersionUtil } from '@ohos/common';\n+import { TagTipLabel } from '@ohos/commonbusiness';\n import type { ComponentContent } from '../model/ComponentData';\n \n export enum ItemSuffixType {\n@@ -41,11 +42,8 @@ export struct ComponentItemList {\n }\n \n @Builder\n- IconBuilder(iconUrl: string) {\n- Row() {\n- ComponentIcon({ iconUrl })\n- }\n- .padding({ right: $r('sys.float.padding_level8') })\n+ IconBuilder(iconUrl: string, showTag: boolean, tagIds: TagEnum[]) {\n+ ComponentIcon({ iconUrl, showTag, tagIds })\n }\n \n build() {\n@@ -55,7 +53,10 @@ export struct ComponentItemList {\n ListItem() {\n if (VersionUtil.canUseHds()) {\n HdsListItemCard({\n- prefixItem: new PrefixCustomBuilder(() => this.IconBuilder(repeatItem.item.mediaUrl)),\n+ prefixItem: new PrefixCustomBuilder(() => {\n+ this.IconBuilder(repeatItem.item.mediaUrl, this.suffixType !== ItemSuffixType.ICON,\n+ repeatItem.item.tagIds);\n+ }),\n textItem: {\n primaryText: {\n text: repeatItem.item.subTitle,\n@@ -72,7 +73,7 @@ export struct ComponentItemList {\n new SuffixButton({ text: $r('app.string.open'), textColor: this.buttonColor }) :\n new SuffixCustomBuilder(() => this.CircleArrowBuilder()),\n cardHeight: this.itemHeight,\n- cardPrefixMargin: $r('sys.float.padding_level6'),\n+ cardPrefixMargin: $r('sys.float.padding_level0'),\n cardSuffixMargin: $r('sys.float.padding_level2'),\n cardBorderRadius: 0,\n cardBackgroundColor: $r('sys.color.ohos_id_color_background_transparent'),\n@@ -99,6 +100,7 @@ export struct ComponentItemList {\n startMargin: $r('sys.float.padding_level36'),\n endMargin: $r('sys.float.padding_level6')\n })\n+ .nestedScroll({scrollForward: NestedScrollMode.PARENT_FIRST, scrollBackward: NestedScrollMode.PARENT_FIRST})\n .scrollBar(BarState.Off)\n .edgeEffect(EdgeEffect.None)\n .width('100%')\n@@ -123,15 +125,24 @@ struct CircleArrow {\n \n @Component\n struct ComponentIcon {\n+ @Prop showTag: boolean;\n+ @Prop tagIds: TagEnum[];\n @Prop @Require iconUrl: string;\n \n build() {\n- Image($rawfile(this.iconUrl))\n- .draggable(false)\n- .alt($r('app.media.ic_placeholder'))\n- .borderRadius($r('sys.float.corner_radius_level5'))\n- .width($r('app.float.tip_image_height'))\n- .aspectRatio(1)\n+ Stack({ alignContent: Alignment.TopStart }) {\n+ Image($rawfile(this.iconUrl))\n+ .draggable(false)\n+ .alt($r('app.media.ic_placeholder'))\n+ .borderRadius($r('sys.float.corner_radius_level5'))\n+ .width($r('app.float.tip_image_height'))\n+ .margin({ left: $r('sys.float.padding_level6'), right: $r('sys.float.padding_level8') })\n+ .aspectRatio(1)\n+ if (this.showTag) {\n+ TagTipLabel({ tags: this.tagIds, isSmall: true })\n+ .margin({ left: $r('sys.float.padding_level3'), top: $r('app.float.small_new_margin_top') })\n+ }\n+ }\n }\n }\n \n@@ -145,8 +156,11 @@ struct ComponentItem {\n \n build() {\n Row() {\n- ComponentIcon({ iconUrl: this.componentContent.mediaUrl })\n- .margin({ right: $r('sys.float.padding_level8') })\n+ ComponentIcon({\n+ iconUrl: this.componentContent.mediaUrl,\n+ showTag: this.suffixType !== ItemSuffixType.ICON,\n+ tagIds: this.componentContent.tagIds,\n+ })\n Column({ space: CommonConstants.SPACE_6 }) {\n Text(this.componentContent.subTitle)\n .fontSize($r('sys.float.Subtitle_M'))\n@@ -179,7 +193,7 @@ struct ComponentItem {\n }\n .width('100%')\n .height(this.itemHeight)\n- .padding($r('sys.float.padding_level6'))\n+ .padding({ right: $r('sys.float.padding_level6') })\n .renderGroup(true)\n }\n }\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/resources/base/element/float.json b/features/componentlibrary/src/main/resources/base/element/float.json\nindex 47cbb97f..43c3f10c 100644\n--- a/features/componentlibrary/src/main/resources/base/element/float.json\n+++ b/features/componentlibrary/src/main/resources/base/element/float.json\n@@ -262,7 +262,7 @@\n },\n {\n \"name\": \"small_new_margin_top\",\n- \"value\": \"-8vp\"\n+ \"value\": \"-6vp\"\n }\n ]\n }\n\\ No newline at end of file\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_016",
"repo": "internal_green/HMOSWorldClient",
"base_commit": "b42a7e80",
"problem_statement": "问题描述:点击实践的banner文章,出现闪退进入蓝色splash的问题",
"hints_text": "",
"patch": "diff --git a/common/Index.ets b/common/Index.ets\nindex a2a17ab2..a67dd1db 100644\n--- a/common/Index.ets\n+++ b/common/Index.ets\n@@ -14,6 +14,8 @@ export { ProcessUtil } from './src/main/ets/util/ProcessUtil';\n \n export { BreakpointType } from './src/main/ets/util/BreakpointSystem';\n \n+export { VersionUtil } from './src/main/ets/util/VersionUtil';\n+\n export { GlobalInfoModel, WIDTH_BREAKPOINTS } from './src/main/ets/model/GlobalInfoModel';\n \n export { BundleInfoData } from './src/main/ets/model/BundleInfoData';\n@@ -88,12 +90,18 @@ export { ColorPickerUtil } from './src/main/ets/util/ColorPickerUtil';\n \n export { NetworkUtil } from './src/main/ets/util/NetworkUtil';\n \n+export { PullUpManager, WantParams } from './src/main/ets/util/PullUpManager';\n+\n+export { TextOverflowUtil } from './src/main/ets/util/TextOverflowUtil';\n+\n+export { TextOverflowData } from './src/main/ets/util/TextOverflowUtil';\n+\n+export { TextOverflowProperty } from './src/main/ets/util/TextOverflowUtil';\n+\n export { AgreementService, ProtocolName } from './src/main/ets/agreementservice/AgreementService';\n \n export { AgreementBasicInfo, AgreementName, AgreementType } from './src/main/ets/agreementservice/AgreementData';\n \n export { AgreementContentPage } from './src/main/ets/agreementservice/page/AgreementContentPage';\n \n-export { AgreementServiceConstant } from './src/main/ets/agreementservice/constant/AgreementServiceConstant';\n-\n-export { PullUpManager, WantParams } from './src/main/ets/util/PullUpManager';\n\\ No newline at end of file\n+export { AgreementServiceConstant } from './src/main/ets/agreementservice/constant/AgreementServiceConstant';\n\\ No newline at end of file\ndiff --git a/common/src/main/ets/component/TopNavigationView.ets b/common/src/main/ets/component/TopNavigationView.ets\nindex 282bde8b..76c202cb 100644\n--- a/common/src/main/ets/component/TopNavigationView.ets\n+++ b/common/src/main/ets/component/TopNavigationView.ets\n@@ -13,6 +13,7 @@\n * limitations under the License.\n */\n \n+import { PaddingOptions, TitleBarStyleOptions } from '@kit.UIDesignKit';\n import { CommonConstants } from '../constant/CommonConstants';\n import { StorageKey } from '../constant/CommonEnums';\n import type { GlobalInfoModel } from '../model/GlobalInfoModel';\n@@ -35,7 +36,7 @@ export struct TopNavigationView {\n @State fontSize: number = 20;\n @State backIconBgColor: ResourceColor =\n this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL ? Color.Transparent :\n- $r('sys.color.comp_background_tertiary');\n+ $r('sys.color.comp_background_tertiary');\n \n aboutToAppear(): void {\n if (this.topNavigationData.fontSize === undefined) {\n@@ -67,7 +68,7 @@ export struct TopNavigationView {\n Column() {\n Row() {\n if (this.topNavigationData.onBackClick) {\n- Button({ type: ButtonType.Circle }) {\n+ Button() {\n SymbolGlyph($r('sys.symbol.chevron_backward'))\n .fontColor([$r('sys.color.icon_primary')])\n .fontSize($r('sys.float.Title_M'))\n@@ -134,4 +135,6 @@ export class TopNavigationData {\n public isBlur?: boolean = false;\n public bgColor?: ResourceStr | Color = Color.Transparent;\n public onBackClick?: Function;\n+ public hdsTitleBarStyle?: TitleBarStyleOptions;\n+ public hdsTitleBarPadding?: PaddingOptions;\n }\n\\ No newline at end of file\ndiff --git a/common/src/main/ets/constant/CommonConstants.ets b/common/src/main/ets/constant/CommonConstants.ets\nindex 8eb120aa..e995f3c7 100644\n--- a/common/src/main/ets/constant/CommonConstants.ets\n+++ b/common/src/main/ets/constant/CommonConstants.ets\n@@ -63,4 +63,8 @@ export class CommonConstants {\n public static readonly WINDOW_RATIO: number = 0.9;\n public static readonly MIN_WINDOW_WIDTH: number = 1440;\n public static readonly MIN_WINDOW_HEIGHT: number = 940;\n+ // Unlimited Lines\n+ public static readonly UNLIMITED_LINES: number = 1000;\n+ // Break Word Offset\n+ public static readonly BREAK_WORD_OFFSET: number = 5;\n }\n\\ No newline at end of file\ndiff --git a/common/src/main/ets/util/ResourceUtil.ets b/common/src/main/ets/util/ResourceUtil.ets\nindex 6689a91c..97b122e3 100644\n--- a/common/src/main/ets/util/ResourceUtil.ets\n+++ b/common/src/main/ets/util/ResourceUtil.ets\n@@ -59,6 +59,26 @@ export class ResourceUtil {\n }\n }\n \n+ /**\n+ * Obtains the number result with a specified resource.\n+ *\n+ * @param resource resource.\n+ */\n+ public static getResourceNumber(context: Context, resource: Resource): number {\n+ if (ResourceUtil.isEmptyObj(resource)) {\n+ Logger.error(TAG, '[getResourceString] resource is empty.');\n+ return 0;\n+ }\n+ let num: number = 0;\n+ try {\n+ num = context.resourceManager.getNumber(resource.id);\n+ } catch (error) {\n+ const err: BusinessError = error as BusinessError;\n+ Logger.error(TAG, `[getResourceString]getStringSync failed, error: ${err.code}, ${err.message}.`);\n+ }\n+ return num;\n+ }\n+\n /**\n * Check whether the object is empty.\n *\ndiff --git a/common/src/main/ets/util/TextOverflowUtil.ets b/common/src/main/ets/util/TextOverflowUtil.ets\nnew file mode 100644\nindex 00000000..9000e114\n--- /dev/null\n+++ b/common/src/main/ets/util/TextOverflowUtil.ets\n@@ -0,0 +1,63 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+import { CommonConstants } from '../constant/CommonConstants';\n+\n+const TAG = '[TextOverflowUtil]';\n+\n+export interface TextOverflowData {\n+ overflowStatus: boolean;\n+ breakWordIndex?: number;\n+}\n+\n+export interface TextOverflowProperty {\n+ constraintWidth: Length;\n+ lineHeight: Length;\n+ fontSize: Length;\n+ fontWeight: FontWeight;\n+ wordBreak: WordBreak;\n+}\n+\n+export class TextOverflowUtil {\n+ public static getOverflowData(uiContext: UIContext, textContent: string, maxLine: number,\n+ textOverflowProperty: TextOverflowProperty): TextOverflowData {\n+ for (let i = 0; i <= textContent.toString().length; i++) {\n+ const subStr: string = textContent.substring(0, i);\n+ const heightOfLimit: Length | undefined =\n+ TextOverflowUtil.getTextHeight(uiContext, subStr, textOverflowProperty, maxLine);\n+ const heightOfUnlimit: Length | undefined =\n+ TextOverflowUtil.getTextHeight(uiContext, subStr, textOverflowProperty, CommonConstants.UNLIMITED_LINES);\n+ if (heightOfLimit && heightOfUnlimit && heightOfLimit !== heightOfUnlimit) {\n+ return { overflowStatus: true, breakWordIndex: i - CommonConstants.BREAK_WORD_OFFSET };\n+ }\n+ }\n+ return { overflowStatus: false };\n+ }\n+\n+ public static getTextHeight(uiContext: UIContext, textContent: string,\n+ textOverflowProperty: TextOverflowProperty, maxLines: number): Length | undefined {\n+ return uiContext.getMeasureUtils()\n+ .measureTextSize({\n+ maxLines: maxLines,\n+ textContent: textContent,\n+ overflow: TextOverflow.Ellipsis,\n+ fontSize: textOverflowProperty.fontSize,\n+ wordBreak: textOverflowProperty.wordBreak,\n+ fontWeight: textOverflowProperty.fontWeight,\n+ lineHeight: textOverflowProperty.lineHeight,\n+ constraintWidth: textOverflowProperty.constraintWidth,\n+ })\n+ .height;\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/common/src/main/ets/util/VersionUtil.ets b/common/src/main/ets/util/VersionUtil.ets\nnew file mode 100644\nindex 00000000..dafa6e03\n--- /dev/null\n+++ b/common/src/main/ets/util/VersionUtil.ets\n@@ -0,0 +1,25 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { deviceInfo } from '@kit.BasicServicesKit';\n+\n+export class VersionUtil {\n+ public static canUseHds(): boolean {\n+ if (deviceInfo.sdkApiVersion >= 20 && canIUse('SystemCapability.UIDesign.HDSComponent.Core')) {\n+ return true;\n+ }\n+ return false;\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/common/src/main/resources/rawfile/mockdata/sample-details-all.json b/common/src/main/resources/rawfile/mockdata/sample-details-all.json\nindex 7c474c25..6f0c6dbc 100644\n--- a/common/src/main/resources/rawfile/mockdata/sample-details-all.json\n+++ b/common/src/main/resources/rawfile/mockdata/sample-details-all.json\n@@ -115,7 +115,7 @@\n {\n \"id\": 16,\n \"title\": \"一多导航栏\",\n- \"desc\": \"本示例基于自适应布局和响应式布局,实现多设备上的分级导航栏效果。在sm、md断点下,展示为底部页签和顶部页签;在lg断点下,展示为侧边页签和顶部页签;在xl断点下,展示为侧边栏分级导航。为开发者提供分级导航栏的开发方案。\",\n+ \"desc\": \"本示例基于自适应布局和响应式布局,为开发者提供多设备分级导航栏的开发方案。在sm、md断点下,展示为底部页签和顶部页签;在lg断点下,展示为侧边页签和顶部页签;在xl断点下,展示为侧边栏分级导航。\",\n \"preInstalled\": false,\n \"sampleType\": \"commonSample\",\n \"isFavorite\": false,\n@@ -255,7 +255,7 @@\n {\n \"id\": 35,\n \"title\": \"常见Tab导航样式合集\",\n- \"desc\": \"Tabs组件可以让用户能聚焦于当前显示的内容,对页面内容进行分类,提高页面空间利用率。本示例基于Tabs组件,为开发者提供不同场景下的导航样式,如:常见底部导航、舵式底部导航、可滑动+更多按钮样式、侧边导航等。\",\n+ \"desc\": \"Tabs组件可以让用户能聚焦于当前显示的内容,对页面内容进行分类,提高页面空间利用率。本示例基于Tabs组件,为开发者提供不同场景下的导航样式,如:常见底部导航、舵式底部导航、侧边导航等。\",\n \"preInstalled\": false,\n \"sampleType\": \"commonSample\",\n \"isFavorite\": false,\n@@ -318,7 +318,7 @@\n {\n \"id\": 43,\n \"title\": \"组件堆叠\",\n- \"desc\": \"本示例介绍运用Stack组件以构建多层次堆叠的视觉效果。通过绑定Scroll组件的onScrollFrameBegin滚动事件回调函数,精准捕获滚动动作的发生。当滚动时,实时地调节组件的透明度、高度等属性,从而成功实现了嵌套滚动效果、透明度动态变化以及平滑的组件切换。\",\n+ \"desc\": \"本示例介绍通过Stack组件构建多层次堆叠的视觉效果。通过绑定Scroll组件的onScrollFrameBegin滚动事件。当滚动时,实时地调节组件的透明度、高度等属性。实现了嵌套滚动、透明度动态变化以及平滑的组件切换。\",\n \"preInstalled\": false,\n \"sampleType\": \"commonSample\",\n \"isFavorite\": false,\n@@ -478,8 +478,8 @@\n },\n {\n \"id\": 51,\n- \"title\": \"基于AudioRenderer的音频播控和多场景交互\",\n- \"desc\": \"本场景解决方案主要面向前台音频开发人员。指导开发者基于AudioRenderer开发音频播控功能。功能包括后台播放、和播控中心的交互、适配不同类型的焦点打断策略、切换路由发声设备、切换输出设备等基础音频常见功能。\",\n+ \"title\": \"AudioRenderer音频播控\",\n+ \"desc\": \"本场景解决方案主要面向前台音频开发人员。指导开发者基于AudioRenderer开发音频播控功能。功能包括后台播放、和播控中心交互、适配不同类型的焦点打断策略、切换路由发声设备、切换输出设备等音频常见功能。\",\n \"preInstalled\": false,\n \"sampleType\": \"commonSample\",\n \"isFavorite\": false,\n@@ -528,7 +528,7 @@\n {\n \"id\": 49,\n \"title\": \"定位服务\",\n- \"desc\": \"本示例通过@kit.LocationKit中的geoLocationManager实现获取缓存位置、获取当前位置,同时运用map.Marker将位置信息标记在地图上。开发者可以在需要用到设备位置信息的开发场景中,如查看所在城市天气、出行打车、旅行导航以及观察运动轨迹等,集成本示例代码实现定位功能。\",\n+ \"desc\": \"本示例通过@kit.LocationKit中的geoLocationManager实现获取缓存位置、获取当前位置,同时运用map.Marker将位置信息标记在地图上。开发者可以在查看所在城市、出行打车、旅行导航等场景使用该能力。\",\n \"preInstalled\": false,\n \"sampleType\": \"commonSample\",\n \"isFavorite\": false,\n@@ -605,7 +605,7 @@\n {\n \"id\": 47,\n \"title\": \"UI框架-软键盘弹出\",\n- \"desc\": \"本示例展示了输入框分别在屏幕顶部和底部时软键盘弹出对页面布局的影响,通过设置软键盘的避让模式为KeyboardAvoidMode.RESIZE、设置NavDestination的mode为NavDestinationMode.DIALOG等方式实现布局的避让,帮助开发者在多种软件盘弹出场景下实现合理的页面布局。\",\n+ \"desc\": \"本示例展示了输入框分别在屏幕顶部和底部时软键盘弹出对页面布局的影响,通过设置软键盘的避让模式为KeyboardAvoidMode.RESIZE、设置NavDestination的mode为NavDestinationMode.DIALOG等方式实现布局避让。\",\n \"preInstalled\": false,\n \"sampleType\": \"commonSample\",\n \"isFavorite\": false,\ndiff --git a/common/src/main/resources/rawfile/mockdata/sample-page.json b/common/src/main/resources/rawfile/mockdata/sample-page.json\nindex 1bfb37b5..626fcd48 100644\n--- a/common/src/main/resources/rawfile/mockdata/sample-page.json\n+++ b/common/src/main/resources/rawfile/mockdata/sample-page.json\n@@ -641,7 +641,7 @@\n \"cardId\": 1,\n \"mediaType\": 1,\n \"mediaUrl\": \"image/sample/function/media/sample_audio_interaction.png\",\n- \"title\": \"基于AudioRenderer的音频播控和多场景交互\",\n+ \"title\": \"AudioRenderer音频播控\",\n \"subTitle\": \"本场景解决方案主要面向前台音频开发人员。指导开发者基于AudioRenderer开发音频播控功能。功能包括后台播放、和播控中心的交互、适配不同类型的焦点打断策略、切换路由发声设备、切换输出设备等基础音频常见功能。\",\n \"tags\": [\n \"音频播放;播控中心交互\"\ndiff --git a/features/commonbusiness/src/main/ets/model/FullScreenNavigationData.ets b/features/commonbusiness/src/main/ets/model/FullScreenNavigationData.ets\nindex 30c3362c..6df89a4b 100644\n--- a/features/commonbusiness/src/main/ets/model/FullScreenNavigationData.ets\n+++ b/features/commonbusiness/src/main/ets/model/FullScreenNavigationData.ets\n@@ -15,6 +15,7 @@\n \n import { TopNavigationData } from '@ohos/common';\n \n+@Observed\n export class FullScreenNavigationData extends TopNavigationData {\n public titleOffsetY: number = 0;\n public titleScale: number = 1;\ndiff --git a/features/commonbusiness/src/main/ets/view/BaseHomeView.ets b/features/commonbusiness/src/main/ets/view/BaseHomeView.ets\nindex e161082c..6c85c3c2 100644\n--- a/features/commonbusiness/src/main/ets/view/BaseHomeView.ets\n+++ b/features/commonbusiness/src/main/ets/view/BaseHomeView.ets\n@@ -14,7 +14,7 @@\n */\n \n import type { GlobalInfoModel, LoadingModel } from '@ohos/common';\n-import { LoadingFailedView, LoadingStatus, LoadingView, NoNetworkView, StorageKey } from '@ohos/common';\n+import { LoadingFailedView, LoadingStatus, LoadingView, NoNetworkView, StorageKey, VersionUtil } from '@ohos/common';\n \n @Component\n export struct BaseHomeView {\n@@ -40,7 +40,9 @@ export struct BaseHomeView {\n this.reloadData?.();\n })\n }\n- this.topTitleView()\n+ if (!VersionUtil.canUseHds()) {\n+ this.topTitleView()\n+ }\n }\n .backgroundColor($r('sys.color.background_secondary'))\n .width('100%')\ndiff --git a/features/commonbusiness/src/main/ets/viewmodel/BaseHomeState.ets b/features/commonbusiness/src/main/ets/viewmodel/BaseHomeState.ets\nindex 225596fb..a6349d2f 100644\n--- a/features/commonbusiness/src/main/ets/viewmodel/BaseHomeState.ets\n+++ b/features/commonbusiness/src/main/ets/viewmodel/BaseHomeState.ets\n@@ -26,6 +26,7 @@ export class BaseHomeState extends BaseState {\n public bannerHeight: number = 0;\n public currentPage: number = 1;\n public hasEdgeEffect: boolean = false;\n+ public showTab: boolean = false;\n \n public constructor() {\n super();\ndiff --git a/features/commonbusiness/src/main/ets/viewmodel/BaseHomeViewModel.ets b/features/commonbusiness/src/main/ets/viewmodel/BaseHomeViewModel.ets\nindex 9f937d6c..0a2a927a 100644\n--- a/features/commonbusiness/src/main/ets/viewmodel/BaseHomeViewModel.ets\n+++ b/features/commonbusiness/src/main/ets/viewmodel/BaseHomeViewModel.ets\n@@ -14,8 +14,9 @@\n */\n \n import { ConfigurationConstant } from '@kit.AbilityKit';\n-import { curves } from '@kit.ArkUI';\n+import { curves, LengthMetrics } from '@kit.ArkUI';\n import { deviceInfo } from '@kit.BasicServicesKit';\n+import { ScrollEffectType } from '@kit.UIDesignKit';\n import type { GlobalInfoModel } from '@ohos/common';\n import {\n BaseVM,\n@@ -26,6 +27,7 @@ import {\n ProductSeriesEnum,\n StatusBarColorType,\n StorageKey,\n+ VersionUtil,\n WindowUtil,\n } from '@ohos/common';\n import type { BannerData } from '../model/BannerData';\n@@ -53,7 +55,8 @@ export class BaseHomeViewModel<T extends BaseHomeState> extends BaseVM<BaseHomeS\n const globalInfoModel: GlobalInfoModel = AppStorage.get(StorageKey.GLOBAL_INFO)!;\n const isLargeWidth: boolean = (globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_LG ||\n globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL);\n- this.state.topNavigationData.bgColor = isLargeWidth ? '#FFF1F3F5' : '#00FFFFFF';\n+ this.state.topNavigationData.bgColor =\n+ isLargeWidth ? $r('sys.color.background_secondary') : $r('sys.color.ohos_id_color_background_transparent');\n this.state.topNavigationData.titleColor = isLargeWidth ? StatusBarColorType.BLACK : StatusBarColorType.WHITE;\n const naviTitleHeight: number =\n globalInfoModel.statusBarHeight + CommonConstants.NAVIGATION_HEIGHT + CommonConstants.SPACE_8;\n@@ -67,6 +70,7 @@ export class BaseHomeViewModel<T extends BaseHomeState> extends BaseVM<BaseHomeS\n }).getValue(globalInfoModel.widthBreakpoint);\n this.state.bannerHeight = this.state.bannerState.bannerHeight;\n this.originBannerHeight = this.state.bannerHeight;\n+ this.setTitleBarStyle();\n }\n \n public getState(): T {\n@@ -135,6 +139,7 @@ export class BaseHomeViewModel<T extends BaseHomeState> extends BaseVM<BaseHomeS\n \n protected handleBreakpointChange(offsetParam: OffsetParam) {\n this.changeBannerHeight();\n+ this.setTitleBarStyle();\n offsetParam.breakpointChange = true;\n this.handleListOffset(offsetParam);\n }\n@@ -182,6 +187,7 @@ export class BaseHomeViewModel<T extends BaseHomeState> extends BaseVM<BaseHomeS\n const marginTop: number = globalInfoModel.statusBarHeight + CommonConstants.NAVIGATION_HEIGHT;\n const showTabOffset: number = this.state.bannerState.bannerHeight - marginTop;\n this.state.topNavigationData.showTab = (offsetParam.yOffset >= showTabOffset);\n+ this.state.showTab = this.state.topNavigationData.showTab;\n }\n \n if (offsetParam.yOffset > this.state.bannerState.bannerHeight ||\n@@ -189,7 +195,8 @@ export class BaseHomeViewModel<T extends BaseHomeState> extends BaseVM<BaseHomeS\n globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL) {\n if (offsetParam.breakpointChange) {\n this.state.topNavigationData.isBlur = true;\n- if (offsetParam.tabIndex === AppStorage.get(StorageKey.CURRENT_TAB) && pageContext.navPathStack.size() === 1) {\n+ if (!VersionUtil.canUseHds() && offsetParam.tabIndex === AppStorage.get(StorageKey.CURRENT_TAB) &&\n+ pageContext.navPathStack.size() === 1) {\n WindowUtil.updateStatusBarColor(isDark);\n }\n TAB_CONTENT_STATUSES[offsetParam.tabIndex] = false;\n@@ -224,7 +231,8 @@ export class BaseHomeViewModel<T extends BaseHomeState> extends BaseVM<BaseHomeS\n this.state.topNavigationData.isBlur = false;\n TAB_CONTENT_STATUSES[offsetParam.tabIndex] = true;\n }\n- if (offsetParam.tabIndex === AppStorage.get(StorageKey.CURRENT_TAB) && pageContext.navPathStack.size() === 1) {\n+ if (!VersionUtil.canUseHds() && offsetParam.tabIndex === AppStorage.get(StorageKey.CURRENT_TAB) &&\n+ pageContext.navPathStack.size() === 1) {\n WindowUtil.updateStatusBarColor(opacity > 0 ? isDark : true);\n }\n let colorData: number = 255;\n@@ -299,6 +307,74 @@ export class BaseHomeViewModel<T extends BaseHomeState> extends BaseVM<BaseHomeS\n this.state.topNavigationData.titleScale = 1;\n });\n }\n+\n+ private setTitleBarStyle() {\n+ if (VersionUtil.canUseHds()) {\n+ const globalInfoModel: GlobalInfoModel = AppStorage.get(StorageKey.GLOBAL_INFO)!;\n+ this.state.topNavigationData.hdsTitleBarPadding = {\n+ start:\n+ LengthMetrics.vp(new BreakpointType<number>({\n+ sm: CommonConstants.SPACE_16,\n+ md: CommonConstants.SPACE_24,\n+ lg: CommonConstants.SPACE_32 + CommonConstants.TAB_BAR_WIDTH,\n+ xl: CommonConstants.SPACE_32,\n+ }).getValue(globalInfoModel.widthBreakpoint)),\n+ end:\n+ LengthMetrics.vp(new BreakpointType<number>({\n+ sm: CommonConstants.SPACE_16,\n+ md: CommonConstants.SPACE_24,\n+ lg: CommonConstants.SPACE_32,\n+ xl: CommonConstants.SPACE_32,\n+ }).getValue(globalInfoModel.widthBreakpoint)),\n+ };\n+ this.state.topNavigationData.hdsTitleBarStyle = {\n+ scrollEffectOpts: {\n+ enableScrollEffect: true,\n+ scrollEffectType: ScrollEffectType.COMMON_BLUR,\n+ blurEffectiveStartOffset: LengthMetrics.vp(new BreakpointType<number>({\n+ sm: this.state.bannerHeight - 160 - globalInfoModel.statusBarHeight,\n+ md: this.state.bannerHeight - 160 - globalInfoModel.statusBarHeight,\n+ lg: 0,\n+ xl: 0,\n+ }).getValue(globalInfoModel.widthBreakpoint)),\n+ blurEffectiveEndOffset: LengthMetrics.vp(new BreakpointType<number>({\n+ sm: this.state.bannerHeight,\n+ md: this.state.bannerHeight,\n+ lg: CommonConstants.NAVIGATION_HEIGHT,\n+ xl: CommonConstants.NAVIGATION_HEIGHT,\n+ }).getValue(globalInfoModel.widthBreakpoint)),\n+ },\n+ originalStyle: {\n+ backgroundStyle: {\n+ backgroundColor: new BreakpointType<ResourceColor>({\n+ sm: $r('sys.color.ohos_id_color_background_transparent'),\n+ md: $r('sys.color.ohos_id_color_background_transparent'),\n+ lg: $r('sys.color.background_secondary')\n+ }).getValue(globalInfoModel.widthBreakpoint),\n+ },\n+ contentStyle: {\n+ titleStyle: {\n+ mainTitleColor: new BreakpointType<ResourceColor>({\n+ sm: $r('sys.color.font_on_primary'),\n+ md: $r('sys.color.font_on_primary'),\n+ lg: $r('sys.color.font_primary')\n+ }).getValue(globalInfoModel.widthBreakpoint),\n+ },\n+ },\n+ },\n+ scrollEffectStyle: {\n+ backgroundStyle: {\n+ backgroundColor: $r('sys.color.ohos_id_color_background_transparent'),\n+ },\n+ contentStyle: {\n+ titleStyle: {\n+ mainTitleColor: $r('sys.color.font_primary'),\n+ },\n+ },\n+ },\n+ };\n+ }\n+ }\n }\n \n export interface CalculateHeightParam {\ndiff --git a/features/componentlibrary/src/main/ets/component/CodeLabCard.ets b/features/componentlibrary/src/main/ets/component/CodeLabCard.ets\nindex 52ce40bf..13019851 100644\n--- a/features/componentlibrary/src/main/ets/component/CodeLabCard.ets\n+++ b/features/componentlibrary/src/main/ets/component/CodeLabCard.ets\n@@ -16,6 +16,7 @@\n import { deviceInfo } from '@kit.BasicServicesKit';\n import { ProductSeriesEnum } from '@ohos/common';\n import type { ComponentCardData, ComponentContent } from '../model/ComponentData';\n+import { ComponentItemList, ItemSuffixType } from './ComponentItemList';\n \n @Reusable\n @Component\n@@ -55,42 +56,12 @@ export struct CodeLabCard {\n .fontColor($r('sys.color.font_on_primary'))\n .fontWeight(FontWeight.Bold)\n .margin({ left: $r('sys.float.padding_level6'), bottom: $r('sys.float.padding_level2') })\n- Row() {\n- Image($rawfile(this.content?.mediaUrl))\n- .draggable(false)\n- .width($r('app.float.tip_image_height'))\n- .borderRadius($r('sys.float.corner_radius_level5'))\n- .aspectRatio(1)\n- Column() {\n- Text(this.content?.subTitle)\n- .fontSize($r('sys.float.Subtitle_M'))\n- .textOverflow({ overflow: TextOverflow.Ellipsis })\n- .fontColor($r('sys.color.font_on_primary'))\n- .fontWeight(FontWeight.Medium)\n- .margin({ bottom: $r('sys.float.padding_level4') })\n- Text(this.content?.title)\n- .fontSize($r('sys.float.Body_S'))\n- .textOverflow({ overflow: TextOverflow.Ellipsis })\n- .fontColor($r('sys.color.font_on_primary'))\n- .maxLines(1)\n- }\n- .alignItems(HorizontalAlign.Start)\n- .padding({ left: $r('sys.float.padding_level6'), right: $r('sys.float.padding_level8') })\n- .layoutWeight(1)\n-\n- Button() {\n- SymbolGlyph($r('sys.symbol.chevron_right'))\n- .fontColor([$r('sys.color.icon_secondary')])\n- .fontSize($r('sys.float.Title_M'))\n- }\n- .backgroundColor($r('sys.color.comp_background_primary'))\n- .width($r('app.float.card_button_height'))\n- .aspectRatio(1)\n- }\n- .padding($r('sys.float.padding_level6'))\n- .width('100%')\n- .height($r('app.float.codelab_content_height'))\n- .backgroundColor($r('sys.color.comp_background_secondary'))\n+ ComponentItemList({\n+ cardContents: this.componentCardData?.cardContents,\n+ suffixType: ItemSuffixType.ICON,\n+ itemHeight: $r('app.float.codelab_content_height'),\n+ widthBreakpoint:WidthBreakpoint.WIDTH_SM,\n+ })\n }\n .renderGroup(true)\n .height($r('app.float.card_content_height'))\ndiff --git a/features/componentlibrary/src/main/ets/component/ComponentItem.ets b/features/componentlibrary/src/main/ets/component/ComponentItem.ets\ndeleted file mode 100644\nindex de6447df..00000000\n--- a/features/componentlibrary/src/main/ets/component/ComponentItem.ets\n+++ /dev/null\n@@ -1,75 +0,0 @@\n-/*\n- * Copyright (c) 2024 Huawei Device Co., Ltd.\n- * Licensed under the Apache License, Version 2.0 (the \"License\");\n- * you may not use this file except in compliance with the License.\n- * You may obtain a copy of the License at\n- *\n- * http://www.apache.org/licenses/LICENSE-2.0\n- *\n- * Unless required by applicable law or agreed to in writing, software\n- * distributed under the License is distributed on an \"AS IS\" BASIS,\n- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n- * See the License for the specific language governing permissions and\n- * limitations under the License.\n- */\n-\n-import { CommonConstants } from '@ohos/common';\n-import type { ComponentContent } from '../model/ComponentData';\n-\n-@Component\n-export struct ComponentItem {\n- @Prop componentContent: ComponentContent;\n- @Prop showDivider: boolean;\n- @Prop buttonColor: ResourceColor = $r('sys.color.interactive_active');\n- @Prop @Require widthBreakpoint: WidthBreakpoint;\n-\n- build() {\n- Column() {\n- Divider()\n- .visibility(this.showDivider ? Visibility.Visible : Visibility.Hidden)\n- .color($r('sys.color.comp_background_tertiary'))\n- .margin({ left: $r('sys.float.padding_level36'), right: $r('sys.float.padding_level6') })\n- Row() {\n- Image($rawfile(this.componentContent.mediaUrl))\n- .draggable(false)\n- .alt($r('app.media.ic_placeholder'))\n- .borderRadius($r('sys.float.corner_radius_level5'))\n- .width($r('app.float.tip_image_height'))\n- .aspectRatio(1)\n- .margin({ right: $r('sys.float.padding_level8') })\n-\n- Column({ space: CommonConstants.SPACE_6 }) {\n- Text(this.componentContent.subTitle)\n- .fontSize($r('sys.float.Subtitle_M'))\n- .fontWeight(FontWeight.Medium)\n- .fontColor($r('sys.color.font_primary'))\n- .maxLines(1)\n- .textOverflow({ overflow: TextOverflow.Ellipsis })\n- Text(this.componentContent.title)\n- .fontSize($r('sys.float.Body_S'))\n- .fontColor($r('sys.color.font_secondary'))\n- .maxLines(1)\n- .textOverflow({ overflow: TextOverflow.Ellipsis })\n- }\n- .alignItems(HorizontalAlign.Start)\n- .layoutWeight(1)\n-\n- Button($r('app.string.open'),\n- { type: ButtonType.Normal, buttonStyle: ButtonStyleMode.NORMAL, controlSize: ControlSize.SMALL })\n- .borderRadius(this.widthBreakpoint === WidthBreakpoint.WIDTH_XL ?\n- $r('sys.float.corner_radius_level4') : '50%')\n- .margin({ left: $r('sys.float.padding_level8') })\n- .width($r('app.float.tip_button_width'))\n- .fontColor(this.buttonColor)\n-\n- }\n- .width('100%')\n- .layoutWeight(1)\n- .padding($r('sys.float.padding_level6'))\n- }\n- .renderGroup(true)\n- .alignItems(HorizontalAlign.Start)\n- .height($r('app.float.component_item_height'))\n- .width('100%')\n- }\n-}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/component/ComponentItemList.ets b/features/componentlibrary/src/main/ets/component/ComponentItemList.ets\nnew file mode 100644\nindex 00000000..7685d6c2\n--- /dev/null\n+++ b/features/componentlibrary/src/main/ets/component/ComponentItemList.ets\n@@ -0,0 +1,185 @@\n+/*\n+ * Copyright (c) 2024 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { TextModifier } from '@kit.ArkUI';\n+import { HdsListItemCard, PrefixCustomBuilder, SuffixButton, SuffixCustomBuilder, } from '@kit.UIDesignKit';\n+import { CommonConstants, ResourceUtil, VersionUtil } from '@ohos/common';\n+import type { ComponentContent } from '../model/ComponentData';\n+\n+export enum ItemSuffixType {\n+ BUTTON = 'button',\n+ ICON = 'icon',\n+}\n+\n+@Component\n+export struct ComponentItemList {\n+ @Prop @Require cardContents: ComponentContent[];\n+ @Prop @Require widthBreakpoint: WidthBreakpoint;\n+ @Prop itemHeight: Resource = $r('app.float.component_item_height');\n+ @Prop suffixType: ItemSuffixType = ItemSuffixType.BUTTON;\n+ @Prop buttonColor: ResourceColor = $r('sys.color.interactive_active')\n+ handleItemClick?: Function;\n+\n+ @Builder\n+ CircleArrowBuilder() {\n+ Row() {\n+ CircleArrow()\n+ }\n+ .padding({ right: $r('sys.float.padding_level6') })\n+ }\n+\n+ @Builder\n+ IconBuilder(iconUrl: string) {\n+ Row() {\n+ ComponentIcon({ iconUrl })\n+ }\n+ .padding({ right: $r('sys.float.padding_level8') })\n+ }\n+\n+ build() {\n+ List() {\n+ Repeat(this.cardContents)\n+ .each((repeatItem: RepeatItem<ComponentContent>) => {\n+ ListItem() {\n+ if (VersionUtil.canUseHds()) {\n+ HdsListItemCard({\n+ prefixItem: new PrefixCustomBuilder(() => this.IconBuilder(repeatItem.item.mediaUrl)),\n+ textItem: {\n+ primaryText: {\n+ text: repeatItem.item.subTitle,\n+ modifier: this.suffixType === ItemSuffixType.ICON ?\n+ new TextModifier().fontColor($r('sys.color.font_on_primary')) : undefined,\n+ },\n+ secondaryText: {\n+ text: repeatItem.item.title,\n+ modifier: this.suffixType === ItemSuffixType.ICON ?\n+ new TextModifier().fontColor($r('sys.color.font_on_primary')) : undefined,\n+ }\n+ },\n+ suffixItem: this.suffixType === ItemSuffixType.BUTTON ?\n+ new SuffixButton({ text: $r('app.string.open'), textColor: this.buttonColor }) :\n+ new SuffixCustomBuilder(() => this.CircleArrowBuilder()),\n+ cardHeight: this.itemHeight,\n+ cardPrefixMargin: $r('sys.float.padding_level6'),\n+ cardSuffixMargin: $r('sys.float.padding_level2'),\n+ cardBorderRadius: 0,\n+ cardBackgroundColor: $r('sys.color.ohos_id_color_background_transparent'),\n+ })\n+ } else {\n+ ComponentItem({\n+ componentContent: repeatItem.item,\n+ widthBreakpoint: this.widthBreakpoint,\n+ buttonColor: this.buttonColor,\n+ suffixType: this.suffixType,\n+ itemHeight: this.itemHeight,\n+ })\n+ }\n+ }\n+ .onClick(() => {\n+ this.handleItemClick?.(repeatItem.item);\n+ })\n+ })\n+ .key((componentContent: ComponentContent) => componentContent.id.toString())\n+ }\n+ .divider({\n+ strokeWidth: '1px',\n+ color: $r('sys.color.comp_background_tertiary'),\n+ startMargin: $r('sys.float.padding_level36'),\n+ endMargin: $r('sys.float.padding_level6')\n+ })\n+ .scrollBar(BarState.Off)\n+ .edgeEffect(EdgeEffect.None)\n+ .width('100%')\n+ .height(this.cardContents.length *\n+ this.getUIContext().px2vp(ResourceUtil.getResourceNumber(this.getUIContext().getHostContext(), this.itemHeight)))\n+ }\n+}\n+\n+@Component\n+struct CircleArrow {\n+ build() {\n+ Button() {\n+ SymbolGlyph($r('sys.symbol.chevron_right'))\n+ .fontColor([$r('sys.color.icon_secondary')])\n+ .fontSize($r('sys.float.Title_M'))\n+ }\n+ .backgroundColor($r('sys.color.comp_background_primary'))\n+ .width($r('app.float.card_button_height'))\n+ .aspectRatio(1)\n+ }\n+}\n+\n+@Component\n+struct ComponentIcon {\n+ @Prop @Require iconUrl: string;\n+\n+ build() {\n+ Image($rawfile(this.iconUrl))\n+ .draggable(false)\n+ .alt($r('app.media.ic_placeholder'))\n+ .borderRadius($r('sys.float.corner_radius_level5'))\n+ .width($r('app.float.tip_image_height'))\n+ .aspectRatio(1)\n+ }\n+}\n+\n+@Component\n+struct ComponentItem {\n+ @Prop componentContent: ComponentContent;\n+ @Prop itemHeight: Length = $r('app.float.component_item_height');\n+ @Prop buttonColor: ResourceColor = $r('sys.color.interactive_active');\n+ @Prop suffixType: ItemSuffixType = ItemSuffixType.BUTTON;\n+ @Prop @Require widthBreakpoint: WidthBreakpoint;\n+\n+ build() {\n+ Row() {\n+ ComponentIcon({ iconUrl: this.componentContent.mediaUrl })\n+ .margin({ right: $r('sys.float.padding_level8') })\n+ Column({ space: CommonConstants.SPACE_6 }) {\n+ Text(this.componentContent.subTitle)\n+ .fontSize($r('sys.float.Subtitle_M'))\n+ .fontWeight(FontWeight.Medium)\n+ .fontColor(this.suffixType === ItemSuffixType.BUTTON ? $r('sys.color.font_primary') :\n+ $r('sys.color.font_on_primary'))\n+ .maxLines(1)\n+ .textOverflow({ overflow: TextOverflow.Ellipsis })\n+ Text(this.componentContent.title)\n+ .fontSize($r('sys.float.Body_S'))\n+ .fontColor(this.suffixType === ItemSuffixType.BUTTON ? $r('sys.color.font_secondary') :\n+ $r('sys.color.font_on_primary'))\n+ .maxLines(1)\n+ .textOverflow({ overflow: TextOverflow.Ellipsis })\n+ }\n+ .alignItems(HorizontalAlign.Start)\n+ .layoutWeight(1)\n+\n+ if (this.suffixType === ItemSuffixType.BUTTON) {\n+ Button($r('app.string.open'),\n+ { type: ButtonType.Normal, buttonStyle: ButtonStyleMode.NORMAL, controlSize: ControlSize.SMALL })\n+ .borderRadius(this.widthBreakpoint === WidthBreakpoint.WIDTH_XL ?\n+ $r('sys.float.corner_radius_level4') : '50%')\n+ .margin({ left: $r('sys.float.padding_level8') })\n+ .width($r('app.float.tip_button_width'))\n+ .fontColor(this.buttonColor)\n+ } else {\n+ CircleArrow()\n+ }\n+ }\n+ .width('100%')\n+ .height(this.itemHeight)\n+ .padding($r('sys.float.padding_level6'))\n+ .renderGroup(true)\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/component/ListCard.ets b/features/componentlibrary/src/main/ets/component/ListCard.ets\nindex f6d053cd..6a314d08 100644\n--- a/features/componentlibrary/src/main/ets/component/ListCard.ets\n+++ b/features/componentlibrary/src/main/ets/component/ListCard.ets\n@@ -16,7 +16,7 @@\n import { GlobalInfoModel, StorageKey } from '@ohos/common';\n import { BreakpointType, CommonConstants } from '@ohos/common';\n import type { ComponentCardData, ComponentContent } from '../model/ComponentData';\n-import { ComponentItem } from './ComponentItem';\n+import { ComponentItemList } from './ComponentItemList';\n \n @Reusable\n @Component\n@@ -49,18 +49,13 @@ export struct ListCard {\n .alignItems(HorizontalAlign.Start)\n .height(CommonConstants.NAVIGATION_HEIGHT)\n \n- Repeat(this.componentCardData?.cardContents)\n- .each((repeatItem: RepeatItem<ComponentContent>) => {\n- ComponentItem({\n- componentContent: repeatItem.item,\n- showDivider: repeatItem.index !== 0,\n- widthBreakpoint: this.globalInfoModel.widthBreakpoint\n- })\n- .onClick(() => {\n- this.handleItemClick?.(repeatItem.item);\n- })\n- })\n- .key((componentContent: ComponentContent) => componentContent.id.toString())\n+ ComponentItemList({\n+ cardContents: this.componentCardData?.cardContents,\n+ widthBreakpoint: this.globalInfoModel.widthBreakpoint,\n+ handleItemClick: (item: ComponentContent) => {\n+ this.handleItemClick?.(item);\n+ }\n+ })\n }\n .backgroundColor($r('sys.color.comp_background_primary'))\n .border({\ndiff --git a/features/componentlibrary/src/main/ets/component/PictureListCard.ets b/features/componentlibrary/src/main/ets/component/PictureListCard.ets\nindex 8632e16c..a55c896c 100644\n--- a/features/componentlibrary/src/main/ets/component/PictureListCard.ets\n+++ b/features/componentlibrary/src/main/ets/component/PictureListCard.ets\n@@ -16,7 +16,7 @@\n import { deviceInfo } from '@kit.BasicServicesKit';\n import { ImageUtil, ProductSeriesEnum } from '@ohos/common';\n import type { ComponentCardData, ComponentContent } from '../model/ComponentData';\n-import { ComponentItem } from './ComponentItem';\n+import { ComponentItemList } from './ComponentItemList';\n \n @Reusable\n @Component\n@@ -62,7 +62,7 @@ export struct PictureListCard {\n .padding($r('sys.float.padding_level6'))\n .width('100%')\n .height(deviceInfo.productSeries === ProductSeriesEnum.VDE ? $r('app.float.card_top_height_verde') :\n- $r('app.float.card_top_height'))\n+ $r('app.float.card_top_height'))\n .margin({ bottom: $r('sys.float.padding_level2') })\n }\n \n@@ -71,31 +71,26 @@ export struct PictureListCard {\n Image($rawfile(this.componentCardData?.cardImage))\n .width('100%')\n .height(deviceInfo.productSeries === ProductSeriesEnum.VDE ? $r('app.float.card_top_height_verde') :\n- $r('app.float.card_top_height'))\n+ $r('app.float.card_top_height'))\n .overlay(this.textOverlay())\n .objectFit(ImageFit.Cover)\n .alt($r('app.media.ic_placeholder'))\n .margin({ bottom: $r('sys.float.padding_level2') })\n \n- Repeat(this.componentCardData?.cardContents)\n- .each((repeatItem: RepeatItem<ComponentContent>) => {\n- ComponentItem({\n- componentContent: repeatItem.item,\n- showDivider: repeatItem.index !== 0,\n- buttonColor: this.buttonColor,\n- widthBreakpoint: this.widthBreakpoint,\n- })\n- .onClick(() => {\n- this.handleItemClick?.(repeatItem.item);\n- })\n- })\n- .key((componentContent: ComponentContent) => componentContent.id.toString())\n+ ComponentItemList({\n+ cardContents: this.componentCardData?.cardContents,\n+ widthBreakpoint: this.widthBreakpoint,\n+ buttonColor: this.buttonColor,\n+ handleItemClick: (item: ComponentContent) => {\n+ this.handleItemClick?.(item);\n+ }\n+ })\n }\n+ .backgroundColor($r('sys.color.comp_background_list_card'))\n .clickEffect({ level: ClickEffectLevel.MIDDLE })\n .borderRadius($r('sys.float.corner_radius_level8'))\n .clip(true)\n .width('100%')\n- .backgroundColor($r('sys.color.comp_background_list_card'))\n .padding({ bottom: $r('sys.float.padding_level2') })\n }\n }\n\\ No newline at end of file\ndiff --git a/features/componentlibrary/src/main/ets/view/CodePreview.ets b/features/componentlibrary/src/main/ets/view/CodePreview.ets\nindex ced39455..46b89a56 100644\n--- a/features/componentlibrary/src/main/ets/view/CodePreview.ets\n+++ b/features/componentlibrary/src/main/ets/view/CodePreview.ets\n@@ -16,12 +16,14 @@\n import { ConfigurationConstant } from '@kit.AbilityKit';\n import { curves, window } from '@kit.ArkUI';\n import { BusinessError, settings } from '@kit.BasicServicesKit';\n+import { HdsNavDestination, HdsNavDestinationAttribute } from '@kit.UIDesignKit';\n import type { GlobalInfoModel, } from '@ohos/common';\n import {\n CommonConstants,\n Logger,\n ScreenOrientation,\n StorageKey,\n+ VersionUtil,\n WebNodeController,\n WebUtil,\n WindowUtil,\n@@ -54,7 +56,7 @@ export struct CodePreview {\n private context: Context = this.getUIContext().getHostContext() as Context;\n private uiContext: UIContext = this.getUIContext();\n \n- onBackPage(): void {\n+ onBackPage(): boolean {\n this.isBack = true;\n WindowUtil.updateStatusBarColor(this.systemColorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK);\n this.javascriptRun();\n@@ -65,6 +67,7 @@ export struct CodePreview {\n this.uiContext.animateTo({ curve: curves.interpolatingSpring(0, 1, 342, 38) }, () => {\n this.viewModel?.pop(false);\n });\n+ return true;\n }\n \n javascriptRun(): void {\n@@ -133,52 +136,78 @@ export struct CodePreview {\n }\n }\n \n+ handleOnReady(ctx: NavDestinationContext) {\n+ const params: CodeViewParams = ctx.pathInfo.param as CodeViewParams;\n+ this.code = params.code as string;\n+ this.componentName = params.componentName as string;\n+ this.webNodeController = WebUtil.getWebNode(WebUtil.getComponentCodeUrl()) as WebNodeController;\n+ this.preFinishAnimation = params.preFinishAnimation as () => void;\n+ this.codePreviewState = this.viewModel!.getState();\n+ }\n+\n+ @Builder\n+ PreviewContentBuilder() {\n+ Column() {\n+ CodePreviewComponent({\n+ onBackPage: () => {\n+ this.onBackPage();\n+ },\n+ webNodeController: this.webNodeController,\n+ code: this.code,\n+ componentName: this.componentName,\n+ pageContainer: true,\n+ topTranslateY: this.codePreviewState?.topTranslateY,\n+ bottomTranslateY: this.codePreviewState?.bottomTranslateY,\n+ navigationOpacity: this.codePreviewState?.navigationOpacity,\n+ isFocus: this.isFocus,\n+ isBack: this.isBack,\n+ })\n+ }\n+ .geometryTransition(CommonConstants.CODE_PREVIEW_GEOMETRY_ID)\n+ .width('100%')\n+ .height('100%')\n+ }\n+\n build() {\n- NavDestination() {\n- Column() {\n- CodePreviewComponent({\n- onBackPage: () => {\n- this.onBackPage();\n- },\n- webNodeController: this.webNodeController,\n- code: this.code,\n- componentName: this.componentName,\n- pageContainer: true,\n- topTranslateY: this.codePreviewState?.topTranslateY,\n- bottomTranslateY: this.codePreviewState?.bottomTranslateY,\n- navigationOpacity: this.codePreviewState?.navigationOpacity,\n- isFocus: this.isFocus,\n- isBack: this.isBack,\n- })\n+ if (VersionUtil.canUseHds()) {\n+ HdsNavDestination() {\n+ this.PreviewContentBuilder()\n+ }\n+ .hideTitleBar(true)\n+ .onReady((ctx: NavDestinationContext) => this.handleOnReady(ctx))\n+ .onShown(() => {\n+ this.isBack = false;\n+ })\n+ .onFocus(() => {\n+ this.isFocus = true;\n+ })\n+ .onBlur(() => {\n+ this.isFocus = false;\n+ })\n+ .onBackPressed(() => {\n+ return this.onBackPage();\n+ })\n+ } else {\n+ NavDestination() {\n+ this.PreviewContentBuilder()\n }\n- .geometryTransition(CommonConstants.CODE_PREVIEW_GEOMETRY_ID)\n .width('100%')\n .height('100%')\n+ .hideTitleBar(true)\n+ .onReady((ctx: NavDestinationContext) => this.handleOnReady(ctx))\n+ .onFocus(() => {\n+ this.isFocus = true;\n+ })\n+ .onBlur(() => {\n+ this.isFocus = false;\n+ })\n+ .onShown(() => {\n+ this.isBack = false;\n+ })\n+ .onBackPressed(() => {\n+ return this.onBackPage();\n+ })\n }\n- .width('100%')\n- .height('100%')\n- .hideTitleBar(true)\n- .onReady((ctx: NavDestinationContext) => {\n- const params: CodeViewParams = ctx.pathInfo.param as CodeViewParams;\n- this.code = params.code as string;\n- this.componentName = params.componentName as string;\n- this.webNodeController = WebUtil.getWebNode(WebUtil.getComponentCodeUrl()) as WebNodeController;\n- this.preFinishAnimation = params.preFinishAnimation as () => void;\n- this.codePreviewState = this.viewModel!.getState();\n- })\n- .onFocus(() => {\n- this.isFocus = true;\n- })\n- .onBlur(() => {\n- this.isFocus = false;\n- })\n- .onShown(() => {\n- this.isBack = false;\n- })\n- .onBackPressed(() => {\n- this.onBackPage();\n- return true;\n- })\n }\n \n private preFinishAnimation: () => void = () => {\ndiff --git a/features/componentlibrary/src/main/ets/view/ComponentDetailView.ets b/features/componentlibrary/src/main/ets/view/ComponentDetailView.ets\nindex 8e9654d8..3031c120 100644\n--- a/features/componentlibrary/src/main/ets/view/ComponentDetailView.ets\n+++ b/features/componentlibrary/src/main/ets/view/ComponentDetailView.ets\n@@ -15,12 +15,14 @@\n \n import { ConfigurationConstant } from '@kit.AbilityKit';\n import { displaySync } from '@kit.ArkGraphics2D';\n+import { HdsNavDestination, HdsNavDestinationAttribute } from '@kit.UIDesignKit';\n import {\n CommonConstants,\n LoadingStatus,\n Logger,\n StorageKey,\n TopNavigationView,\n+ VersionUtil,\n WebUtil,\n WindowUtil,\n } from '@ohos/common';\n@@ -64,6 +66,15 @@ export struct ComponentDetailView {\n });\n }\n \n+ handleOnReady(ctx: NavDestinationContext) {\n+ const params: ComponentDetailParams = ctx.pathInfo.param as ComponentDetailParams;\n+ this.componentName = params.componentName as string;\n+ this.componentId = Number(params.componentId);\n+ CommonConstants.PROMISE_WAIT(500).then(() => {\n+ this.assignViewData();\n+ });\n+ }\n+\n @Builder\n DetailContentBuilder() {\n DetailContentView({\n@@ -80,33 +91,58 @@ export struct ComponentDetailView {\n })\n }\n \n- build() {\n- NavDestination() {\n- BaseDetailComponent({\n- detailContentView: () => {\n- this.DetailContentBuilder()\n- },\n- topTitleView: () => {\n+ @Builder\n+ ContentBuilder() {\n+ BaseDetailComponent({\n+ detailContentView: () => {\n+ this.DetailContentBuilder()\n+ },\n+ topTitleView: () => {\n+ if (!VersionUtil.canUseHds()) {\n this.TopTitleViewBuilder()\n+ }\n+ },\n+ loadingStatus: this.loadingStatus,\n+ })\n+ .expandSafeArea([SafeAreaType.KEYBOARD, SafeAreaType.SYSTEM])\n+ }\n+\n+ build() {\n+ if (VersionUtil.canUseHds()) {\n+ HdsNavDestination() {\n+ this.ContentBuilder()\n+ }\n+ .hideBackButton(false)\n+ .backgroundColor($r('sys.color.background_secondary'))\n+ .ignoreLayoutSafeArea([LayoutSafeAreaType.SYSTEM], [LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM])\n+ .titleBar({\n+ avoidLayoutSafeArea: true,\n+ style: {\n+ originalStyle: { backgroundStyle: { backgroundColor: Color.Transparent } },\n+ scrollEffectOpts: {\n+ enableScrollEffect: true,\n+ },\n },\n- loadingStatus: this.loadingStatus,\n+ content: {\n+ title: { mainTitle: this.componentDetailState?.topNavigationData.title || '' },\n+ }\n+ })\n+ .onDisAppear(() => {\n+ this.displaySync.stop();\n })\n- .expandSafeArea([SafeAreaType.KEYBOARD, SafeAreaType.SYSTEM])\n+ .onReady((ctx: NavDestinationContext) => this.handleOnReady(ctx))\n+ } else {\n+ NavDestination() {\n+ this.ContentBuilder()\n+ }\n+ .hideTitleBar(true)\n+ .height('100%')\n+ .backgroundColor($r('sys.color.background_secondary'))\n+ .onDisAppear(() => {\n+ this.displaySync.stop();\n+ })\n+ .onReady((ctx: NavDestinationContext) => this.handleOnReady(ctx))\n }\n- .hideTitleBar(true)\n- .height('100%')\n- .backgroundColor($r('sys.color.background_secondary'))\n- .onDisAppear(() => {\n- this.displaySync.stop();\n- })\n- .onReady((ctx: NavDestinationContext) => {\n- const params: ComponentDetailParams = ctx.pathInfo.param as ComponentDetailParams;\n- this.componentName = params.componentName as string;\n- this.componentId = Number(params.componentId);\n- CommonConstants.PROMISE_WAIT(500).then(() => {\n- this.assignViewData();\n- });\n- })\n }\n \n assignViewData() {\ndiff --git a/features/componentlibrary/src/main/ets/view/ComponentListView.ets b/features/componentlibrary/src/main/ets/view/ComponentListView.ets\nindex 0a9873d3..b1fd9bc7 100644\n--- a/features/componentlibrary/src/main/ets/view/ComponentListView.ets\n+++ b/features/componentlibrary/src/main/ets/view/ComponentListView.ets\n@@ -14,8 +14,9 @@\n */\n \n import { ConfigurationConstant } from '@kit.AbilityKit';\n-import { GlobalInfoModel, PageContext, StorageKey } from '@ohos/common';\n-import { BreakpointType, CommonConstants } from '@ohos/common';\n+import { HdsNavigation, HdsNavigationAttribute, HdsNavigationTitleMode } from '@kit.UIDesignKit';\n+import type { GlobalInfoModel, PageContext } from '@ohos/common';\n+import { BreakpointType, CommonConstants, StorageKey, VersionUtil } from '@ohos/common';\n import type { BannerData } from '@ohos/commonbusiness';\n import {\n BannerCard,\n@@ -184,23 +185,49 @@ export struct ComponentListView {\n })\n }\n \n+ @Builder\n+ ComponentContentView() {\n+ BaseHomeView({\n+ loadingModel: this.componentListState.loadingModel,\n+ contentView: () => {\n+ this.ContentViewBuilder()\n+ },\n+ topTitleView: () => {\n+ this.TopTitleViewBuilder()\n+ },\n+ reloadData: () => {\n+ this.viewModel.sendEvent({ type: ComponentListEventType.LOAD_COMPONENT_PAGE, param: null });\n+ },\n+ })\n+ }\n+\n build() {\n- Navigation(this.componentListPageContext.navPathStack) {\n- BaseHomeView({\n- loadingModel: this.componentListState.loadingModel,\n- contentView: () => {\n- this.ContentViewBuilder()\n- },\n- topTitleView: () => {\n- this.TopTitleViewBuilder()\n- },\n- reloadData: () => {\n- this.viewModel.sendEvent({ type: ComponentListEventType.LOAD_COMPONENT_PAGE, param: null });\n- },\n+ if (VersionUtil.canUseHds()) {\n+ HdsNavigation(this.componentListPageContext.navPathStack) {\n+ this.ComponentContentView();\n+ }\n+ .mode(NavigationMode.Stack)\n+ .hideBackButton(true)\n+ .titleMode(HdsNavigationTitleMode.MINI)\n+ .bindToScrollable([this.scroller])\n+ .ignoreLayoutSafeArea([LayoutSafeAreaType.SYSTEM], [LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM])\n+ .titleBar({\n+ padding: this.componentListState.topNavigationData.hdsTitleBarPadding,\n+ avoidLayoutSafeArea: true,\n+ style: this.componentListState.topNavigationData.hdsTitleBarStyle,\n+ content: {\n+ title: { mainTitle: this.componentListState.topNavigationData.title },\n+ }\n })\n+ .width('100%')\n+ .height('100%')\n+ } else {\n+ Navigation(this.componentListPageContext.navPathStack) {\n+ this.ComponentContentView()\n+ }\n+ .defaultFocus(true)\n+ .mode(NavigationMode.Stack)\n+ .hideTitleBar(true)\n }\n- .defaultFocus(true)\n- .mode(NavigationMode.Stack)\n- .hideTitleBar(true)\n }\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/ets/component/SampleCard.ets b/features/devpractices/src/main/ets/component/SampleCard.ets\nindex 9898bec5..150718d2 100644\n--- a/features/devpractices/src/main/ets/component/SampleCard.ets\n+++ b/features/devpractices/src/main/ets/component/SampleCard.ets\n@@ -28,7 +28,13 @@ import {\n StorageKey,\n } from '@ohos/common';\n import { SampleDetailConstant } from '../constant/CommonConstants';\n-import { BindSheetEvent, SampleDetailPageVM, LoadSampleEvent } from '../viewmodel/SampleDetailPageVM';\n+import {\n+ BindSheetEvent,\n+ SampleDetailPageVM,\n+ LoadSampleEvent,\n+ SetOverflowStatusEvent,\n+ ChangeCardStatusEvent\n+} from '../viewmodel/SampleDetailPageVM';\n import type { SampleCardData } from '../viewmodel/SampleDetailState';\n \n const TAG = '[SampleCard]';\n@@ -99,38 +105,75 @@ export struct SampleCard {\n .width('100%')\n }\n \n+ @Builder\n+ overlayBuilder() {\n+ Stack()\n+ .height($r('app.float.overlay_height'))\n+ .width('100%')\n+ .linearGradient({\n+ direction: GradientDirection.Top,\n+ colors: [[$r('sys.color.ohos_id_color_background_transparent'), 0],\n+ [$r('sys.color.ohos_id_background_secondary'), SampleDetailConstant.LINEAR_GRADIENT_END]]\n+ })\n+ .visibility(this.sampleCard.isOverflow && !this.sampleCard.cardOpenStatus ? Visibility.Visible :\n+ Visibility.Hidden)\n+ .blendMode(BlendMode.DST_IN, BlendApplyType.OFFSCREEN)\n+ .hitTestBehavior(HitTestMode.None)\n+ }\n+\n build() {\n Column() {\n- Text(this.sampleCard.title)\n- .maxLines(1)\n- .height($r('app.float.samplename_height'))\n- .lineHeight($r('app.float.cardtitle_lineheight'))\n- .fontColor($r('sys.color.font_primary'))\n- .fontWeight(FontWeight.Bold)\n- .fontSize($r('sys.float.Subtitle_L'))\n- .margin({ bottom: $r('sys.float.padding_level1') })\n- .textOverflow({ overflow: TextOverflow.Ellipsis })\n+ Column() {\n+ Text(this.sampleCard.title)\n+ .maxLines(SampleDetailConstant.TITLE_MAXLINE)\n+ .height($r('app.float.samplename_height'))\n+ .lineHeight($r('app.float.cardtitle_lineheight'))\n+ .fontColor($r('sys.color.font_primary'))\n+ .fontWeight(FontWeight.Bold)\n+ .fontSize($r('sys.float.Subtitle_L'))\n+ .margin({ bottom: $r('sys.float.padding_level1') })\n+ .textOverflow({ overflow: TextOverflow.Ellipsis })\n \n- Text(this.sampleCard.desc)\n- .maxLines(SampleDetailConstant.SUBTITLE_MAXLINE)\n- .height($r('app.float.sampledesc_height'))\n- .fontSize($r('sys.float.Subtitle_S'))\n- .fontWeight(FontWeight.Regular)\n- .lineHeight($r('app.float.cardsubtitle_lineheight'))\n- .fontColor($r('sys.color.font_secondary'))\n- .margin({\n- bottom: $r('sys.float.padding_level12'),\n- })\n- .textOverflow({ overflow: TextOverflow.Ellipsis })\n+ Text(this.sampleCard.desc)\n+ .maxLines(this.sampleCard.cardOpenStatus ? SampleDetailConstant.SUBTITLE_OPEN_MAXLINE :\n+ SampleDetailConstant.SUBTITLE_MAXLINE)\n+ .fontSize($r('sys.float.Subtitle_S'))\n+ .fontWeight(FontWeight.Regular)\n+ .lineHeight($r('app.float.cardsubtitle_lineheight'))\n+ .fontColor($r('sys.color.font_secondary'))\n+ .wordBreak(WordBreak.BREAK_ALL)\n+ .textOverflow({ overflow: TextOverflow.Ellipsis })\n+ .overlay(this.overlayBuilder())\n+ .blendMode(BlendMode.SRC_OVER, BlendApplyType.OFFSCREEN)\n+ }\n+ .alignItems(HorizontalAlign.Start)\n+ .layoutWeight(1)\n+ .onAreaChange((oldValue, newValue) => {\n+ if (newValue.width !== oldValue.width) {\n+ this.viewModel.sendEvent(new SetOverflowStatusEvent(this.getUIContext(), newValue, this.sampleIndex));\n+ }\n+ })\n+\n+ Row() {\n+ SymbolGlyph(this.sampleCard.cardOpenStatus ? $r('sys.symbol.chevron_up') : $r('sys.symbol.chevron_down'))\n+ .fontSize($r('app.float.expand_icon_size'))\n+ .fontColor([$r('sys.color.icon_tertiary')])\n+ Text(this.sampleCard.cardOpenStatus ? $r('app.string.card_collapse') : $r('app.string.card_expand'))\n+ .fontSize($r('sys.float.Body_S'))\n+ .fontColor($r('sys.color.font_tertiary'))\n+ .lineHeight($r('app.float.expand_line_height'))\n+ }\n+ .width('100%')\n+ .height($r('app.float.expand_area_height'))\n+ .justifyContent(FlexAlign.Center)\n+ .visibility(this.sampleCard.isOverflow ? Visibility.Visible : Visibility.Hidden)\n+ .onClick(() => {\n+ this.viewModel.sendEvent(new ChangeCardStatusEvent(this.sampleIndex));\n+ })\n \n- Row({\n- space: new BreakpointType({\n- sm: CommonConstants.SPACE_16,\n- md: CommonConstants.SPACE_16,\n- lg: CommonConstants.SPACE_24,\n- }).getValue(this.globalInfoModel.widthBreakpoint),\n- }) {\n- Button($r('app.string.read_code'))\n+ Row() {\n+ Button($r('app.string.read_code'),\n+ { type: ButtonType.Normal, buttonStyle: ButtonStyleMode.NORMAL, controlSize: ControlSize.SMALL })\n .cardButtonStyle($r('sys.color.comp_background_tertiary'), $r('sys.color.background_emphasize'),\n this.globalInfoModel.widthBreakpoint)\n .onClick(() => {\n@@ -156,6 +199,13 @@ export struct SampleCard {\n }\n })\n \n+ Blank()\n+ .width(new BreakpointType({\n+ sm: CommonConstants.SPACE_16,\n+ md: CommonConstants.SPACE_16,\n+ lg: CommonConstants.SPACE_24,\n+ }).getValue(this.globalInfoModel.widthBreakpoint))\n+\n if (this.sampleCard.downloading && this.currentIndex === this.sampleIndex &&\n (this.sampleCard.downloadProgress >= 0)) {\n Progress({\n@@ -165,7 +215,8 @@ export struct SampleCard {\n })\n .value(this.sampleCard.downloadProgress)\n .layoutWeight(1)\n- .borderRadius($r('sys.float.corner_radius_level7'))\n+ .borderRadius(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL ?\n+ $r('sys.float.corner_radius_level4') : '50%')\n .height($r('app.float.progress_height'))\n .color($r('sys.color.background_emphasize'))\n .backgroundColor($r('sys.color.background_primary'))\n@@ -177,7 +228,8 @@ export struct SampleCard {\n fontColor: $r('sys.color.font_primary'),\n })\n } else {\n- Button(this.sampleCard.installed ? $r('app.string.experience_sample') : $r('app.string.download_sample'))\n+ Button(this.sampleCard.installed ? $r('app.string.experience_sample') : $r('app.string.download_sample'),\n+ { type: ButtonType.Normal, buttonStyle: ButtonStyleMode.NORMAL, controlSize: ControlSize.SMALL })\n .cardButtonStyle($r('sys.color.background_emphasize'), $r('sys.color.font_on_primary'),\n this.globalInfoModel.widthBreakpoint)\n .onClick(() => {\n@@ -186,13 +238,23 @@ export struct SampleCard {\n }\n }\n .width('100%')\n+ .height($r('app.float.card_button_height'))\n .justifyContent(FlexAlign.SpaceAround)\n+ .margin({\n+ top: $r('sys.float.padding_level2'),\n+ })\n }\n .borderRadius($r('sys.float.corner_radius_level8'))\n .backgroundColor($r('sys.color.comp_background_primary'))\n- .height($r('app.float.sample_card_height'))\n+ .height(this.sampleCard.cardOpenStatus && this.sampleCard.isOverflow ? $r('app.float.sample_card_open_height') :\n+ $r('app.float.sample_card_height'))\n+ .justifyContent(FlexAlign.SpaceBetween)\n .alignItems(HorizontalAlign.Start)\n .clip(true)\n+ .animation({\n+ duration: SampleDetailConstant.ANIMATION_DURATION,\n+ curve: Curve.EaseOut,\n+ })\n .margin({\n top: new BreakpointType({\n sm: $r('app.float.margin_36'),\n@@ -201,7 +263,7 @@ export struct SampleCard {\n }).getValue(this.globalInfoModel.widthBreakpoint),\n })\n .padding({\n- top: $r('sys.float.padding_level9'),\n+ top: $r('sys.float.padding_level8'),\n bottom: this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_LG ? $r('sys.float.padding_level12') :\n $r('sys.float.padding_level8'),\n left: this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_LG ? $r('sys.float.padding_level16') :\n@@ -214,12 +276,11 @@ export struct SampleCard {\n \n @Extend(Button)\n function cardButtonStyle(backgroundColor: ResourceColor, fontColor: ResourceColor, widthBreakpoint: WidthBreakpoint) {\n- .type(ButtonType.Normal)\n+ .borderRadius(widthBreakpoint === WidthBreakpoint.WIDTH_XL ? $r('sys.float.corner_radius_level4') : '50%')\n .layoutWeight(1)\n .fontSize($r('sys.float.Body_M'))\n .fontWeight(FontWeight.Medium)\n .fontColor(fontColor)\n .backgroundColor(backgroundColor)\n .controlSize(ControlSize.NORMAL)\n- .borderRadius(widthBreakpoint === WidthBreakpoint.WIDTH_XL ? $r('sys.float.corner_radius_level4') : '50%')\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/ets/component/SampleComponent.ets b/features/devpractices/src/main/ets/component/SampleComponent.ets\nindex 8ad77935..d3323c4c 100644\n--- a/features/devpractices/src/main/ets/component/SampleComponent.ets\n+++ b/features/devpractices/src/main/ets/component/SampleComponent.ets\n@@ -13,7 +13,7 @@\n * limitations under the License.\n */\n \n-import { BreakpointType, ColumnEnum, CommonConstants, VideoComponent } from '@ohos/common';\n+import { BreakpointType, ColumnEnum, CommonConstants, GlobalInfoModel, StorageKey, VideoComponent } from '@ohos/common';\n import { MediaTypeEnum } from '@ohos/commonbusiness';\n import { SampleDetailData } from '../viewmodel/SampleDetailState';\n import { SampleCard } from './SampleCard';\n@@ -24,6 +24,7 @@ export struct SampleComponent {\n @Prop @Require sampleIndex: number;\n @Prop showIndicator: boolean = false;\n @Prop @Require widthBreakpoint: WidthBreakpoint;\n+ @StorageProp(StorageKey.GLOBAL_INFO) globalInfoModel: GlobalInfoModel = AppStorage.get(StorageKey.GLOBAL_INFO)!;\n \n build() {\n Column() {\n@@ -45,9 +46,23 @@ export struct SampleComponent {\n }\n }\n .layoutWeight(1)\n+ .margin({\n+ bottom: this.widthBreakpoint === WidthBreakpoint.WIDTH_MD &&\n+ this.globalInfoModel.heightBreakpoint === HeightBreakpoint.HEIGHT_LG ?\n+ $r('app.float.display_bottom_padding') : $r('sys.float.padding_level0'),\n+ top: this.widthBreakpoint === WidthBreakpoint.WIDTH_MD &&\n+ this.globalInfoModel.heightBreakpoint === HeightBreakpoint.HEIGHT_LG ?\n+ $r('app.float.display_top_padding') : $r('sys.float.padding_level0')\n+ })\n \n GridRow({\n- columns: { sm: ColumnEnum.SM, md: ColumnEnum.MD, lg: ColumnEnum.LG },\n+ columns: {\n+ sm: ColumnEnum.SM,\n+ md: this.widthBreakpoint === WidthBreakpoint.WIDTH_MD &&\n+ this.globalInfoModel.heightBreakpoint === HeightBreakpoint.HEIGHT_LG ? ColumnEnum.SM :\n+ ColumnEnum.MD,\n+ lg: ColumnEnum.LG\n+ },\n gutter: {\n x: {\n sm: $r('sys.float.padding_level6'),\n@@ -57,8 +72,18 @@ export struct SampleComponent {\n },\n }) {\n GridCol({\n- span: { sm: CommonConstants.SPAN_4, md: CommonConstants.SPAN_6, lg: CommonConstants.SPAN_8 },\n- offset: { sm: 0, md: 1, lg: 2 },\n+ span: {\n+ sm: CommonConstants.SPAN_4,\n+ md: this.widthBreakpoint === WidthBreakpoint.WIDTH_MD &&\n+ this.globalInfoModel.heightBreakpoint === HeightBreakpoint.HEIGHT_LG ?\n+ CommonConstants.SPAN_4 : CommonConstants.SPAN_6,\n+ lg: CommonConstants.SPAN_8\n+ },\n+ offset: {\n+ sm: 0,\n+ md: this.globalInfoModel.heightBreakpoint === HeightBreakpoint.HEIGHT_LG ? 0 : 1,\n+ lg: 2\n+ },\n }) {\n SampleCard({ sampleCard: this.singleSampleData.sampleCard, sampleIndex: this.sampleIndex, })\n }\n@@ -74,14 +99,19 @@ export struct SampleComponent {\n top: $r('sys.float.padding_level4'),\n left: new BreakpointType({\n sm: $r('sys.float.padding_level8'),\n- md: $r('sys.float.padding_level12'),\n+ md: this.globalInfoModel.heightBreakpoint === HeightBreakpoint.HEIGHT_LG ?\n+ $r('sys.float.padding_level32') : $r('sys.float.padding_level12'),\n lg: $r('sys.float.padding_level16'),\n }).getValue(this.widthBreakpoint),\n right: new BreakpointType({\n sm: $r('sys.float.padding_level8'),\n- md: $r('sys.float.padding_level12'),\n+ md: this.globalInfoModel.heightBreakpoint === HeightBreakpoint.HEIGHT_LG ?\n+ $r('sys.float.padding_level32') : $r('sys.float.padding_level12'),\n lg: $r('sys.float.padding_level16'),\n }).getValue(this.widthBreakpoint),\n+ bottom: this.widthBreakpoint === WidthBreakpoint.WIDTH_MD &&\n+ this.globalInfoModel.heightBreakpoint === HeightBreakpoint.HEIGHT_LG ?\n+ $r('app.float.tablet_vertical_padding') : $r('sys.float.padding_level0'),\n })\n }\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/ets/constant/CommonConstants.ets b/features/devpractices/src/main/ets/constant/CommonConstants.ets\nindex 130f2b64..e8d25fcd 100644\n--- a/features/devpractices/src/main/ets/constant/CommonConstants.ets\n+++ b/features/devpractices/src/main/ets/constant/CommonConstants.ets\n@@ -17,8 +17,14 @@ export class SampleDetailConstant {\n // Progress\n public static readonly PROGRESS_START: number = 0;\n public static readonly PROGRESS_FINISH: number = 100;\n- // MaxLine\n+ // Max lines\n+ public static readonly TITLE_MAXLINE: number = 1;\n public static readonly SUBTITLE_MAXLINE: number = 3;\n+ public static readonly SUBTITLE_OPEN_MAXLINE: number = 5;\n+ //Linear gradient\n+ public static readonly LINEAR_GRADIENT_END: number = 0.35;\n+ //Expand animation\n+ public static readonly ANIMATION_DURATION: number = 300;\n // The offset of the popup component relative to the display position defined by the placement setting.\n public static HOVER_POPUP_LEFT: number = 10;\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/ets/view/PracticeDetailView.ets b/features/devpractices/src/main/ets/view/PracticeDetailView.ets\nindex 9be08cac..1c72d0a8 100644\n--- a/features/devpractices/src/main/ets/view/PracticeDetailView.ets\n+++ b/features/devpractices/src/main/ets/view/PracticeDetailView.ets\n@@ -14,8 +14,17 @@\n */\n \n import { ConfigurationConstant } from '@kit.AbilityKit';\n-import { GlobalInfoModel, StorageKey } from '@ohos/common';\n-import { CommonConstants, LoadingStatus, Toast, TopNavigationView, WindowUtil } from '@ohos/common';\n+import { HdsNavDestination, HdsNavDestinationAttribute } from '@kit.UIDesignKit';\n+import type { GlobalInfoModel } from '@ohos/common';\n+import {\n+ CommonConstants,\n+ LoadingStatus,\n+ StorageKey,\n+ Toast,\n+ TopNavigationView,\n+ VersionUtil,\n+ WindowUtil,\n+} from '@ohos/common';\n import { BaseDetailComponent, SampleDetailParams } from '@ohos/commonbusiness';\n import { SampleComponent } from '../component/SampleComponent';\n import type { SampleDetailData, SampleDetailState } from '../viewmodel/SampleDetailState';\n@@ -46,10 +55,18 @@ export struct SampleDetailView {\n WindowUtil.updateStatusBarColor(isSystemDark);\n }\n \n- private onBack(): void {\n+ private onBack(): boolean {\n if (!this.sampleDetailState.isBackPressed) {\n this.viewModel.sendEvent(new PopEvent());\n }\n+ return true;\n+ }\n+\n+ handleOnReady(cxt: NavDestinationContext) {\n+ const params = cxt.pathInfo.param as SampleDetailParams;\n+ this.sampleCardId = params.sampleCardId;\n+ this.currentIndex = params.currentIndex;\n+ this.viewModel.sendEvent(new InitSampleDetailEvent(this.sampleCardId, params.currentIndex));\n }\n \n @Builder\n@@ -66,7 +83,10 @@ export struct SampleDetailView {\n }\n .layoutWeight(1)\n .width('100%')\n- .padding({ top: (this.globalInfoModel.statusBarHeight + CommonConstants.NAVIGATION_HEIGHT) })\n+ .padding({\n+ top: CommonConstants.NAVIGATION_HEIGHT,\n+ bottom: this.globalInfoModel.naviIndicatorHeight,\n+ })\n .indicator(this.sampleDetailState.sampleCount > 1)\n .index(this.currentIndex)\n .disableSwipe(this.sampleDetailState.sampleCount === 1 || this.sampleDetailState.installingStatus ||\n@@ -98,38 +118,70 @@ export struct SampleDetailView {\n })\n }\n \n- build() {\n- NavDestination() {\n- BaseDetailComponent({\n- detailContentView: () => {\n- this.SampleDetailBuilder()\n- },\n- topTitleView: () => {\n+ @Builder\n+ DetailContentBuilder() {\n+ BaseDetailComponent({\n+ detailContentView: () => {\n+ this.SampleDetailBuilder()\n+ },\n+ topTitleView: () => {\n+ if (!VersionUtil.canUseHds()) {\n this.TopTitleViewBuilder()\n+ }\n+ },\n+ loadingStatus: this.sampleDetailState.loadingStatus,\n+ })\n+ }\n+\n+ build() {\n+ if (VersionUtil.canUseHds()) {\n+ HdsNavDestination() {\n+ this.DetailContentBuilder();\n+ }\n+ .hideBackButton(false)\n+ .titleBar({\n+ avoidLayoutSafeArea: true,\n+ style: {\n+ originalStyle: { backgroundStyle: { backgroundColor: Color.Transparent } },\n+ scrollEffectOpts: {\n+ enableScrollEffect: false,\n+ },\n },\n- loadingStatus: this.sampleDetailState.loadingStatus,\n+ content: {\n+ title: { mainTitle: $r('app.string.sample_title') },\n+ }\n+ })\n+ .backgroundColor($r('sys.color.background_secondary'))\n+ .ignoreLayoutSafeArea([LayoutSafeAreaType.SYSTEM], [LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM])\n+ .onReady((cxt: NavDestinationContext) => this.handleOnReady(cxt))\n+ .onBackPressed(() => {\n+ return this.onBack();\n+ })\n+ .onWillShow(() => {\n+ this.sampleDetailState.isBackPressed = false;\n+ })\n+ .onWillHide(() => {\n+ this.sampleDetailState.isBackPressed = false;\n+ })\n+ } else {\n+ NavDestination() {\n+ this.DetailContentBuilder()\n+ }\n+ .onReady((cxt: NavDestinationContext) => this.handleOnReady(cxt))\n+ .onBackPressed(() => {\n+ return this.onBack();\n+ })\n+ .onWillShow(() => {\n+ this.sampleDetailState.isBackPressed = false;\n })\n+ .onWillHide(() => {\n+ this.sampleDetailState.isBackPressed = false;\n+ })\n+ .padding({ top: this.globalInfoModel.statusBarHeight })\n+ .hideTitleBar(true)\n+ .width('100%')\n+ .height('100%')\n+ .backgroundColor($r('sys.color.background_secondary'))\n }\n- .onReady((cxt: NavDestinationContext) => {\n- const params = cxt.pathInfo.param as SampleDetailParams;\n- this.sampleCardId = params.sampleCardId;\n- this.currentIndex = params.currentIndex;\n- this.viewModel.sendEvent(new InitSampleDetailEvent(this.sampleCardId, params.currentIndex));\n- })\n- .onBackPressed(() => {\n- this.onBack();\n- return true;\n- })\n- .onWillShow(() => {\n- this.sampleDetailState.isBackPressed = false;\n- })\n- .onWillHide(() => {\n- this.sampleDetailState.isBackPressed = false;\n- })\n- .hideTitleBar(true)\n- .padding({ bottom: this.globalInfoModel.naviIndicatorHeight, top: this.globalInfoModel.statusBarHeight })\n- .width('100%')\n- .height('100%')\n- .backgroundColor($r('sys.color.background_secondary'))\n }\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/ets/view/PracticesView.ets b/features/devpractices/src/main/ets/view/PracticesView.ets\nindex 6a5c5f65..7c29fcd3 100644\n--- a/features/devpractices/src/main/ets/view/PracticesView.ets\n+++ b/features/devpractices/src/main/ets/view/PracticesView.ets\n@@ -14,8 +14,9 @@\n */\n \n import { ConfigurationConstant } from '@kit.AbilityKit';\n+import { HdsNavigation, HdsNavigationAttribute, HdsNavigationTitleMode } from '@kit.UIDesignKit';\n import type { GlobalInfoModel, PageContext } from '@ohos/common';\n-import { BreakpointType, CommonConstants, StorageKey } from '@ohos/common';\n+import { BreakpointType, CommonConstants, StorageKey, VersionUtil } from '@ohos/common';\n import type { BannerData } from '@ohos/commonbusiness';\n import {\n BannerCard,\n@@ -78,7 +79,7 @@ export struct PracticesView {\n }\n \n @Builder\n- CategoryHeaderBuilder() {\n+ CategoryHeaderBuilder(hasStartMargin?: boolean) {\n if (this.practiceState.sampleCategories.length > 1) {\n Scroll(this.headerScroller) {\n Row({\n@@ -100,18 +101,19 @@ export struct PracticesView {\n .fontSize($r('sys.float.Body_M'))\n .fontWeight(FontWeight.Medium)\n .fontColor(this.currentIndex === index ? $r('sys.color.font_on_primary') :\n- $r('sys.color.font_tertiary'))\n+ $r('sys.color.font_tertiary'))\n }\n .backgroundColor(this.currentIndex === index ? $r('sys.color.brand') :\n- $r('sys.color.ohos_id_color_button_normal'))\n+ $r('sys.color.ohos_id_color_button_normal'))\n .padding({\n left: $r('sys.float.padding_level8'),\n right: $r('sys.float.padding_level8'),\n top: $r('sys.float.padding_level4'),\n bottom: $r('sys.float.padding_level4'),\n })\n+ .margin({ left: (hasStartMargin && index === 0) ? CommonConstants.TAB_BAR_WIDTH : 0 })\n .borderRadius(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL ?\n- $r('sys.float.corner_radius_level4') : '50%')\n+ $r('sys.float.corner_radius_level4') : '50%')\n .onClick(() => {\n this.currentIndex = index;\n if (!this.practiceState.sampleCategories[index].sampleCards) {\n@@ -213,22 +215,53 @@ export struct PracticesView {\n })\n }\n \n+ @Builder\n+ PracticeContentView() {\n+ BaseHomeView({\n+ loadingModel: this.practiceState.loadingModel,\n+ contentView: () => {\n+ this.ContentViewBuilder()\n+ },\n+ topTitleView: () => {\n+ this.TopTitleViewBuilder()\n+ },\n+ reloadData: () => {\n+ this.viewModel.sendEvent({ type: PracticeEventType.LOAD_SAMPLE_PAGE, param: null });\n+ },\n+ })\n+ }\n+\n build() {\n- Navigation(this.samplePageContext.navPathStack) {\n- BaseHomeView({\n- loadingModel: this.practiceState.loadingModel,\n- contentView: () => {\n- this.ContentViewBuilder()\n- },\n- topTitleView: () => {\n- this.TopTitleViewBuilder()\n- },\n- reloadData: () => {\n- this.viewModel.sendEvent({ type: PracticeEventType.LOAD_SAMPLE_PAGE, param: null });\n- },\n+ if (VersionUtil.canUseHds()) {\n+ HdsNavigation(this.samplePageContext.navPathStack) {\n+ this.PracticeContentView();\n+ }\n+ .mode(NavigationMode.Stack)\n+ .hideBackButton(true)\n+ .titleMode(HdsNavigationTitleMode.MINI)\n+ .bindToScrollable([this.listScroller])\n+ .ignoreLayoutSafeArea([LayoutSafeAreaType.SYSTEM], [LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM])\n+ .titleBar({\n+ padding: this.practiceState.topNavigationData.hdsTitleBarPadding,\n+ avoidLayoutSafeArea: true,\n+ style: this.practiceState.topNavigationData.hdsTitleBarStyle,\n+ content: {\n+ title: { mainTitle: this.practiceState.topNavigationData.title },\n+ bottomBuilder: this.practiceState.showTab ? {\n+ builder: () => {\n+ this.CategoryHeaderBuilder(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_LG);\n+ },\n+ } : undefined,\n+ }\n })\n+ .width('100%')\n+ .height('100%')\n+ } else {\n+ Navigation(this.samplePageContext.navPathStack) {\n+ this.PracticeContentView();\n+ }\n+ .mode(NavigationMode.Stack)\n+ .hideTitleBar(true)\n }\n- .mode(NavigationMode.Stack)\n- .hideTitleBar(true)\n }\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/ets/viewmodel/PracticeViewModel.ets b/features/devpractices/src/main/ets/viewmodel/PracticeViewModel.ets\nindex 7c122011..328e59e2 100644\n--- a/features/devpractices/src/main/ets/viewmodel/PracticeViewModel.ets\n+++ b/features/devpractices/src/main/ets/viewmodel/PracticeViewModel.ets\n@@ -75,6 +75,7 @@ export class PracticeViewModel extends BaseHomeViewModel<PracticeState> {\n this.state.topNavigationData.titleColor = isDark ? StatusBarColorType.WHITE : StatusBarColorType.BLACK;\n this.state.topNavigationData.isBlur = false;\n this.state.topNavigationData.showTab = false;\n+ this.state.showTab = this.state.topNavigationData.showTab;\n WindowUtil.updateStatusBarColor(isDark);\n this.sampleModel.getSamplePage(1, this.pageSize)\n .then((result: ResponseData<SampleData>) => {\ndiff --git a/features/devpractices/src/main/ets/viewmodel/SampleDetailPageVM.ets b/features/devpractices/src/main/ets/viewmodel/SampleDetailPageVM.ets\nindex 580aeecf..281b8998 100644\n--- a/features/devpractices/src/main/ets/viewmodel/SampleDetailPageVM.ets\n+++ b/features/devpractices/src/main/ets/viewmodel/SampleDetailPageVM.ets\n@@ -27,6 +27,9 @@ import {\n Logger,\n PageContext,\n StorageKey,\n+ TextOverflowData,\n+ TextOverflowProperty,\n+ TextOverflowUtil,\n Toast,\n } from '@ohos/common';\n import { SampleCardData, SampleDetailData, SampleDetailState } from './SampleDetailState';\n@@ -69,6 +72,10 @@ export class SampleDetailPageVM extends BaseVM<SampleDetailState> {\n this.setInstalledStatus(baseVMEvent);\n } else if (baseVMEvent instanceof InitSampleDetailEvent) {\n this.initSampleDetail(baseVMEvent);\n+ } else if (baseVMEvent instanceof SetOverflowStatusEvent) {\n+ this.setOverflowStatus(baseVMEvent);\n+ } else if (baseVMEvent instanceof ChangeCardStatusEvent) {\n+ this.changeCardStatus(baseVMEvent);\n }\n }\n \n@@ -154,7 +161,6 @@ export class SampleDetailPageVM extends BaseVM<SampleDetailState> {\n });\n this.state.sampleDatas = sampleDetailData;\n this.initDownloadListener();\n- this.state.loadingStatus = LoadingStatus.SUCCESS;\n }).catch(() => {\n this.state.loadingStatus = LoadingStatus.FAILED;\n });\n@@ -275,6 +281,32 @@ export class SampleDetailPageVM extends BaseVM<SampleDetailState> {\n private setInstallingStatus(installing: boolean): void {\n this.state.installingStatus = installing;\n }\n+\n+ private setOverflowStatus(event: SetOverflowStatusEvent) {\n+ this.reSetOverflowStatus(event.indexOfSwiper);\n+ const textOverflowOptions: TextOverflowProperty = {\n+ constraintWidth: event.area.width,\n+ fontSize: $r('sys.float.Subtitle_S'),\n+ fontWeight: FontWeight.Regular,\n+ lineHeight: $r('app.float.cardsubtitle_lineheight'),\n+ wordBreak: WordBreak.BREAK_ALL,\n+ };\n+ const textOverflowData: TextOverflowData =\n+ TextOverflowUtil.getOverflowData(event.uiContext, this.state.sampleDatas[event.indexOfSwiper].sampleCard.desc,\n+ SampleDetailConstant.SUBTITLE_MAXLINE, textOverflowOptions);\n+ this.state.sampleDatas[event.indexOfSwiper].sampleCard.isOverflow = textOverflowData.overflowStatus;\n+ this.state.loadingStatus = LoadingStatus.SUCCESS;\n+ }\n+\n+ private reSetOverflowStatus(indexOfSwiper: number) {\n+ this.state.sampleDatas[indexOfSwiper].sampleCard.isOverflow = false;\n+ this.state.sampleDatas[indexOfSwiper].sampleCard.breakWordIndex = 0;\n+ }\n+\n+ private changeCardStatus(event: ChangeCardStatusEvent): void {\n+ this.state.sampleDatas[event.indexOfSwiper].sampleCard.cardOpenStatus =\n+ !this.state.sampleDatas[event.indexOfSwiper].sampleCard.cardOpenStatus;\n+ }\n }\n \n export class BindSheetEvent implements BaseVMEvent {\n@@ -319,6 +351,26 @@ export class ChangeDownloadProgressEvent implements BaseVMEvent {\n export class PopEvent implements BaseVMEvent {\n }\n \n+export class SetOverflowStatusEvent implements BaseVMEvent {\n+ public readonly uiContext: UIContext;\n+ public readonly area: Area;\n+ public readonly indexOfSwiper: number;\n+\n+ public constructor(uiContext: UIContext, area: Area, indexOfSwiper: number) {\n+ this.uiContext = uiContext;\n+ this.area = area;\n+ this.indexOfSwiper = indexOfSwiper;\n+ }\n+}\n+\n+export class ChangeCardStatusEvent implements BaseVMEvent {\n+ public readonly indexOfSwiper: number;\n+\n+ public constructor(indexOfSwiper: number) {\n+ this.indexOfSwiper = indexOfSwiper;\n+ }\n+}\n+\n export class SetIndexEvent implements BaseVMEvent {\n public readonly currentIndex: number;\n \ndiff --git a/features/devpractices/src/main/ets/viewmodel/SampleDetailState.ets b/features/devpractices/src/main/ets/viewmodel/SampleDetailState.ets\nindex 092d5110..ddc377fd 100644\n--- a/features/devpractices/src/main/ets/viewmodel/SampleDetailState.ets\n+++ b/features/devpractices/src/main/ets/viewmodel/SampleDetailState.ets\n@@ -50,4 +50,7 @@ export class SampleCardData {\n public downloading: boolean = false;\n public downloadProgress: number = -1;\n public installed: boolean = false;\n+ public isOverflow: boolean = false;\n+ public cardOpenStatus: boolean = false;\n+ public breakWordIndex: number = 0;\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/resources/base/element/float.json b/features/devpractices/src/main/resources/base/element/float.json\nindex 5a213661..43bc8d46 100644\n--- a/features/devpractices/src/main/resources/base/element/float.json\n+++ b/features/devpractices/src/main/resources/base/element/float.json\n@@ -6,11 +6,15 @@\n },\n {\n \"name\": \"card_button_height\",\n- \"value\": \"40.0vp\"\n+ \"value\": \"40vp\"\n },\n {\n \"name\": \"sample_card_height\",\n- \"value\": \"170vp\"\n+ \"value\": \"168vp\"\n+ },\n+ {\n+ \"name\": \"sample_card_open_height\",\n+ \"value\": \"200vp\"\n },\n {\n \"name\": \"samplename_height\",\n@@ -18,7 +22,11 @@\n },\n {\n \"name\": \"sampledesc_height\",\n- \"value\": \"45vp\"\n+ \"value\": \"48vp\"\n+ },\n+ {\n+ \"name\": \"sample_desc_open_height\",\n+ \"value\": \"96vp\"\n },\n {\n \"name\": \"card_content_height\",\n@@ -63,6 +71,34 @@\n {\n \"name\": \"tab_icon_height\",\n \"value\": \"16vp\"\n+ },\n+ {\n+ \"name\": \"expand_icon_size\",\n+ \"value\": \"20vp\"\n+ },\n+ {\n+ \"name\": \"expand_area_height\",\n+ \"value\": \"20vp\"\n+ },\n+ {\n+ \"name\": \"expand_line_height\",\n+ \"value\": \"14vp\"\n+ },\n+ {\n+ \"name\": \"overlay_height\",\n+ \"value\": \"48vp\"\n+ },\n+ {\n+ \"name\": \"tablet_vertical_padding\",\n+ \"value\": \"140vp\"\n+ },\n+ {\n+ \"name\": \"display_bottom_padding\",\n+ \"value\": \"40vp\"\n+ },\n+ {\n+ \"name\": \"display_top_padding\",\n+ \"value\": \"90vp\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/resources/base/element/string.json b/features/devpractices/src/main/resources/base/element/string.json\nindex bbe990de..fe67d1df 100644\n--- a/features/devpractices/src/main/resources/base/element/string.json\n+++ b/features/devpractices/src/main/resources/base/element/string.json\n@@ -55,6 +55,14 @@\n {\n \"name\": \"client_prompt\",\n \"value\": \"Sample in HarmonyOS supports 1+8 multi-device operation. Welcome to experience it\"\n+ },\n+ {\n+ \"name\": \"card_expand\",\n+ \"value\": \"expand\"\n+ },\n+ {\n+ \"name\": \"card_collapse\",\n+ \"value\": \"collapse\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/resources/en_US/element/string.json b/features/devpractices/src/main/resources/en_US/element/string.json\nindex 23c8c575..d440e789 100644\n--- a/features/devpractices/src/main/resources/en_US/element/string.json\n+++ b/features/devpractices/src/main/resources/en_US/element/string.json\n@@ -55,6 +55,14 @@\n {\n \"name\": \"client_prompt\",\n \"value\": \"Sample in HarmonyOS supports 1+8 multi-device operation. Welcome to experience it\"\n+ },\n+ {\n+ \"name\": \"card_expand\",\n+ \"value\": \"expand\"\n+ },\n+ {\n+ \"name\": \"card_collapse\",\n+ \"value\": \"collapse\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/resources/zh_CN/element/string.json b/features/devpractices/src/main/resources/zh_CN/element/string.json\nindex 8bae6e1e..2e013ebc 100644\n--- a/features/devpractices/src/main/resources/zh_CN/element/string.json\n+++ b/features/devpractices/src/main/resources/zh_CN/element/string.json\n@@ -55,6 +55,14 @@\n {\n \"name\": \"client_prompt\",\n \"value\": \"HarmonyOS代码工坊支持1+8多设备运行,欢迎体验\"\n+ },\n+ {\n+ \"name\": \"card_expand\",\n+ \"value\": \"展开\"\n+ },\n+ {\n+ \"name\": \"card_collapse\",\n+ \"value\": \"收起\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/features/exploration/src/main/ets/component/ArticleWebComponent.ets b/features/exploration/src/main/ets/component/ArticleWebComponent.ets\nindex e99d5950..e37edab3 100644\n--- a/features/exploration/src/main/ets/component/ArticleWebComponent.ets\n+++ b/features/exploration/src/main/ets/component/ArticleWebComponent.ets\n@@ -152,10 +152,17 @@ export struct ArticleWebComponent {\n // Setting the local file path that allows cross-domain access.\n const uiContext: UIContext = AppStorage.get<UIContext>(StorageKey.UI_CONTEXT) as UIContext;\n const context: Context = uiContext.getHostContext() as Context;\n- this.webController.setPathAllowingUniversalAccess([context.resourceDir]);\n+ try {\n+ this.webController.setPathAllowingUniversalAccess([context.resourceDir]);\n+ } catch (error) {\n+ Logger.error(TAG, `setPathAllowingUniversalAccess failed, error: ${error.message}`);\n+ }\n })\n .onScroll((event) => {\n- this.handleWebScroll(event.yOffset);\n+ this.viewModel.sendEvent<number>({\n+ type: ExplorationDetailEventType.CHANGE_TITLE_BAR_STYLE,\n+ param: event.yOffset,\n+ });\n })\n .width('100%')\n .height('100%')\n@@ -164,14 +171,7 @@ export struct ArticleWebComponent {\n @Builder\n TopTitleViewBuilder() {\n TopNavigationView({\n- topNavigationData: {\n- title: this.title,\n- isBlur: this.isBlur,\n- isFullScreen: true,\n- onBackClick: () => {\n- this.detailState.topNavigationData.onBackClick?.();\n- }\n- },\n+ topNavigationData: this.detailState.topNavigationData,\n })\n }\n \ndiff --git a/features/exploration/src/main/ets/view/BannerDetailView.ets b/features/exploration/src/main/ets/view/BannerDetailView.ets\nindex e66ad622..8b27352f 100644\n--- a/features/exploration/src/main/ets/view/BannerDetailView.ets\n+++ b/features/exploration/src/main/ets/view/BannerDetailView.ets\n@@ -117,41 +117,48 @@ struct BannerDetailView {\n });\n }\n \n+ handleOnReady(cxt: NavDestinationContext) {\n+ const params = cxt.pathInfo.param as Record<string, string | number | boolean>;\n+ this.discoverContent.id = params.id as number;\n+ this.discoverContent.detailsUrl = params.detailsUrl as string;\n+ this.discoverContent.title = params.title as string;\n+ this.tabViewType = params.tabViewType as number;\n+ this.viewModel.sendEvent<DetailParam>({\n+ type: ExplorationDetailEventType.GET_ARTICLE_DETAIL,\n+ param: {\n+ content: this.discoverContent,\n+ onBackClick: () => {\n+ this.customBackPressed?.();\n+ },\n+ },\n+ });\n+ }\n+\n+ @Builder\n+ BannerContentBuilder() {\n+ ArticleWebComponent({\n+ viewModel: this.viewModel,\n+ detailsUrl: this.detailState.content.detailsUrl,\n+ tabViewType: this.tabViewType,\n+ loadingStatus: this.loadingStatus,\n+ })\n+ .geometryTransition(this.isChangePage ? CommonConstants.BANNER_GEOMETRY + this.tabViewType.toString() : '')\n+ .transition(this.isChangePage ? (this.isPopTransition ? TransitionEffect.OPACITY :\n+ TransitionEffect.OPACITY.animation({ duration: CommonConstants.TRANSITION_DURATION })) : undefined,\n+ (transitionIn: boolean) => {\n+ if (transitionIn) {\n+ this.isChangePage = false;\n+ this.loadingStatus = LoadingStatus.LOADING;\n+ }\n+ })\n+ }\n+\n build() {\n NavDestination() {\n- ArticleWebComponent({\n- viewModel: this.viewModel,\n- detailsUrl: this.detailState.content.detailsUrl,\n- tabViewType: this.tabViewType,\n- loadingStatus: this.loadingStatus,\n- })\n- .geometryTransition(this.isChangePage ? CommonConstants.BANNER_GEOMETRY + this.tabViewType.toString() : '')\n- .transition(this.isChangePage ? (this.isPopTransition ? TransitionEffect.OPACITY :\n- TransitionEffect.OPACITY.animation({ duration: CommonConstants.TRANSITION_DURATION })) : undefined,\n- (transitionIn: boolean) => {\n- if (transitionIn) {\n- this.isChangePage = false;\n- this.loadingStatus = LoadingStatus.LOADING;\n- }\n- })\n+ this.BannerContentBuilder()\n }\n .defaultFocus(true)\n- .onReady((cxt: NavDestinationContext) => {\n- const params = cxt.pathInfo.param as Record<string, string | number | boolean>;\n- this.discoverContent.id = params.id as number;\n- this.discoverContent.detailsUrl = params.detailsUrl as string;\n- this.discoverContent.title = params.title as string;\n- this.tabViewType = params.tabViewType as number;\n- this.viewModel.sendEvent<DetailParam>({\n- type: ExplorationDetailEventType.GET_ARTICLE_DETAIL,\n- param: {\n- content: this.discoverContent,\n- onBackClick: () => {\n- this.customBackPressed?.();\n- },\n- },\n- });\n- })\n+ .onReady((cxt: NavDestinationContext) => this.handleOnReady(cxt))\n .hideTitleBar(true)\n .onBackPressed((): boolean => {\n return this.customBackPressed();\ndiff --git a/features/exploration/src/main/ets/view/ExplorationView.ets b/features/exploration/src/main/ets/view/ExplorationView.ets\nindex 2ee8378f..4f55e689 100644\n--- a/features/exploration/src/main/ets/view/ExplorationView.ets\n+++ b/features/exploration/src/main/ets/view/ExplorationView.ets\n@@ -14,8 +14,9 @@\n */\n \n import { ConfigurationConstant } from '@kit.AbilityKit';\n-import { GlobalInfoModel, PageContext, StorageKey } from '@ohos/common';\n-import { BreakpointType, CommonConstants } from '@ohos/common';\n+import { HdsNavigation, HdsNavigationAttribute, HdsNavigationTitleMode } from '@kit.UIDesignKit';\n+import type { GlobalInfoModel, PageContext } from '@ohos/common';\n+import { BreakpointType, CommonConstants, StorageKey, VersionUtil } from '@ohos/common';\n import type { BannerData } from '@ohos/commonbusiness';\n import {\n BannerCard,\n@@ -139,9 +140,9 @@ export struct ExplorationView {\n })\n .margin({\n left: this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_SM ?\n- $r('sys.float.padding_level8') : 0,\n+ $r('sys.float.padding_level8') : 0,\n right: this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_SM ?\n- $r('sys.float.padding_level8') : 0,\n+ $r('sys.float.padding_level8') : 0,\n })\n }\n }\n@@ -191,10 +192,12 @@ export struct ExplorationView {\n return { offsetRemain: offset };\n })\n .onDidScroll(() => {\n- this.viewModel.sendEvent<OffsetParam>({\n- type: BaseHomeEventType.HANDLE_SCROLL_OFFSET,\n- param: { yOffset: this.listScroller.currentOffset().yOffset, tabIndex: TabBarType.PRACTICE },\n- });\n+ if (!VersionUtil.canUseHds()) {\n+ this.viewModel.sendEvent<OffsetParam>({\n+ type: BaseHomeEventType.HANDLE_SCROLL_OFFSET,\n+ param: { yOffset: this.listScroller.currentOffset().yOffset, tabIndex: TabBarType.PRACTICE },\n+ });\n+ }\n })\n .backgroundColor($r('sys.color.background_secondary'))\n }\n@@ -206,22 +209,47 @@ export struct ExplorationView {\n })\n }\n \n+ @Builder\n+ ExplorationContentView() {\n+ BaseHomeView({\n+ loadingModel: this.explorationState.loadingModel,\n+ contentView: () => {\n+ this.ContentViewBuilder()\n+ },\n+ topTitleView: () => {\n+ this.TopTitleViewBuilder()\n+ },\n+ reloadData: () => {\n+ this.viewModel.sendEvent({ type: ExplorationEventType.LOAD_DISCOVERY_PAGE, param: null });\n+ },\n+ })\n+ }\n+\n build() {\n- Navigation(this.explorationPageContext.navPathStack) {\n- BaseHomeView({\n- loadingModel: this.explorationState.loadingModel,\n- contentView: () => {\n- this.ContentViewBuilder()\n- },\n- topTitleView: () => {\n- this.TopTitleViewBuilder()\n- },\n- reloadData: () => {\n- this.viewModel.sendEvent({ type: ExplorationEventType.LOAD_DISCOVERY_PAGE, param: null });\n- },\n+ if (VersionUtil.canUseHds()) {\n+ HdsNavigation(this.explorationPageContext.navPathStack) {\n+ this.ExplorationContentView();\n+ }\n+ .mode(NavigationMode.Stack)\n+ .hideBackButton(true)\n+ .titleMode(HdsNavigationTitleMode.MINI)\n+ .ignoreLayoutSafeArea([LayoutSafeAreaType.SYSTEM], [LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM])\n+ .titleBar({\n+ padding: this.explorationState.topNavigationData.hdsTitleBarPadding,\n+ avoidLayoutSafeArea: true,\n+ style: this.explorationState.topNavigationData.hdsTitleBarStyle,\n+ content: {\n+ title: { mainTitle: this.explorationState.topNavigationData.title },\n+ }\n })\n+ .width('100%')\n+ .height('100%')\n+ } else {\n+ Navigation(this.explorationPageContext.navPathStack) {\n+ this.ExplorationContentView();\n+ }\n+ .mode(NavigationMode.Stack)\n+ .hideTitleBar(true)\n }\n- .mode(NavigationMode.Stack)\n- .hideTitleBar(true)\n }\n }\n\\ No newline at end of file\ndiff --git a/features/exploration/src/main/ets/viewmodel/ArticleDetailViewModel.ets b/features/exploration/src/main/ets/viewmodel/ArticleDetailViewModel.ets\nindex 26efeb05..9fd895b7 100644\n--- a/features/exploration/src/main/ets/viewmodel/ArticleDetailViewModel.ets\n+++ b/features/exploration/src/main/ets/viewmodel/ArticleDetailViewModel.ets\n@@ -13,7 +13,14 @@\n * limitations under the License.\n */\n \n-import { BaseVM, GlobalInfoModel, LoadingStatus, PageContext, StorageKey } from '@ohos/common';\n+import {\n+ BaseVM,\n+ CommonConstants,\n+ GlobalInfoModel,\n+ LoadingStatus,\n+ PageContext,\n+ StorageKey,\n+} from '@ohos/common';\n import { ComponentDetailParams, SampleDetailParams, TabBarType } from '@ohos/commonbusiness';\n import type { DiscoverContent } from '../model/DiscoverData';\n import { ExplorationDetailState } from './ExplorationDetailState';\n@@ -32,6 +39,8 @@ export class ArticleDetailViewModel extends BaseVM<ExplorationDetailState> {\n return this.pop(param.animation, param.tabBarView);\n } else if (eventParam.type === ExplorationDetailEventType.JUMP_NATIVE_PAGE) {\n return this.jumpNativePage(eventParam.param as NativePageParam);\n+ } else if (eventParam.type === ExplorationDetailEventType.CHANGE_TITLE_BAR_STYLE) {\n+ return this.changeTitleBarStyle(eventParam.param as number);\n }\n throw new Error('Method not implemented.');\n }\n@@ -41,9 +50,16 @@ export class ArticleDetailViewModel extends BaseVM<ExplorationDetailState> {\n this.state.content = detailParam.content;\n this.state.content.detailsUrl = `resource://resfile/${detailParam.content.detailsUrl}`;\n this.state.topNavigationData.onBackClick = detailParam.onBackClick;\n+ this.state.topNavigationData.isFullScreen = true;\n+ this.changeTitleBarStyle(0);\n return Promise.resolve();\n }\n \n+ private changeTitleBarStyle(yOffset: number): void {\n+ this.state.topNavigationData.title = yOffset > CommonConstants.NAVIGATION_HEIGHT ? this.state.content.title : '';\n+ this.state.topNavigationData.isBlur = yOffset > CommonConstants.SPACE_12;\n+ }\n+\n private pop(animated: boolean = true, tabBarView: number = TabBarType.HOME): void {\n const globalInfoModel: GlobalInfoModel = AppStorage.get(StorageKey.GLOBAL_INFO)!;\n let currentPathStack: PageContext = AppStorage.get(StorageKey.HOME_PAGE_CONTEXT) as PageContext;\n@@ -59,7 +75,6 @@ export class ArticleDetailViewModel extends BaseVM<ExplorationDetailState> {\n currentPathStack.popPage(animated);\n }\n \n-\n private jumpNativePage(param: NativePageParam): void {\n const globalInfoModel: GlobalInfoModel = AppStorage.get(StorageKey.GLOBAL_INFO)!;\n let pageContext: PageContext = AppStorage.get(StorageKey.HOME_PAGE_CONTEXT) as PageContext;\n@@ -92,6 +107,7 @@ export enum ExplorationDetailEventType {\n POP = 'pop',\n HANDLE_TITLE_EFFECT = 'handleTitleEffect',\n JUMP_NATIVE_PAGE = 'jumpNativePage',\n+ CHANGE_TITLE_BAR_STYLE = 'changeTitleBarStyle',\n }\n \n export interface ExplorationDetailEventParam<T> {\ndiff --git a/products/phone/src/main/ets/page/MainPage.ets b/products/phone/src/main/ets/page/MainPage.ets\nindex 2f42c508..e1e6a8a2 100644\n--- a/products/phone/src/main/ets/page/MainPage.ets\n+++ b/products/phone/src/main/ets/page/MainPage.ets\n@@ -15,8 +15,18 @@\n \n import type { common } from '@kit.AbilityKit';\n import { ConfigurationConstant } from '@kit.AbilityKit';\n+import { SymbolGlyphModifier } from '@kit.ArkUI';\n+import {\n+ HdsNavDestination,\n+ HdsNavDestinationAttribute,\n+ HdsSideBar,\n+ HdsTabs,\n+ HdsTabsAttribute,\n+ DividerMode,\n+ HdsTabsController,\n+} from '@kit.UIDesignKit';\n import type { GlobalInfoModel, WantParams } from '@ohos/common';\n-import { CommonConstants, ProcessUtil, StorageKey, Toast, WindowUtil } from '@ohos/common';\n+import { BreakpointType, CommonConstants, ProcessUtil, StorageKey, Toast, VersionUtil, WindowUtil } from '@ohos/common';\n import { TAB_CONTENT_STATUSES, TabBarType } from '@ohos/commonbusiness';\n import { ComponentListView } from '@ohos/componentlibrary';\n import { PracticesView } from '@ohos/devpractices';\n@@ -24,6 +34,7 @@ import { ExplorationView } from '@ohos/exploration';\n import { MineView } from '@ohos/mine';\n import { CustomSideBar } from '../component/CustomSideBar';\n import { CustomTabBar } from '../component/CustomTabBar';\n+import { TABS_LIST } from '../model/TabBarModel';\n import { JumpToPageEvent, MainPageViewModel } from '../viewmodel/MainPageViewModel';\n \n const PRESS_TIME = 1500;\n@@ -39,48 +50,33 @@ struct MainPage {\n @StorageProp(StorageKey.COLOR_MODE) @Watch('handleColorModeChange') systemColorMode: ConfigurationConstant.ColorMode =\n AppStorage.get(StorageKey.COLOR_MODE)!;\n @State currentIndex: number = 0;\n- private tabController: TabsController = new TabsController();\n+ private tabController: TabsController | HdsTabsController =\n+ VersionUtil.canUseHds() ? new HdsTabsController() : new TabsController();\n private backPressTime: number = 0;\n private isShown: boolean = false;\n private mainPageViewModel: MainPageViewModel = new MainPageViewModel();\n \n @Builder\n- TabComponent() {\n- Tabs({ controller: this.tabController, index: this.currentIndex }) {\n- TabContent() {\n- ComponentListView()\n- }\n- .height('100%')\n+ TabContentsBuilder(showTabBar: boolean) {\n+ TabContent() {\n+ ComponentListView()\n+ }\n+ .tabBar(showTabBar ? this.bottomTabBarStyle(TabBarType.HOME) : new SubTabBarStyle(''))\n \n- TabContent() {\n- PracticesView()\n- }\n- .height('100%')\n+ TabContent() {\n+ PracticesView()\n+ }\n+ .tabBar(showTabBar ? this.bottomTabBarStyle(TabBarType.SAMPLE) : new SubTabBarStyle(''))\n \n- TabContent() {\n- ExplorationView()\n- }\n- .height('100%')\n+ TabContent() {\n+ ExplorationView()\n+ }\n+ .tabBar(showTabBar ? this.bottomTabBarStyle(TabBarType.PRACTICE) : new SubTabBarStyle(''))\n \n- TabContent() {\n- MineView()\n- }\n- .height('100%')\n+ TabContent() {\n+ MineView()\n }\n- .onAttach(() => {\n- this.tabController.preloadItems([TabBarType.HOME, TabBarType.SAMPLE, TabBarType.PRACTICE])\n- })\n- .onAnimationStart((index: number, targetIndex: number) => {\n- this.changeTabStatus(targetIndex);\n- this.currentIndex = targetIndex;\n- })\n- .animationMode(AnimationMode.NO_ANIMATION)\n- .barWidth(0)\n- .barHeight(0)\n- .scrollable(false)\n- .backgroundColor($r('sys.color.background_secondary'))\n- .height('100%')\n- .width('100%')\n+ .tabBar(showTabBar ? this.bottomTabBarStyle(TabBarType.MINE) : new SubTabBarStyle(''))\n }\n \n aboutToAppear(): void {\n@@ -88,6 +84,11 @@ struct MainPage {\n }\n \n onPageShow(): void {\n+ this.isShown = true;\n+ this.handleColorModeChange();\n+ CommonConstants.PROMISE_WAIT(500).then(() => {\n+ AppStorage.setOrCreate(StorageKey.BLUE_RENDER_GROUP, false);\n+ });\n const wantParams: WantParams | undefined = AppStorage.get<WantParams>(StorageKey.WANT_PARAMETERS);\n AppStorage.delete(StorageKey.WANT_PARAMETERS);\n if (wantParams) {\n@@ -101,7 +102,7 @@ struct MainPage {\n const newTime = new Date().getTime();\n if (this.backPressTime && newTime - this.backPressTime < PRESS_TIME) {\n ProcessUtil.moveAbilityToBackground(this.getUIContext().getHostContext() as common.UIAbilityContext);\n- return false;\n+ return true;\n }\n this.backPressTime = newTime;\n Toast.showToast($r('app.string.back_toast'));\n@@ -118,6 +119,7 @@ struct MainPage {\n } else {\n WindowUtil.updateStatusBarColor(isSystemDark || TAB_CONTENT_STATUSES[selectedIndex]);\n }\n+ this.currentIndex = index;\n }\n \n handleColorModeChange() {\n@@ -126,52 +128,141 @@ struct MainPage {\n }\n }\n \n+ bottomTabBarStyle(tabType: TabBarType): BottomTabBarStyle {\n+ const tabItem = TABS_LIST[tabType];\n+ return BottomTabBarStyle.of({ normal: new SymbolGlyphModifier(tabItem.icon) }, tabItem.title)\n+ .padding({\n+ bottom: this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_LG ? 0 :\n+ this.globalInfoModel.naviIndicatorHeight\n+ })\n+ }\n+\n+ @Builder\n+ HdsTabComponent() {\n+ HdsTabs({ controller: this.tabController as HdsTabsController, index: this.currentIndex }) {\n+ this.TabContentsBuilder(this.globalInfoModel.widthBreakpoint !== WidthBreakpoint.WIDTH_XL)\n+ }\n+ .backgroundColor($r('sys.color.background_secondary'))\n+ .vertical(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_LG)\n+ .barBackgroundColor(Color.Transparent)\n+ .barPosition(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_LG ? BarPosition.Start :\n+ BarPosition.End)\n+ .divider({\n+ mode: DividerMode.FOLLOW_SCROLL,\n+ })\n+ .barHeight(new BreakpointType<Length>({\n+ sm: CommonConstants.TAB_BAR_HEIGHT + this.globalInfoModel.naviIndicatorHeight,\n+ md: CommonConstants.TAB_BAR_HEIGHT + this.globalInfoModel.naviIndicatorHeight,\n+ lg: '100%',\n+ xl: 0,\n+ }).getValue(this.globalInfoModel.widthBreakpoint))\n+ .barOverlap(true)\n+ .scrollable(false)\n+ .onAttach(() => {\n+ this.tabController?.preloadItems([TabBarType.HOME, TabBarType.SAMPLE, TabBarType.PRACTICE])\n+ })\n+ .onChange((index: number) => {\n+ this.changeTabStatus(index);\n+ })\n+ }\n+\n+ @Builder\n+ CustomSideBarBuilder() {\n+ CustomSideBar({\n+ currentIndex: this.currentIndex,\n+ sideBarChange: (currentIndex: number) => {\n+ this.changeTabStatus(currentIndex);\n+ }\n+ })\n+ }\n+\n+ @Builder\n+ TabComponent() {\n+ Tabs({ controller: this.tabController, index: this.currentIndex }) {\n+ this.TabContentsBuilder(false)\n+ }\n+ .onAttach(() => {\n+ this.tabController.preloadItems([TabBarType.HOME, TabBarType.SAMPLE, TabBarType.PRACTICE])\n+ })\n+ .onAnimationStart((index: number, targetIndex: number) => {\n+ this.changeTabStatus(targetIndex);\n+ })\n+ .animationMode(AnimationMode.NO_ANIMATION)\n+ .barWidth(0)\n+ .barHeight(0)\n+ .scrollable(false)\n+ .backgroundColor($r('sys.color.background_secondary'))\n+ }\n+\n build() {\n- NavDestination() {\n- SideBarContainer(SideBarContainerType.Embed) {\n- CustomSideBar({\n- currentIndex: this.currentIndex,\n- sideBarChange: (currentIndex: number) => {\n- this.changeTabStatus(currentIndex);\n- this.currentIndex = currentIndex;\n+ if (VersionUtil.canUseHds()) {\n+ HdsNavDestination() {\n+ HdsSideBar({\n+ isShowSideBar: this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL,\n+ autoHide: false,\n+ sideBarPanelBuilder: () => {\n+ this.CustomSideBarBuilder()\n+ },\n+ contentPanelBuilder: () => {\n+ this.HdsTabComponent()\n }\n- });\n- Stack({ alignContent: Alignment.BottomStart }) {\n- this.TabComponent()\n- CustomTabBar({\n- currentIndex: this.currentIndex, tabBarChange: (currentIndex: number) => {\n+ })\n+ }\n+ .transition(TransitionEffect.OPACITY)\n+ .hideTitleBar(true)\n+ .backgroundColor($r('sys.color.background_secondary'))\n+ .onBackPressed(() => {\n+ return this.onBackPress();\n+ })\n+ .onShown(() => {\n+ this.onPageShow();\n+ })\n+ .onHidden(() => {\n+ AppStorage.setOrCreate(StorageKey.BLUE_RENDER_GROUP, true);\n+ this.isShown = false;\n+ })\n+ .height('100%')\n+ .width('100%')\n+ } else {\n+ NavDestination() {\n+ SideBarContainer(SideBarContainerType.Embed) {\n+ CustomSideBar({\n+ currentIndex: this.currentIndex,\n+ sideBarChange: (currentIndex: number) => {\n this.changeTabStatus(currentIndex);\n- this.currentIndex = currentIndex;\n }\n })\n- .visibility(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL ? Visibility.None :\n- Visibility.Visible)\n+ Stack({ alignContent: Alignment.BottomStart }) {\n+ this.TabComponent()\n+ CustomTabBar({\n+ currentIndex: this.currentIndex, tabBarChange: (currentIndex: number) => {\n+ this.changeTabStatus(currentIndex);\n+ this.currentIndex = currentIndex;\n+ }\n+ })\n+ .visibility(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL ? Visibility.None :\n+ Visibility.Visible)\n+ }\n }\n+ .autoHide(false)\n+ .showSideBar(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL)\n+ .showControlButton(false)\n }\n- .autoHide(false)\n- .showSideBar(this.globalInfoModel.widthBreakpoint === WidthBreakpoint.WIDTH_XL)\n- .showControlButton(false)\n- }\n- .transition(TransitionEffect.OPACITY)\n- .hideTitleBar(true)\n- .backgroundColor($r('sys.color.background_secondary'))\n- .onBackPressed(() => {\n- this.onBackPress();\n- return true;\n- })\n- .onShown(() => {\n- this.isShown = true;\n- this.onPageShow();\n- this.handleColorModeChange();\n- CommonConstants.PROMISE_WAIT(500).then(() => {\n- AppStorage.setOrCreate(StorageKey.BLUE_RENDER_GROUP, false);\n+ .transition(TransitionEffect.OPACITY)\n+ .hideTitleBar(true)\n+ .backgroundColor($r('sys.color.background_secondary'))\n+ .onBackPressed(() => {\n+ return this.onBackPress();\n })\n- })\n- .onHidden(() => {\n- AppStorage.setOrCreate(StorageKey.BLUE_RENDER_GROUP, true);\n- this.isShown = false;\n- })\n- .height('100%')\n- .width('100%')\n+ .onShown(() => {\n+ this.onPageShow();\n+ })\n+ .onHidden(() => {\n+ AppStorage.setOrCreate(StorageKey.BLUE_RENDER_GROUP, true);\n+ this.isShown = false;\n+ })\n+ .height('100%')\n+ .width('100%')\n+ }\n }\n }\n\\ No newline at end of file\ndiff --git a/products/phone/src/main/ets/page/SplashPage.ets b/products/phone/src/main/ets/page/SplashPage.ets\nindex 0fce8135..39d9c7b0 100644\n--- a/products/phone/src/main/ets/page/SplashPage.ets\n+++ b/products/phone/src/main/ets/page/SplashPage.ets\n@@ -14,6 +14,7 @@\n */\n \n import { ConfigurationConstant } from '@kit.AbilityKit';\n+import { HdsNavigation, HdsNavigationAttribute } from '@kit.UIDesignKit';\n import {\n BundleInfoData,\n CommonConstants,\n@@ -21,6 +22,7 @@ import {\n PageContext,\n ResourceUtil,\n StorageKey,\n+ VersionUtil,\n WindowUtil,\n } from '@ohos/common';\n import { SplashEventTypeEnum, SplashViewModel } from '../viewmodel/SplashViewModel';\n@@ -52,16 +54,31 @@ struct SplashPage {\n ResourceUtil.getDrawableDescriptor(this.context, this.bundleInfo.iconResource.id);\n }\n \n+ @Builder\n+ contentBuilder() {\n+ Column()\n+ .width('100%')\n+ .height('100%')\n+ .backgroundColor($r('app.color.start_window_background'))\n+ }\n+\n build() {\n- Navigation(this.appPathInfo) {\n- Column()\n- .width('100%')\n- .height('100%')\n- .backgroundColor($r('app.color.start_window_background'))\n+ if (VersionUtil.canUseHds()) {\n+ HdsNavigation(this.appPathInfo) {\n+ this.contentBuilder()\n+ }\n+ .hideTitleBar(true)\n+ .mode(NavigationMode.Stack)\n+ .height('100%')\n+ .width('100%')\n+ } else {\n+ Navigation(this.appPathInfo) {\n+ this.contentBuilder()\n+ }\n+ .hideTitleBar(true)\n+ .mode(NavigationMode.Stack)\n+ .height('100%')\n+ .width('100%')\n }\n- .hideTitleBar(true)\n- .mode(NavigationMode.Stack)\n- .height('100%')\n- .width('100%')\n }\n }\n\\ No newline at end of file\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "hard",
"type": "issue_fix"
},
{
"instance_id": "ArkTs_Exp_017",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "9d544fff",
"problem_statement": "将首页组件库多行文本输入TextArea组件的预览区域的文本改成可编辑,并且能够在调整区域进行调整",
"hints_text": "",
"patch": "diff --git a/features/componentlibrary/src/main/ets/componentdetailview/textarea/component/TextAreaBuilder.ets b/features/componentlibrary/src/main/ets/componentdetailview/textarea/component/TextAreaBuilder.ets\nindex 4fc6be6..3704963 100644\n--- a/features/componentlibrary/src/main/ets/componentdetailview/textarea/component/TextAreaBuilder.ets\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/textarea/component/TextAreaBuilder.ets\n@@ -31,6 +31,7 @@ export function TextAreaBuilder($$: DescriptorWrapper) {\n @Component\n struct TextAreaComponent {\n @Prop textAreaDescriptor: TextAreaDescriptor;\n+ @State textStr: ResourceStr = $r('app.string.textarea_text');\n // Height of the component preview area.\n @State textAreaInputHeight: number = 0;\n @State contentOffset: number = 0;\n@@ -66,7 +67,7 @@ struct TextAreaComponent {\n build() {\n Column() {\n TextArea({\n- text: $r('app.string.textarea_text'),\n+ text: this.textStr,\n placeholder: $r('app.string.text_placeholder'),\n })\n .margin({\n@@ -86,6 +87,9 @@ struct TextAreaComponent {\n curve: Curve.Linear,\n playMode: PlayMode.Normal,\n })\n+ .onChange((value: string) => {\n+ this.textStr = value;\n+ })\n }\n .height('100%')\n .width($r('app.float.multiline_text_width'))\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "issue_fix"
},
{
"instance_id": "ArkTs_Exp_018",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "f6a24293",
"problem_statement": "HMOS代码工坊快捷入口需求:APP长按应用图标出现快捷入口,包括组件案例、示例代码、技术文章,支持快速跳转组件、样例、实践模块首页",
"hints_text": "",
"patch": "diff --git b/products/phone/src/main/module.json5 a/products/phone/src/main/module.json5\nindex 4f9fb0d..105a648 100644\n--- b/products/phone/src/main/module.json5\n+++ a/products/phone/src/main/module.json5\n@@ -38,6 +38,12 @@\n \"domainVerify\": true\n }\n ],\n+ \"metadata\": [\n+ {\n+ \"name\": \"ohos.ability.shortcuts\",\n+ \"resource\": \"$profile:shortcuts_config\"\n+ }\n+ ]\n }\n ],\n \"extensionAbilities\": [\ndiff --git b/products/phone/src/main/resources/base/profile/shortcuts_config.json a/products/phone/src/main/resources/base/profile/shortcuts_config.json\nnew file mode 100644\nindex 0000000..ea354dd\n--- /dev/null\n+++ a/products/phone/src/main/resources/base/profile/shortcuts_config.json\n@@ -0,0 +1,52 @@\n+{\n+ \"shortcuts\": [\n+ {\n+ \"shortcutId\": \"id_component_list\",\n+ \"label\": \"$string:component_cases\",\n+ \"icon\": \"$media:shortcut_component_full\",\n+ \"wants\": [\n+ {\n+ \"bundleName\": \"com.huawei.hmos.world\",\n+ \"moduleName\": \"phone\",\n+ \"abilityName\": \"EntryAbility\",\n+ \"parameters\": {\n+ \"shortCutKey\": \"ComponentListPage\",\n+ \"isFromShortCut\": \"true\"\n+ }\n+ }\n+ ]\n+ },\n+ {\n+ \"shortcutId\": \"id_sample_list\",\n+ \"label\": \"$string:sample_cases\",\n+ \"icon\": \"$media:shortcut_sample_full\",\n+ \"wants\": [\n+ {\n+ \"bundleName\": \"com.huawei.hmos.world\",\n+ \"moduleName\": \"phone\",\n+ \"abilityName\": \"EntryAbility\",\n+ \"parameters\": {\n+ \"shortCutKey\": \"SampleListPage\",\n+ \"isFromShortCut\": \"true\"\n+ }\n+ }\n+ ]\n+ },\n+ {\n+ \"shortcutId\": \"id_article_list\",\n+ \"label\": \"$string:article_cases\",\n+ \"icon\": \"$media:shortcut_article_full\",\n+ \"wants\": [\n+ {\n+ \"bundleName\": \"com.huawei.hmos.world\",\n+ \"moduleName\": \"phone\",\n+ \"abilityName\": \"EntryAbility\",\n+ \"parameters\": {\n+ \"shortCutKey\": \"ArticleListPage\",\n+ \"isFromShortCut\": \"true\"\n+ }\n+ }\n+ ]\n+ }\n+ ]\n+}\n\\ No newline at end of file\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "medium",
"type": "new_feature"
},
{
"instance_id": "ArkTs_Exp_020",
"repo": "internal_green/HMOSWorldClient",
"base_commit": "81b00292",
"problem_statement": "修改意见反馈最多输入字符为1000",
"hints_text": "",
"patch": "diff --git a/features/mine/src/main/ets/constant/CommonConstants.ets b/features/mine/src/main/ets/constant/CommonConstants.ets\nindex f263e680..60b9bf15 100644\n--- a/features/mine/src/main/ets/constant/CommonConstants.ets\n+++ b/features/mine/src/main/ets/constant/CommonConstants.ets\n@@ -16,7 +16,7 @@\n export class MineConstant {\n public static readonly RATING_STEP: number = 1;\n public static readonly TOAST_DURATION: number = 1000;\n- public static readonly TEXTAREA_MAX_LENGTH: number = 100;\n+ public static readonly TEXTAREA_MAX_LENGTH: number = 1000;\n public static readonly COUNTER_THRESHOLD: number = 1;\n public static readonly LANES_SM: number = 1;\n public static readonly LANES_MD: number = 2;\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "issue_fix"
},
{
"instance_id": "ArkTs_Exp_030",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "f02c38a3",
"problem_statement": "请实现一个意见反馈组件 FeedbackSheet,要求如下:\n\n1.集成方式\n - 在所有的 PracticeDetailView 详情页中集成该组件,在导航栏菜单的右边添加SymbolGlyph反馈入口图标,点击该图标出现意见反馈页面。\n\n2. 组件名称为 FeedbackSheet,使用 @Component 装饰器\n\n3. 功能需求:\n - 显示\"点赞\"和\"点踩\"两个按钮(使用 SymbolGlyph 的 hand_thumbsup 和 hand_thumbsdown 图标)\n - 两个按钮互斥,点击一个会取消另一个的选中状态\n - 选中按钮后,下方显示对应的反馈原因列表(4个选项,使用 List + ForEach 实现,支持多选)\n - 点赞选项:使用方式清晰、可直接复用、场景描述清晰、场景有创新性\n - 点踩选项:操作不成功、闪退、操作卡顿、内容不清晰\n - 反馈列表下方显示 TextInput 输入框(placeholder: \"留下您的意见\",最大100字)\n - 底部显示\"提交\"按钮,只有选中反馈原因后才可点击(opacity 控制可用状态)\n\n4. 交互特性:\n - 使用 bindSheet 绑定半模态弹窗,标题为\"意见反馈\"\n - 弹窗高度根据状态动态调整:初始高度273vp、选中按钮后500vp、输入框获得焦点后748vp\n - 输入框获得焦点时使用 keyboardAvoidMode: SheetKeyboardAvoidMode.TRANSLATE_AND_RESIZE\n - 提交成功后关闭弹窗并重置所有状态\n\n5. 状态管理:\n - 使用 @Link 接收外部控制弹窗显示的变量 bindFeedBack\n - 使用 @State 管理点赞/点踩状态、反馈列表选中状态、输入文本等\n - 使用 @Watch 监听状态变化以动态调整弹窗高度\n\n6. 样式要求:\n - 使用系统资源符号($r('sys.color.xxx'))保持 HarmonyOS 设计规范\n - 按钮使用 ButtonType.Capsule 类型\n - 列表项使用 lanes(3) 实现三列布局\n\n7.资源文件\n - 创建 FeedbackConstants 常量类,定义三种弹窗高度\n - 在 string.json 中添加中英文反馈选项文案",
"hints_text": "",
"patch": "diff --git a/common/Index.ets b/common/Index.ets\nindex bb01ef7..955b3a3 100644\n--- a/common/Index.ets\n+++ b/common/Index.ets\n@@ -104,4 +104,6 @@ export { TextOverflowProperty } from './src/main/ets/util/TextOverflowUtil';\n \n export { FormCardEnum, ArticleListItem } from './src/main/ets/model/FormCardInfo';\n \n-export { SampleDistributionUtil } from './src/main/ets/util/SampleDistributionUtil';\n\\ No newline at end of file\n+export { SampleDistributionUtil } from './src/main/ets/util/SampleDistributionUtil';\n+\n+export { FeedbackSheet } from './src/main/ets/component/FeedbackSheet';\n\\ No newline at end of file\ndiff --git a/common/src/main/ets/component/FeedbackSheet.ets b/common/src/main/ets/component/FeedbackSheet.ets\nnew file mode 100644\nindex 0000000..316fe22\n--- /dev/null\n+++ b/common/src/main/ets/component/FeedbackSheet.ets\n@@ -0,0 +1,244 @@\n+/*\n+ * Copyright (c) 2025 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License,Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import { Toast } from '../../../../Index';\n+import { StorageKey } from '../constant/CommonEnums';\n+import { FeedbackConstants } from '../constant/FeedbackConstants';\n+import { GlobalInfoModel } from '../model/GlobalInfoModel';\n+\n+@Component\n+export struct FeedbackSheet {\n+ @Link bindFeedBack: boolean;\n+ @StorageProp(StorageKey.GLOBAL_INFO) globalInfoModel: GlobalInfoModel = AppStorage.get(StorageKey.GLOBAL_INFO)!;\n+ @State @Watch('expandStatusChange') upClickStatus: boolean = false;\n+ @State @Watch('expandStatusChange') downClickStatus: boolean = false;\n+ @State feedListStatus: boolean[] = [false, false, false, false];\n+ @State textValue: string = '';\n+ private upFeedList: Resource[] =\n+ [$r('app.string.feedback_up1'), $r('app.string.feedback_up2'), $r('app.string.feedback_up3'),\n+ $r('app.string.feedback_up4')];\n+ private downFeedList: Resource[] =\n+ [$r('app.string.feedback_down1'), $r('app.string.feedback_down2'), $r('app.string.feedback_down3'),\n+ $r('app.string.feedback_down4')];\n+ @State @Watch('expandStatusChange') editStatus: boolean = false;\n+ @State listSelected: boolean = false;\n+ @State feedbackHeight: number = FeedbackConstants.FEEDBACK_HEIGHT_LOW;\n+\n+ judgeList(): boolean {\n+ for (let i = 0; i < this.feedListStatus.length; i++) {\n+ if (this.feedListStatus[i]) {\n+ return true;\n+ }\n+ }\n+ return false;\n+ }\n+\n+ expandStatusChange() {\n+ if (this.editStatus) {\n+ this.feedbackHeight = FeedbackConstants.FEEDBACK_HEIGHT_HIGH;\n+ } else {\n+ if (this.upClickStatus || this.downClickStatus) {\n+ this.feedbackHeight = FeedbackConstants.FEEDBACK_HEIGHT_MED;\n+ } else {\n+ this.feedbackHeight = FeedbackConstants.FEEDBACK_HEIGHT_LOW;\n+ }\n+ }\n+ }\n+\n+ private cleanListSelectedStatus(): void {\n+ this.feedListStatus = [false, false, false, false];\n+ }\n+\n+ private cleanButtonStatus(): void {\n+ this.upClickStatus = false;\n+ this.downClickStatus = false;\n+ }\n+\n+ @Builder\n+ FeedbackBuilder() {\n+ Column() {\n+ Row() {\n+ Column() {\n+ Button({ type: ButtonType.Capsule }) {\n+ SymbolGlyph($r('sys.symbol.hand_thumbsup'))\n+ .fontSize(24)\n+ .fontColor([this.upClickStatus ? $r('sys.color.background_primary') :\n+ $r('sys.color.font_primary')])\n+ }\n+ .width(48)\n+ .height(48)\n+ .backgroundColor(this.upClickStatus ? $r('sys.color.brand') :\n+ $r('sys.color.comp_background_tertiary'))\n+ .onClick(() => {\n+ this.cleanListSelectedStatus();\n+ if (!this.upClickStatus && !this.downClickStatus) {\n+ this.upClickStatus = true;\n+ } else if (this.upClickStatus && !this.downClickStatus) {\n+ this.upClickStatus = false;\n+ } else if (!this.upClickStatus && this.downClickStatus) {\n+ this.downClickStatus = false;\n+ this.upClickStatus = true;\n+ this.listSelected = this.judgeList();\n+ this.textValue = '';\n+ }\n+ })\n+\n+ Text('点赞')\n+ .lineHeight(1)\n+ .fontSize(14)\n+ .fontWeight(400)\n+ .fontColor(this.upClickStatus ? $r('sys.color.brand') :\n+ $r('sys.color.font_primary'))\n+ }\n+ .justifyContent(FlexAlign.SpaceBetween)\n+ .width(48)\n+ .height(73)\n+\n+ Column() {\n+ Button({ type: ButtonType.Capsule }) {\n+ SymbolGlyph($r('sys.symbol.hand_thumbsdown'))\n+ .fontSize(24)\n+ .fontColor([this.downClickStatus ? $r('sys.color.background_primary') :\n+ $r('sys.color.font_primary')])\n+ }\n+ .width(48)\n+ .height(48)\n+ .backgroundColor(this.downClickStatus ? $r('sys.color.brand') :\n+ $r('sys.color.comp_background_tertiary'))\n+ .onClick(() => {\n+ this.cleanListSelectedStatus();\n+ if (!this.upClickStatus && !this.downClickStatus) {\n+ this.downClickStatus = true;\n+ } else if (!this.upClickStatus && this.downClickStatus) {\n+ this.downClickStatus = false;\n+ } else if (this.upClickStatus && !this.downClickStatus) {\n+ this.upClickStatus = false;\n+ this.downClickStatus = true;\n+ this.listSelected = this.judgeList();\n+ this.textValue = '';\n+ }\n+ })\n+\n+ Text('点踩')\n+ .lineHeight(1)\n+ .fontSize(14)\n+ .fontWeight(400)\n+ .fontColor(this.downClickStatus ? $r('sys.color.brand') :\n+ $r('sys.color.font_primary'))\n+ }\n+ .justifyContent(FlexAlign.SpaceBetween)\n+ .width(48)\n+ .height(73)\n+ }\n+ .justifyContent(FlexAlign.SpaceBetween)\n+ .height(73)\n+ .width('100%')\n+ .padding({ left: 77, right: 77 })\n+ .margin({ bottom: 40 })\n+\n+ if (this.upClickStatus || this.downClickStatus) {\n+ List({ space: 8 }) {\n+ ForEach(this.upClickStatus ? this.upFeedList : this.downFeedList, (item: string, index: number) => {\n+ ListItem() {\n+ Text(item)\n+ .textAlign(TextAlign.Center)\n+ .borderRadius('50%')\n+ .fontColor(this.feedListStatus[index] ? $r('sys.color.brand') : $r('sys.color.font_primary'))\n+ .fontSize(14)\n+ .fontWeight(400)\n+ .height(28)\n+ .width(104)\n+ .backgroundColor($r('sys.color.comp_background_tertiary'))\n+ .onClick(() => {\n+ this.feedListStatus[index] = !this.feedListStatus[index];\n+ this.listSelected = this.judgeList();\n+ })\n+ }\n+ })\n+ }\n+ .alignListItem(ListItemAlign.Center)\n+ .lanes(3)\n+ .margin({ bottom: 16 })\n+ }\n+ if (this.upClickStatus || this.downClickStatus) {\n+ Column() {\n+ TextInput({ placeholder: '留下您的意见', text: this.textValue })\n+ .showCounter(true, { thresholdPercentage: 1 })\n+ .maxLength(100)\n+ .height(71)\n+ .backgroundColor(Color.Transparent)\n+ .textAlign(TextAlign.Start)\n+ .align(Alignment.TopStart)\n+ .onEditChange((editStatus: boolean) => {\n+ this.editStatus = editStatus;\n+ })\n+ .onChange((value: string) => {\n+ this.textValue = value;\n+ })\n+\n+ }\n+ .margin({ bottom: 16 })\n+ .borderRadius(16)\n+ .backgroundColor($r('sys.color.comp_background_tertiary'))\n+ .height(104)\n+ }\n+\n+ if (!this.editStatus) {\n+ Button('提交')\n+ .height(40)\n+ .width('100%')\n+ .borderRadius('50%')\n+ .fontSize($r('sys.float.Body_M'))\n+ .fontWeight(FontWeight.Medium)\n+ .backgroundColor($r('sys.color.background_emphasize'))\n+ .fontColor($r('sys.color.font_on_primary'))\n+ .controlSize(ControlSize.NORMAL)\n+ .opacity(((this.upClickStatus || this.downClickStatus) && this.listSelected) ? 1 : 0.4)\n+ .onClick(() => {\n+ if ((this.downClickStatus || this.upClickStatus) && this.listSelected) {\n+ this.bindFeedBack = false;\n+ this.cleanListSelectedStatus();\n+ this.cleanButtonStatus();\n+ this.textValue = '';\n+ } else {\n+ Toast.showToast('请反馈具体原因')\n+ }\n+ })\n+ }\n+ }\n+ .padding({\n+ top: 16,\n+ left: 16,\n+ right: 16,\n+ bottom: this.globalInfoModel.naviIndicatorHeight,\n+ })\n+ .width('100%')\n+ }\n+\n+ build() {\n+ Column() {\n+ }\n+ .bindSheet(this.bindFeedBack, this.FeedbackBuilder(), {\n+ title: { title: '意见反馈' },\n+ preferType: SheetType.CENTER,\n+ height: this.feedbackHeight,\n+ width: '100%',\n+ onWillDisappear: () => {\n+ this.bindFeedBack = false;\n+ },\n+ keyboardAvoidMode: SheetKeyboardAvoidMode.TRANSLATE_AND_RESIZE,\n+ })\n+ }\n+}\n\\ No newline at end of file\ndiff --git a/common/src/main/ets/constant/FeedbackConstants.ets b/common/src/main/ets/constant/FeedbackConstants.ets\nnew file mode 100644\nindex 0000000..90ed9b6\n--- /dev/null\n+++ b/common/src/main/ets/constant/FeedbackConstants.ets\n@@ -0,0 +1,21 @@\n+/*\n+ * Copyright (c) 2025 Huawei Device Co., Ltd.\n+ * Licensed under the Apache License,Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+export class FeedbackConstants {\n+ // Feedback property\n+ public static FEEDBACK_HEIGHT_LOW: number = 273;\n+ public static FEEDBACK_HEIGHT_MED: number = 500;\n+ public static FEEDBACK_HEIGHT_HIGH: number = 748;\n+}\n\\ No newline at end of file\ndiff --git a/common/src/main/resources/base/element/string.json b/common/src/main/resources/base/element/string.json\nindex 63774a3..01b8a39 100644\n--- a/common/src/main/resources/base/element/string.json\n+++ b/common/src/main/resources/base/element/string.json\n@@ -19,6 +19,110 @@\n {\n \"name\": \"network_setting\",\n \"value\": \"Setting up the network.\"\n+ },\n+ {\n+ \"name\": \"feedback_up1\",\n+ \"value\": \"clear usage method\"\n+ },\n+ {\n+ \"name\": \"feedback_up2\",\n+ \"value\": \"can be directly reused\"\n+ },\n+ {\n+ \"name\": \"feedback_up3\",\n+ \"value\": \"The scene description is clear\"\n+ },\n+ {\n+ \"name\": \"feedback_up4\",\n+ \"value\": \"The scene is innovative\"\n+ },\n+ {\n+ \"name\": \"feedback_down1\",\n+ \"value\": \"Operation unsuccessful\"\n+ },\n+ {\n+ \"name\": \"feedback_down2\",\n+ \"value\": \"Crash\"\n+ },\n+ {\n+ \"name\": \"feedback_down3\",\n+ \"value\": \"Operation lag\"\n+ },\n+ {\n+ \"name\": \"feedback_down4\",\n+ \"value\": \"Content is unclear\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up1\",\n+ \"value\": \"Clear usage method\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up2\",\n+ \"value\": \"Can be directly reused\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up3\",\n+ \"value\": \"The scene description is clear\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up4\",\n+ \"value\": \"Highly practical for various scenarios\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up5\",\n+ \"value\": \"The interface is aesthetically pleasing\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up6\",\n+ \"value\": \"The interface layout is reasonable\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up7\",\n+ \"value\": \"Fast loading speed\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up8\",\n+ \"value\": \"Convenient interaction\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up9\",\n+ \"value\": \"Well adapted to multiple devices\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down1\",\n+ \"value\": \"Download experience issues\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down2\",\n+ \"value\": \"The scene is unclear\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down3\",\n+ \"value\": \"Not very practical\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down4\",\n+ \"value\": \"Lacks originality\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down5\",\n+ \"value\": \"Version incompatible\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down6\",\n+ \"value\": \"Incompatible with multiple devices\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down7\",\n+ \"value\": \"Crash/Stutter\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down8\",\n+ \"value\": \"The interaction logic is confusing\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down9\",\n+ \"value\": \"The interface is not aesthetically pleasing.\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/common/src/main/resources/en_US/element/string.json b/common/src/main/resources/en_US/element/string.json\nindex 63774a3..3503855 100644\n--- a/common/src/main/resources/en_US/element/string.json\n+++ b/common/src/main/resources/en_US/element/string.json\n@@ -19,6 +19,106 @@\n {\n \"name\": \"network_setting\",\n \"value\": \"Setting up the network.\"\n+ },\n+ {\n+ \"name\": \"feedback_up1\",\n+ \"value\": \"clear usage method\"\n+ },\n+ {\n+ \"name\": \"feedback_up2\",\n+ \"value\": \"can be directly reused\"\n+ },\n+ {\n+ \"name\": \"feedback_up3\",\n+ \"value\": \"The scene description is clear\"\n+ },\n+ {\n+ \"name\": \"feedback_up4\",\n+ \"value\": \"The scene is innovative\"\n+ },\n+ {\n+ \"name\": \"feedback_down1\",\n+ \"value\": \"Operation unsuccessful\"\n+ },\n+ {\n+ \"name\": \"feedback_down2\",\n+ \"value\": \"Crash\"\n+ },\n+ {\n+ \"name\": \"feedback_down3\",\n+ \"value\": \"Operation lag\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up1\",\n+ \"value\": \"Clear usage method\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up2\",\n+ \"value\": \"Can be directly reused\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up3\",\n+ \"value\": \"The scene description is clear\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up4\",\n+ \"value\": \"Highly practical for various scenarios\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up5\",\n+ \"value\": \"The interface is aesthetically pleasing\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up7\",\n+ \"value\": \"Fast loading speed\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up6\",\n+ \"value\": \"The interface layout is reasonable\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up8\",\n+ \"value\": \"Convenient interaction\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up9\",\n+ \"value\": \"Well adapted to multiple devices\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down1\",\n+ \"value\": \"Download experience issues\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down2\",\n+ \"value\": \"The scene is unclear\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down3\",\n+ \"value\": \"Not very practical\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down4\",\n+ \"value\": \"Lacks originality\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down5\",\n+ \"value\": \"Version incompatible\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down6\",\n+ \"value\": \"Incompatible with multiple devices\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down7\",\n+ \"value\": \"Crash/Stutter\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down8\",\n+ \"value\": \"The interaction logic is confusing\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down9\",\n+ \"value\": \"The interface is not aesthetically pleasing.\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/common/src/main/resources/zh_CN/element/string.json b/common/src/main/resources/zh_CN/element/string.json\nindex d3d2e8c..dcc799d 100644\n--- a/common/src/main/resources/zh_CN/element/string.json\n+++ b/common/src/main/resources/zh_CN/element/string.json\n@@ -19,6 +19,110 @@\n {\n \"name\": \"network_setting\",\n \"value\": \"设置网络\"\n+ },\n+ {\n+ \"name\": \"feedback_up1\",\n+ \"value\": \"使用方式清晰\"\n+ },\n+ {\n+ \"name\": \"feedback_up2\",\n+ \"value\": \"可直接复用\"\n+ },\n+ {\n+ \"name\": \"feedback_up3\",\n+ \"value\": \"场景描述清晰\"\n+ },\n+ {\n+ \"name\": \"feedback_up4\",\n+ \"value\": \"场景有创新性\"\n+ },\n+ {\n+ \"name\": \"feedback_down1\",\n+ \"value\": \"操作不成功\"\n+ },\n+ {\n+ \"name\": \"feedback_down2\",\n+ \"value\": \"闪退\"\n+ },\n+ {\n+ \"name\": \"feedback_down3\",\n+ \"value\": \"操作卡顿\"\n+ },\n+ {\n+ \"name\": \"feedback_down4\",\n+ \"value\": \"内容不清晰\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up1\",\n+ \"value\": \"使用方式清晰\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up2\",\n+ \"value\": \"可直接复用\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up3\",\n+ \"value\": \"场景描述清晰\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up4\",\n+ \"value\": \"场景实用性强\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up5\",\n+ \"value\": \"界面美观\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up6\",\n+ \"value\": \"界面布局合理\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up7\",\n+ \"value\": \"加载速度快\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up8\",\n+ \"value\": \"交互操作便捷\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_up9\",\n+ \"value\": \"多设备适配好\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down1\",\n+ \"value\": \"下载体验问题\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down2\",\n+ \"value\": \"场景不清晰\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down3\",\n+ \"value\": \"实用性不强\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down4\",\n+ \"value\": \"没创新性\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down5\",\n+ \"value\": \"版本不兼容\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down6\",\n+ \"value\": \"多设备不适配\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down7\",\n+ \"value\": \"崩溃/卡顿\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down8\",\n+ \"value\": \"交互逻辑混乱\"\n+ },\n+ {\n+ \"name\": \"feedback_sample_down9\",\n+ \"value\": \"界面不美观\"\n }\n ]\n }\n\\ No newline at end of file\ndiff --git a/features/devpractices/src/main/ets/view/PracticeDetailView.ets b/features/devpractices/src/main/ets/view/PracticeDetailView.ets\nindex 159e78a..7eb3b4a 100644\n--- a/features/devpractices/src/main/ets/view/PracticeDetailView.ets\n+++ b/features/devpractices/src/main/ets/view/PracticeDetailView.ets\n@@ -15,7 +15,7 @@\n \n import { ConfigurationConstant } from '@kit.AbilityKit';\n import { HdsNavDestination, HdsNavDestinationAttribute } from '@kit.UIDesignKit';\n-import type { GlobalInfoModel } from '@ohos/common';\n+import { FeedbackSheet, GlobalInfoModel } from '@ohos/common';\n import {\n CommonConstants,\n LoadingStatus,\n@@ -50,6 +50,7 @@ export struct SampleDetailView {\n @State sampleDetailState: SampleDetailState = this.viewModel.getState();\n @State loadingStatus: LoadingStatus = LoadingStatus.IDLE;\n @Provide currentIndex: number = -1;\n+ @State bindFeedBack: boolean = false;\n private sampleCardId: number = -1;\n \n aboutToAppear(): void {\n@@ -136,6 +137,7 @@ export struct SampleDetailView {\n build() {\n if (VersionUtil.canUseHds()) {\n HdsNavDestination() {\n+ FeedbackSheet({ bindFeedBack: this.bindFeedBack })\n this.DetailContentBuilder();\n }\n .hideBackButton(false)\n@@ -149,6 +151,18 @@ export struct SampleDetailView {\n },\n content: {\n title: { mainTitle: $r('app.string.sample_title') },\n+ menu: {\n+ value: [{\n+ content: {\n+ label: 'menu1',\n+ icon: $r('sys.symbol.square_and_pencil'),\n+ isEnabled: true,\n+ action: () => {\n+ this.bindFeedBack = true;\n+ }\n+ }\n+ }]\n+ }\n }\n })\n .backgroundColor($r('sys.color.background_secondary'))\n@@ -165,6 +179,7 @@ export struct SampleDetailView {\n })\n } else {\n NavDestination() {\n+ FeedbackSheet({ bindFeedBack: this.bindFeedBack })\n this.DetailContentBuilder()\n }\n .onReady((cxt: NavDestinationContext) => this.handleOnReady(cxt))\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "hard",
"type": "issue_fix"
},
{
"instance_id": "ArkTs_Exp_031",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "df2e124c",
"problem_statement": "解决HMOS代码工坊卡片2*2点击闪退的问题",
"hints_text": "",
"patch": "diff --git a/common/src/main/ets/util/PullUpManager.ets b/common/src/main/ets/util/PullUpManager.ets\nindex c91636f..9a88c4e 100644\n--- a/common/src/main/ets/util/PullUpManager.ets\n+++ b/common/src/main/ets/util/PullUpManager.ets\n@@ -56,11 +56,15 @@ export class PullUpManager {\n */\n public static getFormCardType(want: Want): FormCardEnum | void {\n // The serviceCard and Lock screen card all has formID. Short cut entry doesn't has formID.\n- if (want.parameters && want.parameters?.['formID']) {\n- const cardWantParams: WantParams = JSON.parse(want.parameters['params'] as string);\n- const cardFrom: FormCardEnum = Reflect.get(cardWantParams, 'cardFrom') as FormCardEnum;\n- PullUpManager.formCardType = cardFrom;\n- return cardFrom;\n+ if (want.parameters && want.parameters?.['formID'] && want.parameters['params']) {\n+ try {\n+ const cardWantParams: WantParams = JSON.parse(want.parameters['params'] as string);\n+ const cardFrom: FormCardEnum = Reflect.get(cardWantParams, 'cardFrom') as FormCardEnum;\n+ PullUpManager.formCardType = cardFrom;\n+ return cardFrom;\n+ } catch (err) {\n+ Logger.error(TAG, `The getFormCardType occur error: ${err}}`)\n+ }\n }\n // Reset the PullUpManager.FormCardType.\n PullUpManager.formCardType = undefined;\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "medium",
"type": "issue_fix"
},
{
"instance_id": "ArkTs_Exp_032",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "f02c38a3",
"problem_statement": "下架首页组件中的相机选择器CameraPicker",
"hints_text": "",
"patch": "diff --git a/common/src/main/resources/rawfile/mockdata/component-page.json b/common/src/main/resources/rawfile/mockdata/component-page.json\nindex 5f7207f..6b55eea 100644\n--- a/common/src/main/resources/rawfile/mockdata/component-page.json\n+++ b/common/src/main/resources/rawfile/mockdata/component-page.json\n@@ -93,27 +93,6 @@\n }\n ]\n },\n- {\n- \"id\": 7,\n- \"cardTitle\": \"安全使用相机\",\n- \"cardSubTitle\": \"CameraPicker\",\n- \"cardType\": 1,\n- \"cardStyleType\": 3,\n- \"cardImage\": \"image/component/card/camerapicker.png\",\n- \"version\": 1000000,\n- \"cardContents\": [\n- {\n- \"id\": 28,\n- \"type\": 1,\n- \"cardId\": 7,\n- \"mediaType\": 1,\n- \"mediaUrl\": \"image/component/icon/camerapicker.png\",\n- \"title\": \"CameraPicker\",\n- \"subTitle\": \"相机选择器\",\n- \"tagIds\": []\n- }\n- ]\n- },\n {\n \"id\": 2,\n \"cardTitle\": \"按钮、图片、进度条等\",\ndiff --git a/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets b/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\nindex 2358159..ad2dbbd 100644\n--- a/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\n+++ b/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\n@@ -59,8 +59,6 @@ import { PhotoViewPickerCodeGenerator } from './photopicker/viewmodel/PhotoViewP\n import { CalendarPickerBuilder } from './picker/calendarPicker/component/CalendarPickerBuilder'\n import { CalendarPickerCodeGenerator } from './picker/calendarPicker/viewmodel/CalendarPickerCodeGenerator'\n import { CalendarPickerDescriptor } from './picker/calendarPicker/viewmodel/CalendarPickerDescriptor'\n-import { CameraPickerBuilder } from './picker/camerapicker/component/CameraPickerBuilder'\n-import { CameraPickerCodeGenerator } from './picker/camerapicker/viewmodel/CameraPickerCodeGenerator'\n import { DatePickerBuilder } from './picker/datepicker/component/DatePickerBuilder'\n import { DatePickerCodeGenerator } from './picker/datepicker/viewmodel/DatePickerCodeGenerator'\n import { DatePickerDescriptor } from './picker/datepicker/viewmodel/DatePickerDescriptor'\n@@ -119,7 +117,6 @@ import { ProgressAttributeFilter } from './progress/viewmodel/ProgressAttributeF\n import { ToggleAttributeFilter } from './toggleview/viewmodel/ToggleAttributeFilter'\n import { ColumnAttributeFilter } from './columnview/viewmodel/ColumnAttributeFilter'\n import { RowAttributeFilter } from './rowview/viewmodel/RowAttributeFilter'\n-import { CameraPickerDescriptor } from './picker/camerapicker/viewmodel/CameraPickerDescriptor'\n import { ImageAttributeFilter } from './Image/viewmodel/ImageAttributeFilter'\n \n export const componentDetailConfig: Record<string, ConfigInterface> = {\n@@ -283,11 +280,6 @@ export const componentDetailConfig: Record<string, ConfigInterface> = {\n descriptor: () => new AppLinkingDescriptor(),\n codeGenerate: new AppLinkingCodeGenerator(),\n },\n- 'CameraPicker': {\n- previewComponentBuilder: wrapBuilder(CameraPickerBuilder),\n- descriptor: () => new CameraPickerDescriptor(),\n- codeGenerate: new CameraPickerCodeGenerator(),\n- },\n 'PhotoViewPicker': {\n previewComponentBuilder: wrapBuilder(PhotoViewPickerBuilder),\n descriptor: () => new CommonDescriptor(),\ndiff --git a/products/phone/src/main/resources/resfile/articlecols/common/config/articleUrlConfig.json b/products/phone/src/main/resources/resfile/articlecols/common/config/articleUrlConfig.json\nindex 5c2e697..a897b0a 100644\n--- a/products/phone/src/main/resources/resfile/articlecols/common/config/articleUrlConfig.json\n+++ b/products/phone/src/main/resources/resfile/articlecols/common/config/articleUrlConfig.json\n@@ -41,7 +41,6 @@\n \"safety_14\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-picker#documentviewpicker\",\n \"safety_15\": \"https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/tutorials_NEXT-FilesManger\",\n \"safety_16\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/camera-overview\",\n- \"safety_17\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-camerapicker\",\n \"safety_18\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/vision-cardrecognition\",\n \"safety_19\": \"https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/tutorials_Next-VisionKit\",\n \"safety_20\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/vision-documentscanner\",\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "issue_fix"
},
{
"instance_id": "ArkTs_Exp_033",
"repo": "openharmony/sample_in_harmonyos",
"base_commit": "597014f1",
"problem_statement": "重新上架相机选择器CameraPicker组件到首页组件列表中,确保CameraPicker组件能够正常显示和使用。\n",
"hints_text": "",
"patch": "diff --git b/common/src/main/resources/rawfile/mockdata/component-page.json a/common/src/main/resources/rawfile/mockdata/component-page.json\nindex 6b55eea..5f7207f 100644\n--- b/common/src/main/resources/rawfile/mockdata/component-page.json\n+++ a/common/src/main/resources/rawfile/mockdata/component-page.json\n@@ -93,6 +93,27 @@\n }\n ]\n },\n+ {\n+ \"id\": 7,\n+ \"cardTitle\": \"安全使用相机\",\n+ \"cardSubTitle\": \"CameraPicker\",\n+ \"cardType\": 1,\n+ \"cardStyleType\": 3,\n+ \"cardImage\": \"image/component/card/camerapicker.png\",\n+ \"version\": 1000000,\n+ \"cardContents\": [\n+ {\n+ \"id\": 28,\n+ \"type\": 1,\n+ \"cardId\": 7,\n+ \"mediaType\": 1,\n+ \"mediaUrl\": \"image/component/icon/camerapicker.png\",\n+ \"title\": \"CameraPicker\",\n+ \"subTitle\": \"相机选择器\",\n+ \"tagIds\": []\n+ }\n+ ]\n+ },\n {\n \"id\": 2,\n \"cardTitle\": \"按钮、图片、进度条等\",\ndiff --git b/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets a/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\nindex ad2dbbd..2358159 100644\n--- b/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\n+++ a/features/componentlibrary/src/main/ets/componentdetailview/ComponentDetailConfig.ets\n@@ -59,6 +59,8 @@ import { PhotoViewPickerCodeGenerator } from './photopicker/viewmodel/PhotoViewP\n import { CalendarPickerBuilder } from './picker/calendarPicker/component/CalendarPickerBuilder'\n import { CalendarPickerCodeGenerator } from './picker/calendarPicker/viewmodel/CalendarPickerCodeGenerator'\n import { CalendarPickerDescriptor } from './picker/calendarPicker/viewmodel/CalendarPickerDescriptor'\n+import { CameraPickerBuilder } from './picker/camerapicker/component/CameraPickerBuilder'\n+import { CameraPickerCodeGenerator } from './picker/camerapicker/viewmodel/CameraPickerCodeGenerator'\n import { DatePickerBuilder } from './picker/datepicker/component/DatePickerBuilder'\n import { DatePickerCodeGenerator } from './picker/datepicker/viewmodel/DatePickerCodeGenerator'\n import { DatePickerDescriptor } from './picker/datepicker/viewmodel/DatePickerDescriptor'\n@@ -117,6 +119,7 @@ import { ProgressAttributeFilter } from './progress/viewmodel/ProgressAttributeF\n import { ToggleAttributeFilter } from './toggleview/viewmodel/ToggleAttributeFilter'\n import { ColumnAttributeFilter } from './columnview/viewmodel/ColumnAttributeFilter'\n import { RowAttributeFilter } from './rowview/viewmodel/RowAttributeFilter'\n+import { CameraPickerDescriptor } from './picker/camerapicker/viewmodel/CameraPickerDescriptor'\n import { ImageAttributeFilter } from './Image/viewmodel/ImageAttributeFilter'\n \n export const componentDetailConfig: Record<string, ConfigInterface> = {\n@@ -280,6 +283,11 @@ export const componentDetailConfig: Record<string, ConfigInterface> = {\n descriptor: () => new AppLinkingDescriptor(),\n codeGenerate: new AppLinkingCodeGenerator(),\n },\n+ 'CameraPicker': {\n+ previewComponentBuilder: wrapBuilder(CameraPickerBuilder),\n+ descriptor: () => new CameraPickerDescriptor(),\n+ codeGenerate: new CameraPickerCodeGenerator(),\n+ },\n 'PhotoViewPicker': {\n previewComponentBuilder: wrapBuilder(PhotoViewPickerBuilder),\n descriptor: () => new CommonDescriptor(),\ndiff --git b/products/phone/src/main/resources/resfile/articlecols/common/config/articleUrlConfig.json a/products/phone/src/main/resources/resfile/articlecols/common/config/articleUrlConfig.json\nindex a897b0a..5c2e697 100644\n--- b/products/phone/src/main/resources/resfile/articlecols/common/config/articleUrlConfig.json\n+++ a/products/phone/src/main/resources/resfile/articlecols/common/config/articleUrlConfig.json\n@@ -41,6 +41,7 @@\n \"safety_14\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-picker#documentviewpicker\",\n \"safety_15\": \"https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/tutorials_NEXT-FilesManger\",\n \"safety_16\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/camera-overview\",\n+ \"safety_17\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-camerapicker\",\n \"safety_18\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/vision-cardrecognition\",\n \"safety_19\": \"https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/tutorials_Next-VisionKit\",\n \"safety_20\": \"https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/vision-documentscanner\",\n",
"test_patch": "",
"version": "6.0.0(20)",
"created_at": "2024-05-20T10:00:00Z",
"FAIL_TO_PASS": [
"hypium_test_execution"
],
"PASS_TO_PASS": [],
"difficulty": "easy",
"type": "new_feature"
}
]