1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15import common from '@ohos.app.ability.common'; 16import I18n from '@ohos.i18n'; 17import image from '@ohos.multimedia.image'; 18import uniformDataStruct from '@ohos.data.uniformDataStruct'; 19import { BusinessError } from '@kit.BasicServicesKit'; 20import { display } from '@kit.ArkUI'; 21 22export enum FormType { 23 TYPE_BIG = 0, 24 TYPE_MID = 1, 25 TYPE_SMALL = 2 26} 27 28enum TextType { 29 TITLE = 0, 30 DESCRIPTION = 1, 31 APP_NAME = 2 32} 33 34const TAG: string = 'udmf.ContentFormCard'; 35const defaultIcon: string = 36 '82,73,70,70,60,3,0,0,87,69,66,80,86,80,56,32,48,3,0,0,144,67,0,157,1,42,36,2,76,1,62,145,72,161,76,37,164,163,34,3' + 37 '4,151,40,24,176,18,9,105,110,225,117,81,27,243,141,167,87,231,251,1,151,228,76,129,74,56,124,143,240,134,221,17,24' + 38 '5,145,49,195,251,155,103,15,145,254,16,219,162,62,178,38,56,127,115,108,225,242,63,194,27,116,71,214,68,199,15,238' + 39 ',109,156,62,71,248,67,110,136,250,200,152,225,253,205,179,135,200,255,8,109,209,31,89,19,28,63,185,182,112,249,31,' + 40 '225,13,186,35,235,34,99,135,247,54,206,31,35,252,33,183,68,125,100,76,112,254,230,217,195,228,75,0,41,63,219,242,2' + 41 '38,77,44,240,251,18,157,13,186,35,235,34,99,135,247,54,206,31,35,249,8,172,169,162,121,152,235,226,174,0,65,245,14' + 42 '5,49,195,251,155,103,15,145,254,16,219,50,4,52,148,102,170,225,73,64,87,161,183,68,125,100,76,112,254,230,217,195,' + 43 '228,71,209,214,155,210,69,175,155,95,117,236,130,111,176,161,115,26,13,253,205,179,135,200,255,8,109,209,31,89,19,' + 44 '28,63,185,182,112,248,134,3,147,196,80,183,60,143,240,134,221,17,245,145,49,195,251,155,103,9,153,121,194,183,243,' + 45 '118,43,147,107,248,164,83,185,180,54,232,143,172,137,142,31,220,219,56,124,136,157,203,110,159,181,177,87,164,132,' + 46 '51,246,217,120,189,13,186,35,235,34,99,134,241,245,180,72,132,116,112,254,7,167,195,150,227,244,98,234,67,237,155,' + 47 '35,135,102,236,204,223,23,161,183,68,125,100,75,176,70,248,207,116,46,59,232,218,137,15,41,225,38,20,162,105,88,3,' + 48 '59,221,52,249,17,46,76,68,130,195,148,187,103,15,145,253,241,76,10,132,82,146,126,208,179,241,65,64,84,151,15,193,' + 49 '27,58,174,246,254,217,195,225,201,8,103,237,178,241,122,27,116,71,210,161,106,19,234,133,230,77,60,101,201,227,55,' + 50 '59,2,148,71,237,122,200,152,222,202,193,86,94,164,111,28,63,185,180,88,205,133,69,41,39,237,156,62,237,252,33,183,' + 51 '68,126,68,34,111,88,1,159,60,108,76,112,252,104,245,218,227,1,255,172,137,142,31,220,219,56,124,143,239,99,182,153' + 52 ',157,89,206,237,156,41,135,174,215,24,15,76,90,90,193,245,145,49,195,251,155,103,15,145,18,140,226,36,22,28,165,21' + 53 '8,7,174,215,23,217,167,25,36,48,125,100,76,112,254,230,217,195,196,106,61,255,30,253,149,0,0,254,254,226,128,0,0,0' + 54 ',0,0,8,43,156,5,139,91,64,214,164,5,157,168,214,71,99,143,63,110,129,210,71,53,1,30,120,20,41,161,99,5,167,202,76,' + 55 '251,103,189,240,128,146,208,198,255,248,206,215,46,193,53,91,227,66,219,241,255,4,235,164,113,76,186,21,195,174,10' + 56 ',72,252,102,101,0,19,200,26,224,13,190,145,249,137,208,169,128,196,203,52,114,184,23,26,103,126,29,119,157,143,214' + 57 ',115,91,208,138,148,47,18,132,3,189,65,160,138,162,129,225,223,121,199,68,111,66,131,240,170,9,87,178,109,244,143,' + 58 '204,78,245,205,43,87,181,148,112,162,163,53,27,128,197,247,165,165,55,37,6,212,240,48,76,139,191,173,182,51,61,7,1' + 59 '38,70,81,93,158,178,96,58,63,135,99,61,33,123,114,106,17,205,205,245,73,209,248,208,230,67,84,83,67,62,174,199,125' + 60 ',7,42,68,205,119,254,54,95,35,146,246,87,229,105,194,49,134,23,113,205,13,105,146,10,231,32,0,26,210,69,47,127,104' + 61 ',73,141,205,245,214,23,231,110,132,188,27,13,88,8,43,145,225,60,68,0,42,15,95,85,238,25,204,75,166,163,127,0,0'; 62const MAX_CARD_SCALE: number = 1.2; 63const MIN_CARD_SCALE: number = 0.8; 64const SMALL_MIN_CARD_SCALE: number = 0.4; 65const DEFAULT_BIG_CARD_SIZE: number = 200; 66const DEFAULT_MID_CARD_WIDTH: number = 200; 67const DEFAULT_MID_CARD_HEIGHT: number = 100; 68const DEFAULT_SMALL_CARD_WIDTH: number = 137; 69const DEFAULT_SMALL_CARD_HEIGHT: number = 83; 70const DEFAULT_EMPTY_TITLE_WIDTH: number = 70; 71const DEFAULT_EMPTY_APPNAME_WIDTH: number = 40; 72const SMALL_EMPTY_TITLE_WIDTH: number = 50; 73const SMALL_EMPTY_APPNAME_WIDTH: number = 30; 74const DEFAULT_EMPTY_TEXT_RADIUS: number = 2; 75const DEFAULT_EMPTY_DESCRIPTION_WIDTH: string = '100%'; 76const CARD_BACKGROUND: string = '#E6FFFFFF'; 77const TRANSLATE_BACKGROUND: string = '#00000000'; 78const APP_NAME_COLOR: string = '#99182431'; 79const DEFAULT_THUMB_BACKGROUND: string = '#CCCCCC'; 80const DEFAULT_FONT_BACKGROUND: string = '#55CCCCCC'; 81const TITLE_FONT_COLOR: string = '#ff182431'; 82const DESCRIPTION_FONT_COLOR: string = '#99182431'; 83const DEFAULT_MID_IMAGE_HEIGHT: number = 72; // 4x2卡片,图片默认高度 84const DEFAULT_SMALL_IMAGE_HEIGHT: number = 59; // 2x1卡片,图片默认高度 85const DEFAULT_DENSITY: number = 3.25; 86 87interface CardStyle { 88 thumbWidth: number, 89 thumbHeight: number, 90 thumbMarginLeft?: number, 91 titleFontSize: number, 92 titleFontLineHeight: number, 93 titleFontMarginTop: number, 94 descriptionFontSize: number, 95 descriptionLineHeight: number, 96 maxDescriptionFontSize?: number, 97 maxDescriptionLineHeight?: number, 98 descriptionMarginTop: number, 99 dividerMarginTop: number, 100 appNameFontSize: number, 101 appIconSize: number, 102 cardRadius: number, 103 appNameMarginLeft: number, 104 appNameLineHeight: number, 105 cardPadding: number, 106 cardPaddingBottom: number, 107 cardPaddingTop: number 108} 109 110const BIG_CARD_STYLE: CardStyle = { 111 thumbWidth: 200, 112 thumbHeight: 120, 113 titleFontSize: 14, 114 titleFontLineHeight: 16, 115 titleFontMarginTop: 10, 116 descriptionFontSize: 14, 117 descriptionLineHeight: 16, 118 descriptionMarginTop: 4, 119 dividerMarginTop: 5, 120 appNameFontSize: 10, 121 appNameLineHeight: 14, 122 appIconSize: 12, 123 cardRadius: 16, 124 appNameMarginLeft: 6.5, 125 cardPadding: 12, 126 cardPaddingBottom: 10, 127 cardPaddingTop: 5 128} 129 130const MID_CARD_STYLE: CardStyle = { 131 thumbWidth: 36, 132 thumbHeight: 48, 133 thumbMarginLeft: 14, 134 descriptionFontSize: 10, 135 descriptionLineHeight: 12, 136 maxDescriptionFontSize: 14, 137 maxDescriptionLineHeight: 16, 138 descriptionMarginTop: 10, 139 titleFontSize: 14, 140 titleFontLineHeight: 16, 141 titleFontMarginTop: 14, 142 dividerMarginTop: 5, 143 appNameFontSize: 10, 144 appNameLineHeight: 14, 145 appIconSize: 12, 146 cardRadius: 16, 147 appNameMarginLeft: 6.5, 148 cardPadding: 12, 149 cardPaddingBottom: 10, 150 cardPaddingTop: 5 151} 152 153const SMALL_CARD_STYLE: CardStyle = { 154 thumbWidth: 24, 155 thumbHeight: 24, 156 thumbMarginLeft: 8, 157 titleFontSize: 12, 158 titleFontLineHeight: 14, 159 titleFontMarginTop: 9, 160 descriptionFontSize: 10, 161 descriptionLineHeight: 12, 162 maxDescriptionFontSize: 12, 163 maxDescriptionLineHeight: 14, 164 descriptionMarginTop: 4, 165 dividerMarginTop: 5, 166 appNameFontSize: 10, 167 appIconSize: 12, 168 cardRadius: 12, 169 appNameMarginLeft: 4, 170 appNameLineHeight: 12, 171 cardPadding: 8, 172 cardPaddingBottom: 8, 173 cardPaddingTop: 4 174} 175 176@Preview 177@Component 178export struct ContentFormCard { 179 @Prop @Watch('formTypeChange') formType: FormType = FormType.TYPE_MID; 180 private contentFormData: uniformDataStruct.ContentForm | undefined = undefined; 181 private formStyle: CardStyle = MID_CARD_STYLE; 182 private controller: TextController = new TextController(); 183 @State cardScale: number = 1; 184 @Prop @Watch('formSizeChange') formWidth: number = 0; 185 @Prop @Watch('formSizeChange') formHeight: number = 0; 186 @State cardWidth: number = 0; 187 @State cardHeight: number = 0; 188 @State defaultThumbImage: image.PixelMap | undefined = undefined; 189 @State thumbImage: image.PixelMap | undefined = undefined; 190 @State appImage: image.PixelMap | undefined = undefined; 191 @State lineCount: number = 1; 192 @State isMirrorLanguageType: boolean = false; 193 private handleOnClick: () => void = () => { 194 }; 195 196 aboutToAppear(): void { 197 this.initSystemLanguage(); 198 this.initCardStyle(); 199 this.createPixelMap(); 200 } 201 202 aboutToDisappear(): void { 203 this.contentFormData = undefined; 204 this.thumbImage = undefined; 205 this.appImage = undefined; 206 } 207 208 formTypeChange(): void { 209 switch (this.formType) { 210 case FormType.TYPE_BIG: 211 this.formWidth = DEFAULT_BIG_CARD_SIZE; 212 break; 213 case FormType.TYPE_MID: 214 this.formWidth = DEFAULT_MID_CARD_WIDTH; 215 break; 216 default: 217 this.formWidth = DEFAULT_SMALL_CARD_WIDTH; 218 break; 219 } 220 this.initCardStyle(); 221 } 222 223 formSizeChange(): void { 224 this.initCardStyle(); 225 } 226 227 initCardScale(widthScale: number, defaultWidth: number, defaultHeight: number): void { 228 let minScale = this.formType === FormType.TYPE_SMALL ? SMALL_MIN_CARD_SCALE : MIN_CARD_SCALE; 229 if (widthScale > MAX_CARD_SCALE) { 230 this.cardScale = MAX_CARD_SCALE; 231 } else if (widthScale < minScale) { 232 this.cardScale = minScale; 233 } else { 234 this.cardScale = widthScale; 235 } 236 this.cardWidth = defaultWidth * this.cardScale; 237 this.cardHeight = 238 (this.contentFormData?.title === '' && this.formHeight > 0) ? this.formHeight : defaultHeight * this.cardScale; 239 console.info(`${TAG}, widthScale:${this.cardScale}, cardScale: ${this.cardScale}, ` + 240 `cardWidth: ${this.cardWidth}, cardHeight: ${this.cardHeight}`); 241 } 242 243 initCardStyle(): void { 244 let widthScale = 1; 245 this.lineCount = 1; 246 switch (this.formType) { 247 case FormType.TYPE_BIG: 248 this.formStyle = BIG_CARD_STYLE; 249 widthScale = this.formWidth ? this.formWidth / DEFAULT_BIG_CARD_SIZE : 1; 250 this.initCardScale(widthScale, DEFAULT_BIG_CARD_SIZE, DEFAULT_BIG_CARD_SIZE); 251 break; 252 case FormType.TYPE_MID: 253 this.formStyle = MID_CARD_STYLE; 254 widthScale = this.formWidth ? this.formWidth / DEFAULT_MID_CARD_WIDTH : 1; 255 this.initCardScale(widthScale, DEFAULT_MID_CARD_WIDTH, DEFAULT_MID_CARD_HEIGHT); 256 break; 257 default: 258 this.formStyle = SMALL_CARD_STYLE; 259 widthScale = this.formWidth ? this.formWidth / DEFAULT_SMALL_CARD_WIDTH : 1; 260 this.initCardScale(widthScale, DEFAULT_SMALL_CARD_WIDTH, DEFAULT_SMALL_CARD_HEIGHT); 261 break; 262 } 263 } 264 265 @Styles 266 thumbStyle() { 267 .width('100%') 268 .padding({ 269 left: this.formStyle.cardPadding * this.cardScale, 270 right: this.formStyle.cardPadding * this.cardScale 271 }) 272 .layoutWeight(1) 273 } 274 275 @Builder 276 ThumbImage() { 277 Column() { 278 if (this.formHeight > 0) { 279 Image(this.thumbImage ? this.thumbImage : this.defaultThumbImage) 280 .objectFit(ImageFit.Contain) 281 .width('100%') 282 .layoutWeight(1) 283 .draggable(false) 284 .id('cardThumbImage') 285 } else { 286 Image(this.thumbImage ? this.thumbImage : this.defaultThumbImage) 287 .objectFit(ImageFit.Contain) 288 .width('100%') 289 .aspectRatio(this.getAspectRatio()) 290 .draggable(false) 291 .id('cardThumbImage') 292 } 293 } 294 .size({ width: '100%' }) 295 .layoutWeight(this.formHeight > 0 ? 1 : 0) 296 .backgroundColor(this.thumbImage ? CARD_BACKGROUND : DEFAULT_THUMB_BACKGROUND) 297 } 298 299 @Builder 300 CardDivider() { 301 Divider() 302 .height(1)//.color(CARD_DIVIDER_COLOR) 303 .opacity(0.5) 304 .padding({ 305 left: this.formStyle.cardPadding * this.cardScale, 306 right: this.formStyle.cardPadding * this.cardScale 307 }) 308 } 309 310 @Builder 311 AppView() { 312 Row({ space: this.formStyle.appNameMarginLeft * this.cardScale }) { 313 Image(this.appImage) 314 .width(this.formStyle.appIconSize * this.cardScale) 315 .height(this.formStyle.appIconSize * this.cardScale) 316 .objectFit(ImageFit.Fill) 317 .alt($r('sys.media.ohos_app_icon')) 318 .borderRadius($r('sys.float.corner_radius_level1')) 319 .draggable(false) 320 .id('cardAppIcon') 321 Text(this.contentFormData?.appName ? this.contentFormData?.appName : ' ') 322 .fontSize(this.formStyle.appNameFontSize * this.cardScale) 323 .fontColor(APP_NAME_COLOR) 324 .maxLines(1) 325 .lineHeight(this.formStyle.appNameLineHeight * this.cardScale) 326 .textOverflow({ overflow: TextOverflow.Ellipsis }) 327 .constraintSize({ minWidth: this.getTextSize(TextType.APP_NAME, this.contentFormData?.appName) }) 328 .backgroundColor(this.getTextBackground(this.contentFormData?.appName)) 329 .fontWeight(FontWeight.Regular) 330 .borderRadius(this.contentFormData?.title === '' ? 0 : DEFAULT_EMPTY_TEXT_RADIUS) 331 .direction(this.isMirrorLanguageType ? Direction.Rtl : Direction.Ltr) 332 .maxFontScale(1) 333 .layoutWeight(1) 334 .id('cardAppName') 335 336 } 337 .padding({ 338 left: this.formStyle.cardPadding * this.cardScale, 339 right: this.formStyle.cardPadding * this.cardScale, 340 top: this.formStyle.cardPaddingTop * this.cardScale, 341 bottom: this.formStyle.cardPaddingBottom * this.cardScale, 342 }) 343 } 344 345 @Builder 346 TitleText() { 347 Text(this.contentFormData?.title) 348 .fontSize(this.formStyle.titleFontSize * this.cardScale) 349 .fontColor(TITLE_FONT_COLOR) 350 .fontWeight(FontWeight.Bold) 351 .maxLines(1) 352 .textOverflow({ overflow: TextOverflow.Ellipsis }) 353 .height(this.formStyle.titleFontLineHeight * this.cardScale) 354 .margin({ top: this.formStyle.titleFontMarginTop * this.cardScale }) 355 .constraintSize({ minWidth: this.getTextSize(TextType.TITLE, this.contentFormData?.title) }) 356 .backgroundColor(this.getTextBackground(this.contentFormData?.title)) 357 .borderRadius(this.contentFormData?.title === '' ? 0 : DEFAULT_EMPTY_TEXT_RADIUS) 358 .direction(this.isMirrorLanguageType ? Direction.Rtl : Direction.Ltr) 359 .maxFontScale(1) 360 .id('cardTitleText') 361 } 362 363 @Builder 364 Card4x4() { 365 Column() { 366 Image(this.thumbImage ? this.thumbImage : this.defaultThumbImage) 367 .objectFit(ImageFit.Cover) 368 .width('100%') 369 .height(this.formStyle.thumbHeight * this.cardScale) 370 .backgroundColor(this.thumbImage ? CARD_BACKGROUND : DEFAULT_THUMB_BACKGROUND) 371 .draggable(false) 372 .id('cardThumbImage') 373 Column() { 374 this.TitleText() 375 Text(this.contentFormData?.description) 376 .fontSize(this.formStyle.descriptionFontSize * this.cardScale) 377 .fontColor(DESCRIPTION_FONT_COLOR) 378 .fontWeight(FontWeight.Regular) 379 .maxLines(1) 380 .textOverflow({ overflow: TextOverflow.Ellipsis }) 381 .constraintSize({ minWidth: this.getTextSize(TextType.DESCRIPTION, this.contentFormData?.description) }) 382 .height(this.formStyle.descriptionLineHeight * this.cardScale) 383 .margin({ top: this.formStyle.descriptionMarginTop * this.cardScale }) 384 .backgroundColor(this.getTextBackground(this.contentFormData?.description)) 385 .fontWeight(FontWeight.Regular) 386 .borderRadius(this.contentFormData?.description ? 0 : DEFAULT_EMPTY_TEXT_RADIUS) 387 .direction(this.isMirrorLanguageType ? Direction.Rtl : Direction.Ltr) 388 .maxFontScale(1) 389 .id('cardDescription') 390 } 391 .alignItems(HorizontalAlign.Start) 392 .width('100%') 393 .padding({ 394 left: this.formStyle.cardPadding * this.cardScale, 395 right: this.formStyle.cardPadding * this.cardScale 396 }) 397 .margin({ bottom: this.formStyle.dividerMarginTop * this.cardScale }) 398 .justifyContent(FlexAlign.Center) 399 400 this.CardDivider() 401 this.AppView() 402 } 403 .size({ width: '100%', height: this.cardHeight }) 404 } 405 406 @Builder 407 DescriptionView() { 408 Text(this.contentFormData?.description ? this.contentFormData?.description : ' ', { controller: this.controller }) 409 .fontColor(DESCRIPTION_FONT_COLOR) 410 .fontWeight(FontWeight.Regular) 411 .maxLines(2) 412 .fontWeight(FontWeight.Regular) 413 .textOverflow({ overflow: TextOverflow.Ellipsis }) 414 .lineHeight((this.lineCount === 1 ? 415 (this.formStyle.maxDescriptionLineHeight ? this.formStyle.maxDescriptionLineHeight : 416 this.formStyle.descriptionLineHeight) : this.formStyle.descriptionLineHeight) * this.cardScale) 417 .fontSize(this.getDescriptionFontSize() * this.cardScale) 418 .constraintSize({ minWidth: this.getTextSize(TextType.DESCRIPTION, this.contentFormData?.description) }) 419 .backgroundColor(this.getTextBackground(this.contentFormData?.description)) 420 .borderRadius(this.contentFormData?.description ? 0 : DEFAULT_EMPTY_TEXT_RADIUS) 421 .onAreaChange(() => { 422 let layoutManager: LayoutManager = this.controller.getLayoutManager(); 423 this.lineCount = layoutManager.getLineCount(); 424 if (layoutManager.getLineCount() === 2) { 425 this.lineCount = 2; 426 } 427 }) 428 .direction(this.isMirrorLanguageType ? Direction.Rtl : Direction.Ltr) 429 .maxFontScale(1) 430 .id('cardDescription') 431 } 432 433 @Builder 434 Card4x2() { 435 Column() { 436 if (this.contentFormData?.title === '') { // show the card only thumbData 437 this.ThumbImage() 438 } else { // show the card has thumbData and title,description 439 Row() { 440 Column({ space: this.formStyle.descriptionMarginTop * this.cardScale }) { 441 this.TitleText() 442 this.DescriptionView() 443 } 444 .layoutWeight(1) 445 .alignItems(HorizontalAlign.Start) 446 447 if (this.thumbImage) { 448 Image(this.thumbImage) 449 .width(this.formStyle.thumbWidth * this.cardScale) 450 .height(this.formStyle.thumbHeight * this.cardScale) 451 .objectFit(this.thumbImage ? ImageFit.Cover : ImageFit.Contain) 452 .borderRadius(4) 453 .draggable(false) 454 .margin({ 455 right: this.isMirrorLanguageType ? (this.formStyle.thumbMarginLeft as number * this.cardScale) : 0, 456 left: this.isMirrorLanguageType ? 0 : (this.formStyle.thumbMarginLeft as number * this.cardScale), 457 top: this.formStyle.titleFontMarginTop * this.cardScale 458 }) 459 .id('cardThumbImage') 460 } 461 } 462 .thumbStyle() 463 .margin({ bottom: this.formStyle.dividerMarginTop * this.cardScale }) 464 .alignItems(VerticalAlign.Top) 465 } 466 467 this.CardDivider(); 468 this.AppView(); 469 } 470 .size({ width: '100%' }) 471 .constraintSize(this.getThumbViewConstraintSize()) 472 } 473 474 @Builder 475 Card2x1() { 476 Column() { 477 if (this.contentFormData?.title === '') { // show the card only thumbData 478 this.ThumbImage() 479 } else { 480 Column() { 481 this.TitleText() 482 Row() { 483 Column() { 484 this.DescriptionView() 485 } 486 .layoutWeight(1) 487 .alignItems(HorizontalAlign.Start) 488 489 if (this.thumbImage) { 490 Image(this.thumbImage) 491 .objectFit(ImageFit.Cover) 492 .borderRadius($r('sys.float.corner_radius_level2')) 493 .width(this.formStyle.thumbWidth * this.cardScale) 494 .height(this.formStyle.thumbHeight * this.cardScale) 495 .draggable(false) 496 .margin({ 497 left: this.isMirrorLanguageType ? 0 : (this.formStyle.thumbMarginLeft as number * this.cardScale), 498 right: this.isMirrorLanguageType ? (this.formStyle.thumbMarginLeft as number * this.cardScale) : 0 499 }) 500 .id('cardThumbImage') 501 } 502 } 503 .margin({ top: this.formStyle.descriptionMarginTop * this.cardScale }) 504 .layoutWeight(1) 505 } 506 .thumbStyle() 507 .alignItems(HorizontalAlign.Start) 508 .margin({ bottom: this.formStyle.dividerMarginTop * this.cardScale }) 509 } 510 this.CardDivider() 511 this.AppView() 512 } 513 .size({ width: '100%' }) 514 .constraintSize(this.getThumbViewConstraintSize()) 515 } 516 517 build() { 518 Column() { 519 if (this.initSystemLanguage() && this.formType === FormType.TYPE_BIG) { 520 this.Card4x4(); 521 } else if (this.formType === FormType.TYPE_MID) { 522 this.Card4x2(); 523 } else { 524 this.Card2x1(); 525 } 526 } 527 .borderRadius(this.formStyle.cardRadius * this.cardScale) 528 .clip(true) 529 .backgroundColor(CARD_BACKGROUND) 530 .backgroundBlurStyle(BlurStyle.COMPONENT_ULTRA_THICK, 531 { colorMode: ThemeColorMode.LIGHT, adaptiveColor: AdaptiveColor.DEFAULT, scale: 1.0 }) 532 .shadow(ShadowStyle.OUTER_DEFAULT_SM) 533 .width(this.cardWidth) 534 .onClick(() => { 535 this.handleOnClick(); 536 if (!this.contentFormData?.linkUri) { 537 console.warn(`${TAG}, linkUri is null`); 538 return; 539 } 540 try { 541 let context = getContext(this) as common.UIAbilityContext; 542 context.openLink(this.contentFormData?.linkUri, { appLinkingOnly: false, parameters: {} }); 543 } catch (err) { 544 let error = err as BusinessError; 545 console.error(`${TAG}, Failed to openLink, code is ${error.code}, message is ${error.message}`); 546 } 547 }) 548 } 549 550 initSystemLanguage(): boolean { 551 try { 552 this.isMirrorLanguageType = I18n.isRTL(I18n.System.getSystemLanguage()); 553 } catch (err) { 554 let error = err as BusinessError; 555 console.error(`${TAG}, Failed to init system language, code is ${error.code}, message is ${error.message}`); 556 } 557 return true; 558 } 559 560 async getPixelMap(uint: Uint8Array, callback: Function): Promise<void> { 561 let imageResource: image.ImageSource | undefined = undefined; 562 try { 563 imageResource = image.createImageSource(uint.buffer); 564 let pixelMapData = await imageResource?.createPixelMap(); 565 callback(pixelMapData); 566 imageResource.release(); 567 } catch (err) { 568 let error = err as BusinessError; 569 console.error(`${TAG}, Failed to create pixelMap, code is ${error.code}, message is ${error.message}`); 570 } 571 } 572 573 transStringToUint8Array(srcData: string): Uint8Array { 574 const arr: string[] = srcData.split(','); 575 const uint8Array = new Uint8Array(arr.length); 576 arr.forEach((value, index) => { 577 uint8Array[index] = parseInt(value); 578 }) 579 return uint8Array; 580 } 581 582 createPixelMap(): void { 583 let defaultThumbData = this.transStringToUint8Array(defaultIcon); 584 this.getPixelMap(defaultThumbData, (pixelMap: image.PixelMap) => { 585 this.defaultThumbImage = pixelMap; 586 }) 587 588 if (this.contentFormData && this.contentFormData?.thumbData) { 589 if (!(this.contentFormData?.thumbData instanceof Uint8Array)) { 590 console.error(`${TAG}, thumbData is not Uint8Array`); 591 return; 592 } 593 this.getPixelMap(this.contentFormData?.thumbData, (pixelMap: image.PixelMap) => { 594 this.thumbImage = pixelMap; 595 }) 596 } 597 if (this.contentFormData && this.contentFormData?.appIcon) { 598 if (!(this.contentFormData?.appIcon instanceof Uint8Array)) { 599 console.error(`${TAG}, appIcon is not Uint8Array`); 600 return; 601 } 602 this.getPixelMap(this.contentFormData?.appIcon, (pixelMap: image.PixelMap) => { 603 this.appImage = pixelMap; 604 }) 605 } 606 } 607 608 getAspectRatio(): number { 609 let iamgeSize = this.thumbImage?.getImageInfoSync().size; 610 let defaultCardWidth = this.formType === FormType.TYPE_MID ? DEFAULT_MID_CARD_WIDTH : DEFAULT_SMALL_CARD_WIDTH; 611 let defaultImageHeight = 612 this.formType === FormType.TYPE_MID ? DEFAULT_MID_IMAGE_HEIGHT : DEFAULT_SMALL_IMAGE_HEIGHT; 613 if (iamgeSize && this.thumbImage) { 614 if ((iamgeSize.width / iamgeSize.height) > (defaultCardWidth / (defaultImageHeight * MIN_CARD_SCALE))) { 615 return defaultCardWidth / (defaultImageHeight * MIN_CARD_SCALE); 616 } 617 if ((iamgeSize.width / iamgeSize.height) < (defaultCardWidth / (defaultImageHeight * MAX_CARD_SCALE))) { 618 return defaultCardWidth / (defaultImageHeight * MAX_CARD_SCALE); 619 } 620 return iamgeSize.width / iamgeSize.height; 621 } 622 return defaultCardWidth / defaultImageHeight; 623 } 624 625 getTextBackground(text: string | undefined): string { 626 if (text && text.length > 0) { 627 return TRANSLATE_BACKGROUND; 628 } 629 return DEFAULT_FONT_BACKGROUND; 630 } 631 632 getTextSize(textType: TextType, text: string | undefined): number | string { 633 if (textType === TextType.TITLE) { 634 if (text === '' || text === undefined || text === null) { 635 if (this.formType === FormType.TYPE_SMALL) { 636 return SMALL_EMPTY_TITLE_WIDTH; 637 } 638 return DEFAULT_EMPTY_TITLE_WIDTH; 639 } 640 return DEFAULT_EMPTY_DESCRIPTION_WIDTH; 641 } 642 if (textType === TextType.APP_NAME) { 643 if (text === '' || text === undefined || text === null) { 644 if (this.formType === FormType.TYPE_SMALL) { 645 return SMALL_EMPTY_APPNAME_WIDTH; 646 } 647 return DEFAULT_EMPTY_APPNAME_WIDTH; 648 } 649 return DEFAULT_EMPTY_DESCRIPTION_WIDTH; 650 } 651 return '100%' 652 } 653 654 getThumbViewConstraintSize(): ConstraintSizeOptions { 655 if (this.contentFormData?.title !== '') { 656 return { maxHeight: this.cardHeight, minHeight: this.cardHeight }; 657 } else { 658 if (this.formHeight > 0) { 659 return { 660 maxHeight: this.formHeight, 661 minHeight: this.formHeight 662 }; 663 } 664 return { 665 maxHeight: this.cardHeight * MAX_CARD_SCALE, 666 minHeight: this.cardHeight * MIN_CARD_SCALE 667 }; 668 } 669 } 670 671 getDescriptionFontSize(): number { 672 return this.lineCount === 1 ? (this.formStyle.maxDescriptionFontSize ? this.formStyle.maxDescriptionFontSize : 673 this.formStyle.descriptionFontSize) : this.formStyle.descriptionFontSize; 674 } 675}