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