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