1/* 2 * Copyright (c) 2023-2024 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 */ 15 16import display from '@ohos.display'; 17import mediaquery from '@ohos.mediaquery'; 18import { Theme } from '@ohos.arkui.theme'; 19import { LengthMetrics } from '@ohos.arkui.node' 20import componentUtils from '@ohos.arkui.componentUtils'; 21import { SymbolGlyphModifier, Configuration } from '@kit.ArkUI'; 22import { systemDateTime } from '@kit.BasicServicesKit'; 23 24const RESOURCE_TYPE_STRING = 10003; 25const RESOURCE_TYPE_FLOAT = 10002; 26const RESOURCE_TYPE_INTEGER = 10007; 27 28interface IconTheme { 29 size: SizeOptions; 30 margin: LocalizedMargin; 31 fillColor: ResourceColor; 32 borderRadius: Length; 33} 34 35interface TitleTheme { 36 margin: LocalizedMargin; 37 minFontSize: number; 38 fontWeight: FontWeight; 39 fontSize: Resource; 40 fontColor: ResourceColor; 41} 42 43interface ButtonTheme { 44 margin: LocalizedMargin; 45 padding: LocalizedPadding; 46 fontSize: Resource; 47 fontColor: ResourceColor; 48 textMargin: LocalizedMargin; 49 minFontSize: number; 50 fontWeight: FontWeight; 51 hoverColor: ResourceColor; 52 backgroundColor: ResourceColor; 53} 54 55interface MessageTheme { 56 fontSize: Resource; 57 fontColor: ResourceColor; 58 fontWeight: FontWeight; 59 plainFontColor: ResourceColor; 60} 61 62interface CloseButtonTheme { 63 size: SizeOptions; 64 margin: LocalizedMargin; 65 padding: LocalizedPadding; 66 fillColor: ResourceColor; 67 hoverColor: ResourceColor; 68 backgroundColor: ResourceColor; 69 symbolStyle: SymbolGlyphModifier; 70 symbolSize: string; 71 accessibilityMessage: Resource; 72} 73 74interface WindowsTheme { 75 padding: LocalizedPadding; 76} 77 78interface PopupTheme { 79 icon: IconTheme; 80 title: TitleTheme; 81 button: ButtonTheme; 82 message: MessageTheme; 83 windows: WindowsTheme; 84 closeButton: CloseButtonTheme; 85} 86 87export const defaultTheme: PopupTheme = { 88 icon: { 89 size: { width: 32, height: 32 }, 90 margin: { 91 top: LengthMetrics.vp(12), 92 bottom: LengthMetrics.vp(12), 93 start: LengthMetrics.vp(12), 94 end: LengthMetrics.vp(12) 95 }, 96 fillColor: '', 97 borderRadius: $r('sys.float.ohos_id_corner_radius_default_s') 98 99 }, 100 title: { 101 margin: { bottom: LengthMetrics.vp(2) }, 102 minFontSize: 12, 103 fontWeight: FontWeight.Medium, 104 fontSize: $r('sys.float.ohos_id_text_size_sub_title2'), 105 fontColor: $r('sys.color.font_primary') 106 }, 107 button: { 108 margin: { 109 top: LengthMetrics.vp(16), 110 bottom: LengthMetrics.vp(16), 111 start: LengthMetrics.vp(16), 112 end: LengthMetrics.vp(16) 113 }, 114 padding: { 115 top: LengthMetrics.vp(4), 116 bottom: LengthMetrics.vp(4), 117 start: LengthMetrics.vp(4), 118 end: LengthMetrics.vp(4) 119 }, 120 fontSize: $r('sys.float.ohos_id_text_size_button2'), 121 fontColor: $r('sys.color.font_emphasize'), 122 textMargin: { 123 top: LengthMetrics.vp(8), 124 bottom: LengthMetrics.vp(8), 125 start: LengthMetrics.vp(8), 126 end: LengthMetrics.vp(8) 127 }, 128 minFontSize: 9, 129 fontWeight: FontWeight.Medium, 130 hoverColor: $r('sys.color.ohos_id_color_hover'), 131 backgroundColor: $r('sys.color.ohos_id_color_background_transparent') 132 }, 133 message: { 134 fontSize: $r('sys.float.ohos_id_text_size_body2'), 135 fontColor: $r('sys.color.font_secondary'), 136 fontWeight: FontWeight.Regular, 137 plainFontColor: $r('sys.color.font_primary') 138 }, 139 windows: { 140 padding: { 141 top: LengthMetrics.vp(12), 142 bottom: LengthMetrics.vp(12), 143 start: LengthMetrics.vp(12), 144 end: LengthMetrics.vp(12) 145 }, 146 }, 147 closeButton: { 148 size: { width: 22, height: 22 }, 149 padding: { 150 top: LengthMetrics.vp(2), 151 bottom: LengthMetrics.vp(2), 152 start: LengthMetrics.vp(2), 153 end: LengthMetrics.vp(2) 154 }, 155 margin: { 156 top: LengthMetrics.vp(12), 157 bottom: LengthMetrics.vp(12), 158 start: LengthMetrics.vp(12), 159 end: LengthMetrics.vp(12) 160 }, 161 symbolStyle: new SymbolGlyphModifier($r('sys.symbol.xmark')), 162 fillColor: $r('sys.color.icon_secondary'), 163 hoverColor: $r('sys.color.ohos_id_color_hover'), 164 backgroundColor: $r('sys.color.ohos_id_color_background_transparent'), 165 symbolSize: '18vp', 166 accessibilityMessage: $r('sys.string.off_used_for_accessibility_text') 167 }, 168}; 169 170export interface PopupTextOptions { 171 text: ResourceStr; 172 fontSize?: number | string | Resource; 173 fontColor?: ResourceColor; 174 fontWeight?: number | FontWeight | string; 175} 176 177export interface PopupButtonOptions { 178 text: ResourceStr; 179 action?: () => void; 180 fontSize?: number | string | Resource; 181 fontColor?: ResourceColor; 182} 183 184export interface PopupIconOptions { 185 image: ResourceStr; 186 width?: Dimension; 187 height?: Dimension; 188 fillColor?: ResourceColor; 189 borderRadius?: Length | BorderRadiuses; 190} 191 192export interface PopupOptions { 193 icon?: PopupIconOptions; 194 title?: PopupTextOptions; 195 message: PopupTextOptions; 196 direction?: Direction; 197 showClose?: boolean | Resource; 198 onClose?: () => void; 199 buttons?: [PopupButtonOptions?, PopupButtonOptions?]; 200 maxWidth?: Dimension; 201} 202 203const noop = () => { 204}; 205 206const POPUP_DEFAULT_MAXWIDTH = 400; 207 208@Builder 209export function Popup(options: PopupOptions) { 210 PopupComponent({ 211 icon: options.icon, 212 title: options.title, 213 message: options.message, 214 popupDirection: options.direction, 215 showClose: options.showClose, 216 onClose: options.onClose, 217 buttons: options.buttons, 218 maxWidth: options.maxWidth 219 }) 220} 221 222function isValidString(dimension: string, regex: RegExp): boolean { 223 const matches = dimension.match(regex); 224 if (!matches || matches.length < 3) { 225 return false; 226 } 227 const value = Number.parseFloat(matches[1]); 228 return value >= 0; 229} 230 231function isValidDimensionString(dimension: string): boolean { 232 return isValidString(dimension, new RegExp('(-?\\d+(?:\\.\\d+)?)_?(fp|vp|px|lpx|%)?$', 'i')); 233} 234 235function isValidResource(context: Context | undefined, value: Resource) { 236 const resourceManager = context?.resourceManager; 237 if (value === void (0) || value === null || resourceManager === void (0)) { 238 return false; 239 } 240 if (value.type !== RESOURCE_TYPE_STRING && value.type !== RESOURCE_TYPE_INTEGER && 241 value.type !== RESOURCE_TYPE_FLOAT) { 242 return false; 243 } 244 245 if (value.type === RESOURCE_TYPE_INTEGER || value.type === RESOURCE_TYPE_FLOAT) { 246 if (resourceManager.getNumber(value.id) >= 0) { 247 return true; 248 } else { 249 return false; 250 } 251 } 252 253 if (value.type === RESOURCE_TYPE_STRING && !isValidDimensionString(resourceManager.getStringSync(value.id))) { 254 return false; 255 } else { 256 return true; 257 } 258} 259 260@Component 261export struct PopupComponent { 262 private onClose: () => void = noop; 263 private theme: PopupTheme = defaultTheme; 264 private applycontentKey: string = 'applyContent' + systemDateTime.getTime(false); 265 @Prop icon: PopupIconOptions = { image: '' }; 266 @Prop maxWidth?: Dimension; 267 @Prop messageMaxWidth?: number = 0; 268 @Prop title: PopupTextOptions = { text: '' }; 269 @Prop message: PopupTextOptions = { text: '' }; 270 @Prop popupDirection: Direction = Direction.Auto; 271 @Prop showClose: boolean | Resource = true; 272 @Prop buttons: [PopupButtonOptions?, PopupButtonOptions?] = [{ text: '' }, { text: '' }]; 273 textHeight: number = 0; 274 @State titleHeight: number = 0; 275 @State applyHeight: number = 0; 276 @State buttonHeight: number = 0; 277 @State messageMaxWeight: number | undefined = 0; 278 @State beforeScreenStatus: boolean | undefined = undefined; 279 @State currentScreenStatus: boolean = true; 280 @State applySizeOptions: ConstraintSizeOptions | undefined = undefined; 281 @State closeButtonBackgroundColor: ResourceColor = $r('sys.color.ohos_id_color_background_transparent'); 282 @State firstButtonBackgroundColor: ResourceColor = $r('sys.color.ohos_id_color_background_transparent'); 283 @State secondButtonBackgroundColor: ResourceColor = $r('sys.color.ohos_id_color_background_transparent'); 284 @State closeButtonFillColorWithTheme: ResourceColor = $r('sys.color.icon_secondary'); 285 private listener = mediaquery.matchMediaSync('(orientation: landscape)') 286 287 private getIconWidth(): Dimension { 288 return this.icon?.width ?? this.theme.icon.size.width as number 289 } 290 291 private getIconHeight(): Dimension { 292 return this.icon?.height ?? this.theme.icon.size.height as number 293 } 294 295 private getIconFillColor(): ResourceColor { 296 return this.icon?.fillColor ?? this.theme.icon.fillColor 297 } 298 299 private getIconBorderRadius(): Length | BorderRadiuses { 300 return this.icon?.borderRadius ?? this.theme.icon.borderRadius 301 } 302 303 private getIconMargin(): LocalizedMargin { 304 return { 305 start: new LengthMetrics(this.theme.button.margin.start.value / 2, this.theme.button.margin.start.unit), 306 end: new LengthMetrics(this.theme.icon.margin.start.value - (this.theme.button.margin.end.value / 2) 307 , this.theme.button.margin.start.unit) 308 } 309 } 310 311 private getIconImage(): ResourceStr | undefined { 312 return this.icon?.image 313 } 314 315 private getTitleText(): ResourceStr | undefined { 316 return this.title?.text 317 } 318 319 private getTitlePadding(): LocalizedPadding { 320 return { 321 start: new LengthMetrics(this.theme.button.margin.start.value / 2, this.theme.button.margin.start.unit), 322 end: this.theme.closeButton.margin.end 323 } 324 } 325 326 private getTitleMargin(): LocalizedMargin { 327 return this.theme.title.margin 328 } 329 330 private getTitleMinFontSize(): number | string | Resource { 331 return this.theme.title.minFontSize 332 } 333 334 private getTitleFontWeight(): number | FontWeight | string { 335 return this.title?.fontWeight ?? this.theme.title.fontWeight 336 } 337 338 private getTitleFontSize(): number | string | Resource { 339 return this.title?.fontSize ?? this.theme.title.fontSize 340 } 341 342 private getTitleFontColor(): ResourceColor { 343 return this.title?.fontColor ?? this.theme.title.fontColor 344 } 345 346 private getCloseButtonWidth(): Length | undefined { 347 return this.theme.closeButton.size.width 348 } 349 350 private getCloseButtonHeight(): Length | undefined { 351 return this.theme.closeButton.size.height 352 } 353 354 private getCloseButtonFillColor(): ResourceColor { 355 return this.closeButtonFillColorWithTheme; 356 } 357 358 private getCloseButtonHoverColor(): ResourceColor { 359 return this.theme.closeButton.hoverColor 360 } 361 362 private getCloseButtonBackgroundColor(): ResourceColor { 363 return this.theme.closeButton.backgroundColor 364 } 365 366 private getCloseButtonPadding(): LocalizedPadding { 367 return this.theme.closeButton.padding 368 } 369 370 private getCloseButtonSymbolSize(): string | undefined { 371 return this.theme.closeButton.symbolSize 372 } 373 374 private getMessageText(): string | Resource { 375 return this.message.text 376 } 377 378 private getMessageFontSize(): number | string | Resource { 379 return this.message.fontSize ?? this.theme.message.fontSize 380 } 381 382 private getMessageFontColor(): ResourceColor { 383 let fontColor: ResourceColor 384 if (this.message.fontColor) { 385 fontColor = this.message.fontColor 386 } else { 387 if (this.title.text !== '' && this.title.text !== void (0)) { 388 fontColor = this.theme.message.fontColor 389 } else { 390 fontColor = this.theme.message.plainFontColor 391 } 392 } 393 return fontColor 394 } 395 396 private getMessagePadding(): LocalizedPadding { 397 let padding: LocalizedPadding 398 padding = { 399 start: LengthMetrics.vp(this.theme.button.margin.start.value / 2), 400 end: LengthMetrics.vp(this.theme.closeButton.margin.end.value) 401 } 402 return padding 403 } 404 405 private getMessageMaxWeight(): number | undefined { 406 let textMaxWeight: number | undefined = undefined; 407 let defaultDisplaySync: display.Display | undefined = undefined; 408 try { 409 defaultDisplaySync = display.getDefaultDisplaySync() 410 } catch (error) { 411 console.error(`Ace Popup getDefaultDisplaySync, error: ${error.toString()}`); 412 return textMaxWeight = 400 413 } 414 if (this.showClose || this.showClose === void (0)) { 415 if (this.messageMaxWidth != undefined) { 416 if (this.maxWidth != undefined && this.maxWidth > px2vp(defaultDisplaySync.width)) { 417 textMaxWeight = px2vp(defaultDisplaySync.width) 418 } else { 419 textMaxWeight = this.messageMaxWidth 420 } 421 } else { 422 if (defaultDisplaySync.width != 0) { 423 textMaxWeight = px2vp(defaultDisplaySync.width) 424 } else { 425 // The previewer does not support the display interface to use abnormal values 426 textMaxWeight = -1 427 } 428 } 429 textMaxWeight -= (this.theme.windows.padding.start.value - (this.theme.button.margin.end.value / 2)) 430 textMaxWeight -= this.theme.windows.padding.end.value 431 textMaxWeight -= this.theme.button.margin.start.value / 2 432 textMaxWeight -= this.theme.closeButton.margin.end.value 433 textMaxWeight -= this.getCloseButtonWidth() as number 434 } 435 return textMaxWeight 436 } 437 438 private getMessageFontWeight(): number | FontWeight | string { 439 return this.theme.message.fontWeight 440 } 441 442 private getButtonMargin(): LocalizedMargin { 443 return { 444 top: LengthMetrics.vp(this.theme.button.textMargin.top.value / 2 - 4), 445 bottom: LengthMetrics.vp(this.theme.button.textMargin.bottom.value / 2 - 4), 446 start: LengthMetrics.vp(this.theme.button.margin.start.value / 2 - 4), 447 end: LengthMetrics.vp(this.theme.button.margin.end.value / 2 - 4) 448 } 449 } 450 451 private getButtonTextMargin(): LocalizedMargin { 452 return { top: LengthMetrics.vp(this.theme.button.textMargin.bottom.value) } 453 } 454 455 private getButtonTextPadding(): LocalizedPadding { 456 return this.theme.button.padding 457 } 458 459 private getButtonHoverColor(): ResourceColor { 460 return this.theme.button.hoverColor 461 } 462 463 private getButtonBackgroundColor(): ResourceColor { 464 return this.theme.button.backgroundColor 465 } 466 467 private getFirstButtonText(): string | Resource | undefined { 468 return this.buttons?.[0]?.text 469 } 470 471 private getSecondButtonText(): string | Resource | undefined { 472 return this.buttons?.[1]?.text 473 } 474 475 private getFirstButtonFontSize(): number | string | Resource { 476 return this.buttons?.[0]?.fontSize ?? this.theme.button.fontSize 477 } 478 479 private getSecondButtonFontSize(): number | string | Resource { 480 return this.buttons?.[1]?.fontSize ?? this.theme.button.fontSize 481 } 482 483 private getFirstButtonFontColor(): ResourceColor { 484 return this.buttons?.[0]?.fontColor ?? this.theme.button.fontColor 485 } 486 487 private getSecondButtonFontColor(): ResourceColor { 488 return this.buttons?.[1]?.fontColor ?? this.theme.button.fontColor 489 } 490 491 private getButtonMinFontSize(): Dimension { 492 return this.theme.button.minFontSize 493 } 494 495 private getButtonFontWeight(): number | FontWeight | string { 496 return this.theme.button.fontWeight 497 } 498 499 private getWindowsPadding(): LocalizedPadding { 500 let top = this.theme.windows.padding.top; 501 let bottom = 502 LengthMetrics.vp(this.theme.windows.padding.bottom.value - (this.theme.button.textMargin.bottom.value / 2)); 503 let start = LengthMetrics.vp(this.theme.windows.padding.start.value - (this.theme.button.margin.end.value / 2)); 504 let end = this.theme.button.padding.end; 505 let resolvedMaxWidth = this.toVp(this.maxWidth); 506 if (resolvedMaxWidth === 0) { 507 start = LengthMetrics.vp(0); 508 end = LengthMetrics.vp(0); 509 } 510 return { 511 top: top, 512 bottom: bottom, 513 start: start, 514 end: end 515 }; 516 } 517 518 onWillApplyTheme(theme: Theme): void { 519 this.theme.title.fontColor = theme.colors.fontPrimary; 520 this.theme.button.fontColor = theme.colors.fontEmphasize; 521 this.theme.message.fontColor = theme.colors.fontSecondary; 522 this.theme.message.plainFontColor = theme.colors.fontPrimary; 523 this.closeButtonFillColorWithTheme = theme.colors.iconSecondary; 524 } 525 526 aboutToAppear() { 527 this.listener.on("change", (mediaQueryResult: mediaquery.MediaQueryResult) => { 528 this.currentScreenStatus = mediaQueryResult.matches 529 }) 530 } 531 532 aboutToDisappear() { 533 this.listener.off("change") 534 } 535 536 getScrollMaxHeight(): number | undefined { 537 let scrollMaxHeight: number | undefined = undefined; 538 if (this.currentScreenStatus !== this.beforeScreenStatus) { 539 this.applySizeOptions = this.getApplyMaxSize(); 540 this.beforeScreenStatus = this.currentScreenStatus 541 return scrollMaxHeight; 542 } 543 scrollMaxHeight = px2vp(componentUtils.getRectangleById(this.applycontentKey).size?.height) 544 scrollMaxHeight -= this.titleHeight 545 scrollMaxHeight -= this.buttonHeight 546 scrollMaxHeight -= this.theme.windows.padding.top.value 547 scrollMaxHeight -= (this.theme.button.textMargin.bottom.value / 2) 548 scrollMaxHeight -= this.theme.title.margin.bottom.value 549 scrollMaxHeight -= (this.theme.windows.padding.bottom.value - 550 (this.theme.button.textMargin.bottom.value / 2)) 551 if (Math.floor(this.textHeight) > Math.floor(scrollMaxHeight + 1)) { 552 return scrollMaxHeight 553 } else { 554 scrollMaxHeight = undefined 555 return scrollMaxHeight 556 } 557 } 558 559 private getLayoutWeight(): number { 560 let layoutWeight: number 561 if ((this.icon.image !== '' && this.icon.image !== void (0)) || 562 (this.title.text !== '' && this.title.text !== void (0)) || 563 (this.buttons?.[0]?.text !== '' && this.buttons?.[0]?.text !== void (0)) || 564 (this.buttons?.[1]?.text !== '' && this.buttons?.[1]?.text !== void (0))) { 565 layoutWeight = 1 566 } else { 567 layoutWeight = 0 568 } 569 return layoutWeight 570 } 571 572 private resourceToVp(value: Resource): number { 573 try { 574 if ((value as Resource).id !== -1) { 575 return px2vp(getContext(this).resourceManager.getNumber((value as Resource).id)) 576 } else { 577 return px2vp(getContext(this) 578 .resourceManager 579 .getNumberByName(((value.params as string[])[0]).split('.')[2])) 580 } 581 } catch (error) { 582 return POPUP_DEFAULT_MAXWIDTH 583 } 584 } 585 586 private toVp(value: Dimension | Length | undefined): number { 587 let defaultDisplaySync: display.Display | undefined = undefined; 588 try { 589 defaultDisplaySync = display.getDefaultDisplaySync() 590 } catch (error) { 591 console.error(`Ace Popup getDefaultDisplaySync, error: ${error.toString()}`); 592 return Number.NEGATIVE_INFINITY; 593 } 594 if (value === void (0)) { 595 return Number.NEGATIVE_INFINITY 596 } 597 switch (typeof (value)) { 598 case 'number': 599 return value as number 600 case 'object': 601 try { 602 let returnValue = this.resourceToVp(value); 603 if (returnValue === 0 && 604 !isValidResource(getContext(this), value)) { 605 return Number.NEGATIVE_INFINITY; 606 } 607 return returnValue; 608 } catch (error) { 609 return Number.NEGATIVE_INFINITY 610 } 611 case 'string': 612 let regex: RegExp = new RegExp('(-?\\d+(?:\\.\\d+)?)_?(fp|vp|px|lpx|%)?$', 'i'); 613 let matches: RegExpMatchArray | null = value.match(regex); 614 if (!matches) { 615 return Number.NEGATIVE_INFINITY 616 } 617 let length: number = Number(matches?.[1] ?? 0); 618 let unit: string = matches?.[2] ?? 'vp' 619 switch (unit.toLowerCase()) { 620 case 'px': 621 length = px2vp(length) 622 break 623 case 'fp': 624 length = px2vp(fp2px(length)) 625 break 626 case 'lpx': 627 length = px2vp(lpx2px(length)) 628 break 629 case '%': 630 length = length / 100 * px2vp(defaultDisplaySync.width); 631 break 632 case 'vp': 633 break 634 default: 635 break 636 } 637 return length 638 default: 639 return Number.NEGATIVE_INFINITY 640 } 641 } 642 643 private getApplyMaxSize(): ConstraintSizeOptions { 644 let applyMaxWidth: number | undefined = undefined; 645 let applyMaxHeight: number | undefined = undefined; 646 let applyMaxSize: ConstraintSizeOptions | undefined = undefined; 647 let defaultDisplaySync: display.Display | undefined = undefined; 648 let maxWidthSize = 400; 649 try { 650 defaultDisplaySync = display.getDefaultDisplaySync() 651 } catch (error) { 652 console.error(`Ace Popup getDefaultDisplaySync, error: ${error.toString()}`); 653 this.messageMaxWeight = 400 654 return applyMaxSize = { maxWidth: 400, maxHeight: 480 } 655 } 656 if (this.maxWidth !== undefined) { 657 if (typeof this.maxWidth === 'number' && this.maxWidth >= 0) { 658 maxWidthSize = this.maxWidth; 659 } else if (typeof this.maxWidth === 'number' && this.maxWidth < 0) { 660 maxWidthSize = POPUP_DEFAULT_MAXWIDTH 661 } else { 662 maxWidthSize = this.toVp(this.maxWidth); 663 } 664 } 665 if (px2vp(defaultDisplaySync.width) > maxWidthSize) { 666 applyMaxWidth = maxWidthSize 667 } else { 668 if (defaultDisplaySync.width != 0) { 669 applyMaxWidth = px2vp(defaultDisplaySync.width) 670 } else { 671 // The previewer does not support the display interface to use abnormal values 672 applyMaxWidth = -1 673 } 674 } 675 if (px2vp(defaultDisplaySync.height) > 480) { 676 applyMaxHeight = 480 677 } else { 678 applyMaxHeight = px2vp(defaultDisplaySync.height) - 40 - 40 679 } 680 applyMaxSize = { maxWidth: applyMaxWidth, maxHeight: applyMaxHeight } 681 this.messageMaxWidth = applyMaxWidth; 682 this.messageMaxWeight = this.getMessageMaxWeight() 683 return applyMaxSize 684 } 685 686 private getTitleTextAlign(): TextAlign { 687 let titleAlign = TextAlign.Start; 688 if ((Configuration.getLocale().dir === 'rtl') && this.popupDirection === Direction.Auto) { 689 titleAlign = TextAlign.End; 690 } 691 return titleAlign 692 } 693 694 build() { 695 Row() { 696 if (this.icon.image !== '' && this.icon.image !== void (0)) { 697 Image(this.getIconImage()) 698 .direction(this.popupDirection) 699 .width(this.getIconWidth()) 700 .height(this.getIconHeight()) 701 .margin(this.getIconMargin()) 702 .fillColor(this.getIconFillColor()) 703 .borderRadius(this.getIconBorderRadius()) 704 .draggable(false) 705 } 706 if (this.title.text !== '' && this.title.text !== void (0)) { 707 Column() { 708 Flex({ alignItems: ItemAlign.Start }) { 709 Text(this.getTitleText()) 710 .direction(this.popupDirection) 711 .flexGrow(1) 712 .maxLines(2) 713 .align(Alignment.Start) 714 .padding(this.getTitlePadding()) 715 .minFontSize(this.getTitleMinFontSize()) 716 .textOverflow({ overflow: TextOverflow.Ellipsis }) 717 .fontWeight(this.getTitleFontWeight()) 718 .fontSize(this.getTitleFontSize()) 719 .fontColor(this.getTitleFontColor()) 720 .constraintSize({ minHeight: this.getCloseButtonHeight() }) 721 .textAlign(this.getTitleTextAlign()) 722 if (this.showClose || this.showClose === void (0)) { 723 Button() { 724 SymbolGlyph() 725 .fontColor([this.getCloseButtonFillColor()]) 726 .fontSize(this.getCloseButtonSymbolSize()) 727 .direction(this.popupDirection) 728 .attributeModifier(this.theme.closeButton.symbolStyle) 729 .focusable(true) 730 .draggable(false) 731 } 732 .direction(this.popupDirection) 733 .width(this.getCloseButtonWidth()) 734 .height(this.getCloseButtonHeight()) 735 .padding(this.getCloseButtonPadding()) 736 .backgroundColor(this.closeButtonBackgroundColor) 737 .flexShrink(0) 738 .accessibilityText(this.theme.closeButton.accessibilityMessage) 739 .onHover((isHover: boolean) => { 740 if (isHover) { 741 this.closeButtonBackgroundColor = this.getCloseButtonHoverColor() 742 } else { 743 this.closeButtonBackgroundColor = this.getCloseButtonBackgroundColor() 744 } 745 }) 746 .onClick(() => { 747 if (this.onClose) { 748 this.onClose(); 749 } 750 }) 751 } 752 } 753 .direction(this.popupDirection) 754 .width("100%") 755 .margin(this.getTitleMargin()) 756 .onAreaChange((_, rect) => { 757 this.titleHeight = rect.height as number 758 }) 759 760 Scroll() { 761 Text(this.getMessageText()) 762 .direction(this.popupDirection) 763 .fontSize(this.getMessageFontSize()) 764 .fontColor(this.getMessageFontColor()) 765 .fontWeight(this.getMessageFontWeight()) 766 .constraintSize({ minHeight: this.getCloseButtonHeight() }) 767 .onAreaChange((_, rect) => { 768 this.textHeight = rect.height as number 769 }) 770 } 771 .direction(this.popupDirection) 772 .width("100%") 773 .align(Alignment.TopStart) 774 .padding(this.getMessagePadding()) 775 .scrollBar(BarState.Auto) 776 .scrollable(ScrollDirection.Vertical) 777 .constraintSize({ maxHeight: this.getScrollMaxHeight() }) 778 .edgeEffect(EdgeEffect.Spring, { alwaysEnabled: false }) 779 780 Flex({ wrap: FlexWrap.Wrap }) { 781 if (this.buttons?.[0]?.text !== '' && this.buttons?.[0]?.text !== void (0)) { 782 Button() { 783 Text(this.getFirstButtonText()) 784 .direction(this.popupDirection) 785 .maxLines(2) 786 .focusable(true) 787 .fontSize(this.getFirstButtonFontSize()) 788 .fontColor(this.getFirstButtonFontColor()) 789 .fontWeight(this.getButtonFontWeight()) 790 .minFontSize(this.getButtonMinFontSize()) 791 .textOverflow({ overflow: TextOverflow.Ellipsis }) 792 } 793 .type(ButtonType.Normal) 794 .borderRadius($r('sys.float.popup_button_border_radius')) 795 .direction(this.popupDirection) 796 .margin(this.getButtonMargin()) 797 .padding(this.getButtonTextPadding()) 798 .backgroundColor(this.firstButtonBackgroundColor) 799 .onHover((isHover: boolean) => { 800 if (isHover) { 801 this.firstButtonBackgroundColor = this.getButtonHoverColor() 802 } else { 803 this.firstButtonBackgroundColor = this.getButtonBackgroundColor() 804 } 805 }) 806 .onClick(() => { 807 if (this.buttons?.[0]?.action) { 808 this.buttons?.[0]?.action(); 809 } 810 }) 811 } 812 if (this.buttons?.[1]?.text !== '' && this.buttons?.[1]?.text !== void (0)) { 813 Button() { 814 Text(this.getSecondButtonText()) 815 .direction(this.popupDirection) 816 .maxLines(2) 817 .focusable(true) 818 .fontSize(this.getSecondButtonFontSize()) 819 .fontColor(this.getSecondButtonFontColor()) 820 .fontWeight(this.getButtonFontWeight()) 821 .minFontSize(this.getButtonMinFontSize()) 822 .textOverflow({ overflow: TextOverflow.Ellipsis }) 823 } 824 .type(ButtonType.Normal) 825 .borderRadius($r('sys.float.popup_button_border_radius')) 826 .direction(this.popupDirection) 827 .margin(this.getButtonMargin()) 828 .padding(this.getButtonTextPadding()) 829 .backgroundColor(this.secondButtonBackgroundColor) 830 .onHover((isHover: boolean) => { 831 if (isHover) { 832 this.secondButtonBackgroundColor = this.getButtonHoverColor() 833 } else { 834 this.secondButtonBackgroundColor = this.getButtonBackgroundColor() 835 } 836 }) 837 .onClick(() => { 838 if (this.buttons?.[1]?.action) { 839 this.buttons?.[1]?.action(); 840 } 841 }) 842 } 843 } 844 .direction(this.popupDirection) 845 .margin(this.getButtonTextMargin()) 846 .flexGrow(1) 847 .onAreaChange((_, rect) => { 848 if ((this.buttons?.[0]?.text !== '' && this.buttons?.[0]?.text !== void (0)) || 849 (this.buttons?.[1]?.text !== '' && this.buttons?.[1]?.text !== void (0))) { 850 this.buttonHeight = rect.height as number 851 } else { 852 this.buttonHeight = 0 853 } 854 }) 855 } 856 .direction(this.popupDirection) 857 .layoutWeight(this.getLayoutWeight()) 858 } else { 859 Column() { 860 Flex().height(0).onAreaChange((_, rect) => { 861 this.titleHeight = rect.height as number 862 }) 863 Row() { 864 Scroll() { 865 Text(this.getMessageText()) 866 .direction(this.popupDirection) 867 .fontSize(this.getMessageFontSize()) 868 .fontColor(this.getMessageFontColor()) 869 .fontWeight(this.getMessageFontWeight()) 870 .constraintSize({ maxWidth: this.messageMaxWeight, minHeight: this.getCloseButtonHeight() }) 871 .onAreaChange((_, rect) => { 872 this.textHeight = rect.height as number 873 }) 874 } 875 .direction(this.popupDirection) 876 .layoutWeight(this.getLayoutWeight()) 877 .edgeEffect(EdgeEffect.Spring, { alwaysEnabled: false }) 878 .align(Alignment.TopStart) 879 .padding(this.getMessagePadding()) 880 .scrollBar(BarState.Auto) 881 .scrollable(ScrollDirection.Vertical) 882 .constraintSize({ maxHeight: this.getScrollMaxHeight() }) 883 884 if (this.showClose || this.showClose === void (0)) { 885 Button() { 886 SymbolGlyph() 887 .fontColor([this.getCloseButtonFillColor()]) 888 .fontSize(this.getCloseButtonSymbolSize()) 889 .direction(this.popupDirection) 890 .attributeModifier(this.theme.closeButton.symbolStyle) 891 .focusable(true) 892 .draggable(false) 893 } 894 .direction(this.popupDirection) 895 .width(this.getCloseButtonWidth()) 896 .height(this.getCloseButtonHeight()) 897 .padding(this.getCloseButtonPadding()) 898 .backgroundColor(this.closeButtonBackgroundColor) 899 .flexShrink(0) 900 .accessibilityText(this.theme.closeButton.accessibilityMessage) 901 .onHover((isHover: boolean) => { 902 if (isHover) { 903 this.closeButtonBackgroundColor = this.getCloseButtonHoverColor() 904 } else { 905 this.closeButtonBackgroundColor = this.getCloseButtonBackgroundColor() 906 } 907 }) 908 .onClick(() => { 909 if (this.onClose) { 910 this.onClose(); 911 } 912 }) 913 } 914 } 915 .direction(this.popupDirection) 916 .alignItems(VerticalAlign.Top) 917 918 Flex({ wrap: FlexWrap.Wrap }) { 919 if (this.buttons?.[0]?.text !== '' && this.buttons?.[0]?.text !== void (0)) { 920 Button() { 921 Text(this.getFirstButtonText()) 922 .direction(this.popupDirection) 923 .maxLines(2) 924 .focusable(true) 925 .fontSize(this.getFirstButtonFontSize()) 926 .fontColor(this.getFirstButtonFontColor()) 927 .fontWeight(this.getButtonFontWeight()) 928 .minFontSize(this.getButtonMinFontSize()) 929 .textOverflow({ overflow: TextOverflow.Ellipsis }) 930 } 931 .type(ButtonType.Normal) 932 .borderRadius($r('sys.float.popup_button_border_radius')) 933 .direction(this.popupDirection) 934 .margin(this.getButtonMargin()) 935 .padding(this.getButtonTextPadding()) 936 .backgroundColor(this.firstButtonBackgroundColor) 937 .onHover((isHover: boolean) => { 938 if (isHover) { 939 this.firstButtonBackgroundColor = this.getButtonHoverColor() 940 } else { 941 this.firstButtonBackgroundColor = this.getButtonBackgroundColor() 942 } 943 }) 944 .onClick(() => { 945 if (this.buttons?.[0]?.action) { 946 this.buttons?.[0]?.action(); 947 } 948 }) 949 } 950 if (this.buttons?.[1]?.text !== '' && this.buttons?.[1]?.text !== void (0)) { 951 Button() { 952 Text(this.getSecondButtonText()) 953 .direction(this.popupDirection) 954 .maxLines(2) 955 .focusable(true) 956 .fontSize(this.getSecondButtonFontSize()) 957 .fontColor(this.getSecondButtonFontColor()) 958 .fontWeight(this.getButtonFontWeight()) 959 .minFontSize(this.getButtonMinFontSize()) 960 .textOverflow({ overflow: TextOverflow.Ellipsis }) 961 } 962 .type(ButtonType.Normal) 963 .borderRadius($r('sys.float.popup_button_border_radius')) 964 .direction(this.popupDirection) 965 .margin(this.getButtonMargin()) 966 .padding(this.getButtonTextPadding()) 967 .backgroundColor(this.secondButtonBackgroundColor) 968 .onHover((isHover: boolean) => { 969 if (isHover) { 970 this.secondButtonBackgroundColor = this.getButtonHoverColor() 971 } else { 972 this.secondButtonBackgroundColor = this.getButtonBackgroundColor() 973 } 974 }) 975 .onClick(() => { 976 if (this.buttons?.[1]?.action) { 977 this.buttons?.[1]?.action(); 978 } 979 }) 980 } 981 } 982 .direction(this.popupDirection) 983 .margin(this.getButtonTextMargin()) 984 .flexGrow(1) 985 .onAreaChange((_, rect) => { 986 if ((this.buttons?.[0]?.text !== '' && this.buttons?.[0]?.text !== void (0)) || 987 (this.buttons?.[1]?.text !== '' && this.buttons?.[1]?.text !== void (0))) { 988 this.buttonHeight = rect.height as number 989 } else { 990 this.buttonHeight = 0 991 } 992 }) 993 } 994 .direction(this.popupDirection) 995 .layoutWeight(this.getLayoutWeight()) 996 } 997 } 998 .direction(this.popupDirection) 999 .alignItems(VerticalAlign.Top) 1000 .padding(this.getWindowsPadding()) 1001 .constraintSize(this.applySizeOptions) 1002 .constraintSize(this.getApplyMaxSize()) 1003 .key(this.applycontentKey) 1004 .onAreaChange((_, rect) => { 1005 this.applyHeight = rect.height as number 1006 }) 1007 } 1008} 1009