/*
* Copyright (c) 2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import display from '@ohos.display';
import mediaquery from '@ohos.mediaquery';
import { Theme } from '@ohos.arkui.theme';
import { LengthMetrics } from '@ohos.arkui.node';
import { SymbolGlyphModifier, Configuration } from '@kit.ArkUI';
import { systemDateTime } from '@kit.BasicServicesKit';
import { TextModifier, ImageModifier } from '@ohos.arkui.modifier';
const RESOURCE_TYPE_STRING = 10003;
const RESOURCE_TYPE_FLOAT = 10002;
const RESOURCE_TYPE_INTEGER = 10007;
interface IconTheme {
size: SizeOptions;
margin: LocalizedMargin;
fillColor: ColorContent | ResourceColor;
borderRadius: Length;
}
interface TitleTheme {
margin: LocalizedMargin;
minFontSize: number;
fontWeight: FontWeight;
fontSize: Resource;
fontColor: ResourceColor;
}
interface ButtonTheme {
margin: LocalizedMargin;
padding: LocalizedPadding;
fontSize: Resource;
fontColor: ResourceColor;
textMargin: LocalizedMargin;
minFontSize: number;
fontWeight: FontWeight;
hoverColor: ResourceColor;
backgroundColor: ResourceColor;
responseRegion: Length;
}
interface MessageTheme {
fontSize: Resource;
fontColor: ResourceColor;
fontWeight: FontWeight;
plainFontColor: ResourceColor;
}
interface CloseButtonTheme {
size: SizeOptions;
margin: LocalizedMargin;
padding: LocalizedPadding;
fillColor: ResourceColor;
hoverColor: ResourceColor;
backgroundColor: ResourceColor;
symbolStyle: SymbolGlyphModifier;
symbolSize: string;
accessibilityMessage: Resource;
responseRegion: Length;
}
interface WindowsTheme {
padding: LocalizedPadding;
}
interface PopupTheme {
icon: IconTheme;
title: TitleTheme;
button: ButtonTheme;
message: MessageTheme;
windows: WindowsTheme;
closeButton: CloseButtonTheme;
}
export const defaultTheme: PopupTheme = {
icon: {
size: { width: 32, height: 32 },
margin: {
top: LengthMetrics.vp(12),
bottom: LengthMetrics.vp(12),
start: LengthMetrics.vp(12),
end: LengthMetrics.vp(12)
},
fillColor: ColorContent.ORIGIN,
borderRadius: $r('sys.float.ohos_id_corner_radius_default_s')
},
title: {
margin: { bottom: LengthMetrics.vp(2) },
minFontSize: 12,
fontWeight: FontWeight.Medium,
fontSize: $r('sys.float.ohos_id_text_size_sub_title2'),
fontColor: $r('sys.color.font_primary')
},
button: {
margin: {
top: LengthMetrics.vp(16),
bottom: LengthMetrics.vp(16),
start: LengthMetrics.vp(16),
end: LengthMetrics.vp(16)
},
padding: {
top: LengthMetrics.vp(4),
bottom: LengthMetrics.vp(4),
start: LengthMetrics.vp(4),
end: LengthMetrics.vp(4)
},
fontSize: $r('sys.float.ohos_id_text_size_button2'),
fontColor: $r('sys.color.font_emphasize'),
textMargin: {
top: LengthMetrics.vp(8),
bottom: LengthMetrics.vp(8),
start: LengthMetrics.vp(8),
end: LengthMetrics.vp(8)
},
minFontSize: 9,
fontWeight: FontWeight.Medium,
hoverColor: $r('sys.color.ohos_id_color_hover'),
backgroundColor: $r('sys.color.ohos_id_color_background_transparent'),
responseRegion: $r('sys.float.popup_button_response_region')
},
message: {
fontSize: $r('sys.float.ohos_id_text_size_body2'),
fontColor: $r('sys.color.font_secondary'),
fontWeight: FontWeight.Regular,
plainFontColor: $r('sys.color.font_primary')
},
windows: {
padding: {
top: LengthMetrics.vp(12),
bottom: LengthMetrics.vp(12),
start: LengthMetrics.vp(12),
end: LengthMetrics.vp(12)
},
},
closeButton: {
size: { width: 22, height: 22 },
padding: {
top: LengthMetrics.vp(2),
bottom: LengthMetrics.vp(2),
start: LengthMetrics.vp(2),
end: LengthMetrics.vp(2)
},
margin: {
top: LengthMetrics.vp(12),
bottom: LengthMetrics.vp(12),
start: LengthMetrics.vp(12),
end: LengthMetrics.vp(12)
},
symbolStyle: new SymbolGlyphModifier($r('sys.symbol.xmark')),
fillColor: $r('sys.color.icon_secondary'),
hoverColor: $r('sys.color.ohos_id_color_hover'),
backgroundColor: $r('sys.color.ohos_id_color_background_transparent'),
symbolSize: '18vp',
accessibilityMessage: $r('sys.string.off_used_for_accessibility_text'),
responseRegion: $r('sys.float.popup_close_button_response_region')
},
};
export interface PopupV2Button {
text: ResourceStr;
buttonTextModifier?: TextModifier;
action?: () => void;
}
export interface PopupV2InitInfo {
icon?: ResourceStr;
iconModifier?: ImageModifier;
title?: ResourceStr;
titleModifier?: TextModifier
message: ResourceStr;
messageModifier?: TextModifier
direction?: Direction;
showClose?: boolean | Resource;
onClose?: () => void;
buttons?: [PopupV2Button?, PopupV2Button?];
maxWidth?: Dimension;
}
const noop = () => {
};
const POPUP_DEFAULT_MAXWIDTH = 400;
const MAX_FONT_SCALE = 2;
@Builder
export function PopupV2(options: PopupV2InitInfo) {
PopupV2ComponentV2({
icon: options.icon,
title: options.title,
iconModifier: options.iconModifier,
titleModifier: options.titleModifier,
messageModifier: options.messageModifier,
message: options.message,
popupDirection: options.direction,
showClose: options.showClose,
onClose: options.onClose,
buttons: options.buttons,
maxWidth: options.maxWidth
})
}
function isValidString(dimension: string, regex: RegExp): boolean {
const matches = dimension.match(regex);
if (!matches || matches.length < 3) {
return false;
}
const value = Number.parseFloat(matches[1]);
return value >= 0;
}
function isValidDimensionString(dimension: string): boolean {
return isValidString(dimension, new RegExp('(-?\\d+(?:\\.\\d+)?)_?(fp|vp|px|lpx|%)?$', 'i'));
}
function isValidResource(context: Context | undefined, value: Resource) {
const resourceManager = context?.resourceManager;
if (value === void (0) || value === null || resourceManager === void (0)) {
return false;
}
if (value.type !== RESOURCE_TYPE_STRING && value.type !== RESOURCE_TYPE_INTEGER &&
value.type !== RESOURCE_TYPE_FLOAT) {
return false;
}
if (value.type === RESOURCE_TYPE_INTEGER || value.type === RESOURCE_TYPE_FLOAT) {
if (resourceManager.getNumber(value.id) >= 0) {
return true;
} else {
return false;
}
}
if (value.type === RESOURCE_TYPE_STRING && !isValidDimensionString(resourceManager.getStringSync(value.id))) {
return false;
} else {
return true;
}
}
@ComponentV2
export struct PopupV2ComponentV2 {
@Param onClose: () => void = noop;
@Param theme: PopupTheme = defaultTheme;
private applycontentKey: string = 'applyContent' + systemDateTime.getTime(false);
@Param icon: ResourceStr = '';
@Require @Param maxWidth?: Dimension;
@Local messageMaxWidth?: number = 0;
@Param title: ResourceStr = '' ;
@Param message: ResourceStr = '' ;
@Require @Param iconModifier?: ImageModifier;
@Require @Param titleModifier?: TextModifier;
@Require @Param messageModifier?: TextModifier;
@Param popupDirection: Direction = Direction.Auto;
@Param showClose: boolean | Resource = true;
@Param buttons: [PopupV2Button?, PopupV2Button?] = [{ text: '' }, { text: '' }];
textHeight: number = 0;
@Local titleHeight: number = 0;
@Local applyHeight: number = 0;
@Local buttonHeight: number = 0;
@Local messageMaxWeight: number | undefined = 0;
@Local beforeScreenStatus: boolean | undefined = undefined;
@Local currentScreenStatus: boolean | undefined = undefined;
@Local applySizeOptions: ConstraintSizeOptions | undefined = undefined;
@Local closeButtonBackgroundColor: ResourceColor = $r('sys.color.ohos_id_color_background_transparent');
@Local firstButtonBackgroundColor: ResourceColor = $r('sys.color.ohos_id_color_background_transparent');
@Local secondButtonBackgroundColor: ResourceColor = $r('sys.color.ohos_id_color_background_transparent');
@Local closeButtonFillColorWithTheme: ResourceColor = $r('sys.color.icon_secondary');
@Local scrollMaxHeight: number | undefined = undefined;
@Local firstButtonHeight: number = 0;
@Local secondButtonHeight: number = 0;
@Local appMaxFontScale: number = MAX_FONT_SCALE;
private listener = mediaquery.matchMediaSync('(orientation: landscape)')
private getIconWidth(): Dimension {
return this.theme.icon.size.width as number
}
private getIconHeight(): Dimension {
return this.theme.icon.size.height as number
}
private getIconFillColor(): ResourceColor | ColorContent {
return this.theme.icon.fillColor
}
private getIconBorderRadius(): Length | BorderRadiuses {
return this.theme.icon.borderRadius
}
private getIconMargin(): LocalizedMargin {
return {
start: new LengthMetrics(this.theme.button.margin.start!.value / 2, this.theme.button.margin.start!.unit),
end: new LengthMetrics(this.theme.icon.margin.start!.value - (this.theme.button.margin.end!.value / 2)
, this.theme.button.margin.start!.unit)
}
}
private getIconImage(): ResourceStr | undefined {
return this.icon
}
private getTitleText(): ResourceStr | undefined {
return this.title
}
private getTitlePadding(): LocalizedPadding {
return {
start: new LengthMetrics(this.theme.button.margin.start!.value / 2, this.theme.button.margin.start!.unit),
end: this.theme.closeButton.margin.end
}
}
private getTitleMargin(): LocalizedMargin {
return this.theme.title.margin
}
private getTitleMinFontSize(): number | string | Resource {
return this.theme.title.minFontSize
}
private getTitleFontWeight(): number | FontWeight | string {
return this.theme.title.fontWeight
}
private getTitleFontSize(): number | string | Resource {
return this.theme.title.fontSize
}
private getTitleFontColor(): ResourceColor {
return this.theme.title.fontColor
}
private getCloseButtonWidth(): Length | undefined {
return this.theme.closeButton.size.width
}
private getCloseButtonHeight(): Length | undefined {
return this.theme.closeButton.size.height
}
private getCloseButtonFillColor(): ResourceColor {
return this.closeButtonFillColorWithTheme;
}
private getCloseButtonHoverColor(): ResourceColor {
return this.theme.closeButton.hoverColor
}
private getCloseButtonBackgroundColor(): ResourceColor {
return this.theme.closeButton.backgroundColor
}
private getCloseButtonPadding(): LocalizedPadding {
return this.theme.closeButton.padding
}
private getCloseButtonSymbolSize(): string | undefined {
return this.theme.closeButton.symbolSize
}
private getMessageText(): string | Resource {
return this.message
}
private getMessageFontSize(): number | string | Resource {
return this.theme.message.fontSize
}
private getMessageFontColor(): ResourceColor {
let fontColor: ResourceColor
if (this.title !== '' && this.title !== void (0)) {
fontColor = this.theme.message.fontColor
} else {
fontColor = this.theme.message.plainFontColor
}
return fontColor
}
private getMessagePadding(): LocalizedPadding {
let padding: LocalizedPadding
padding = {
start: LengthMetrics.vp((this.theme.button.margin.start?.value || 0) / 2),
end: LengthMetrics.vp(this.theme.closeButton.margin.end?.value || 0)
}
return padding
}
private getMessageMaxWeight(): number | undefined {
let textMaxWeight: number | undefined = undefined;
let defaultDisplaySync: display.Display | undefined = undefined;
try {
defaultDisplaySync = display.getDefaultDisplaySync()
} catch (error) {
console.error(`Ace PopupV2 getDefaultDisplaySync, error: ${error.toString()}`);
return textMaxWeight = 400
}
if (this.showClose || this.showClose === void (0)) {
if (this.messageMaxWidth != undefined) {
if (this.maxWidth != undefined && this.maxWidth > px2vp(defaultDisplaySync.width)) {
textMaxWeight = px2vp(defaultDisplaySync.width)
} else {
textMaxWeight = this.messageMaxWidth
}
} else {
if (defaultDisplaySync.width != 0) {
textMaxWeight = px2vp(defaultDisplaySync.width)
} else {
// The previewer does not support the display interface to use abnormal values
textMaxWeight = -1
}
}
textMaxWeight -= (this.theme.windows.padding.start!.value - (this.theme.button.margin.end!.value / 2))
textMaxWeight -= this.theme.windows.padding.end!.value
textMaxWeight -= this.theme.button.margin.start!.value / 2
textMaxWeight -= this.theme.closeButton.margin.end!.value
textMaxWeight -= this.getCloseButtonWidth() as number
}
return textMaxWeight
}
private getMessageFontWeight(): number | FontWeight | string {
return this.theme.message.fontWeight
}
private getButtonMargin(): LocalizedMargin {
return {
top: LengthMetrics.vp(this.theme.button.textMargin.top!.value / 2 - 4),
bottom: LengthMetrics.vp(this.theme.button.textMargin.bottom!.value / 2 - 4),
start: LengthMetrics.vp(this.theme.button.margin.start!.value / 2 - 4),
end: LengthMetrics.vp(this.theme.button.margin.end!.value / 2 - 4)
}
}
private getButtonTextMargin(): LocalizedMargin {
return { top: LengthMetrics.vp(this.theme.button.textMargin.bottom!.value) }
}
private getButtonTextPadding(): LocalizedPadding {
return this.theme.button.padding
}
private getButtonHoverColor(): ResourceColor {
return this.theme.button.hoverColor
}
private getButtonBackgroundColor(): ResourceColor {
return this.theme.button.backgroundColor
}
private getFirstButtonText(): string | Resource | undefined {
return this.buttons?.[0]?.text
}
private getSecondButtonText(): string | Resource | undefined {
return this.buttons?.[1]?.text
}
private getFirstButtonFontSize(): number | string | Resource {
return this.theme.button.fontSize
}
private getSecondButtonFontSize(): number | string | Resource {
return this.theme.button.fontSize
}
private getFirstButtonFontColor(): ResourceColor {
return this.theme.button.fontColor
}
private getSecondButtonFontColor(): ResourceColor {
return this.theme.button.fontColor
}
private getButtonMinFontSize(): Dimension {
return this.theme.button.minFontSize
}
private getButtonFontWeight(): number | FontWeight | string {
return this.theme.button.fontWeight
}
private getBtnResponseRegion(actualWidth: number, actualHeight: number, minSizeVp: number): Rectangle | undefined {
if (actualWidth === 0 || actualHeight === 0 || minSizeVp <= 0) {
return undefined;
}
let needExpandWidth = actualWidth === -1 ? false : (actualWidth < minSizeVp);
let needExpandHeight = actualHeight < minSizeVp;
if (!needExpandWidth && !needExpandHeight) {
return undefined;
}
let regionWidth = needExpandWidth ? minSizeVp : '100%';
let regionHeight = needExpandHeight ? minSizeVp : '100%';
let offsetX = needExpandWidth ? (minSizeVp - actualWidth) / 2 : 0;
let offsetY = needExpandHeight ? (minSizeVp - actualHeight) / 2 : 0;
return {
x: -offsetX,
y: -offsetY,
width: regionWidth,
height: regionHeight
};
}
private getCloseBtnResponseRegion(): Rectangle | undefined {
let responseRegionValue = this.toVp(this.theme.closeButton.responseRegion);
return this.getBtnResponseRegion(this.theme.closeButton.size.width as number,
this.theme.closeButton.size.height as number, responseRegionValue)
}
private getNormalBtnResponseRegion(height: number): Rectangle | undefined {
let responseRegionValue = this.toVp(this.theme.button.responseRegion);
return this.getBtnResponseRegion(-1, height, responseRegionValue)
}
private getWindowsPadding(): LocalizedPadding {
let top = this.theme.windows.padding.top;
let bottom =
LengthMetrics.vp(this.theme.windows.padding.bottom!.value - (this.theme.button.textMargin.bottom!.value / 2));
let start = LengthMetrics.vp(this.theme.windows.padding.start!.value - (this.theme.button.margin.end!.value / 2));
let end = this.theme.windows.padding.end;
let resolvedMaxWidth = this.toVp(this.maxWidth);
if (resolvedMaxWidth === 0) {
start = LengthMetrics.vp(0);
end = LengthMetrics.vp(0);
}
return {
top: top,
bottom: bottom,
start: start,
end: end
};
}
onWillApplyTheme(theme: Theme): void {
this.theme.title.fontColor = theme.colors.fontPrimary;
this.theme.button.fontColor = theme.colors.fontEmphasize;
this.theme.message.fontColor = theme.colors.fontSecondary;
this.theme.message.plainFontColor = theme.colors.fontPrimary;
this.closeButtonFillColorWithTheme = theme.colors.iconSecondary;
}
aboutToAppear() {
let uiContext: UIContext = this.getUIContext();
this.appMaxFontScale = uiContext.getMaxFontScale();
this.listener.on('change', (mediaQueryResult: mediaquery.MediaQueryResult) => {
setTimeout(() => {
this.currentScreenStatus = mediaQueryResult.matches
this.setScrollMaxHeight(undefined, true)
}, 10)
})
}
aboutToDisappear() {
this.listener.off('change')
}
setScrollMaxHeight(maxHeight: number | undefined, forceChange: boolean = false) {
let scrollMaxHeight: number | undefined = undefined;
if (maxHeight) {
scrollMaxHeight = maxHeight!;
} else {
this.applySizeOptions = this.getApplyMaxSize();
let maxHeightInDisplay = this.applySizeOptions?.maxHeight as number;
if (this.applyHeight && !forceChange) {
scrollMaxHeight = Math.min(this.applyHeight, maxHeightInDisplay)
} else {
scrollMaxHeight = maxHeightInDisplay;
}
}
scrollMaxHeight -= this.titleHeight
scrollMaxHeight -= this.buttonHeight
scrollMaxHeight -= this.theme.windows.padding.top!.value
scrollMaxHeight -= (this.theme.button.textMargin.bottom!.value / 2)
scrollMaxHeight -= this.theme.title.margin.bottom!.value
scrollMaxHeight -= (this.theme.windows.padding.bottom!.value -
(this.theme.button.textMargin.bottom!.value / 2))
if (Math.floor(this.textHeight) > Math.floor(scrollMaxHeight + 1)) {
this.scrollMaxHeight = scrollMaxHeight;
} else {
this.scrollMaxHeight = undefined;
}
}
private getLayoutWeight(): number {
let layoutWeight: number
if ((this.icon !== '' && this.icon !== void (0)) ||
(this.title !== '' && this.title !== void (0)) ||
(this.buttons?.[0]?.text !== '' && this.buttons?.[0]?.text !== void (0)) ||
(this.buttons?.[1]?.text !== '' && this.buttons?.[1]?.text !== void (0))) {
layoutWeight = 1
} else {
layoutWeight = 0
}
return layoutWeight
}
private resourceToVp(value: Resource): number {
try {
if ((value as Resource).id !== -1) {
return px2vp(getContext(this).resourceManager.getNumber((value as Resource).id))
} else {
return px2vp(getContext(this)
.resourceManager
.getNumberByName(((value.params as string[])[0]).split('.')[2]))
}
} catch (error) {
return POPUP_DEFAULT_MAXWIDTH
}
}
private toVp(value: Dimension | Length | undefined): number {
let defaultDisplaySync: display.Display | undefined = undefined;
try {
defaultDisplaySync = display.getDefaultDisplaySync()
} catch (error) {
console.error(`Ace PopupV2 getDefaultDisplaySync, error: ${error.toString()}`);
return Number.NEGATIVE_INFINITY;
}
if (value === void (0)) {
return Number.NEGATIVE_INFINITY
}
switch (typeof (value)) {
case 'number':
return value as number
case 'object':
try {
let returnValue = this.resourceToVp(value);
if (returnValue === 0 &&
!isValidResource(getContext(this), value)) {
return Number.NEGATIVE_INFINITY;
}
return returnValue;
} catch (error) {
return Number.NEGATIVE_INFINITY
}
case 'string':
let regex: RegExp = new RegExp('(-?\\d+(?:\\.\\d+)?)_?(fp|vp|px|lpx|%)?$', 'i');
let matches: RegExpMatchArray | null = value.match(regex);
if (!matches) {
return Number.NEGATIVE_INFINITY
}
let length: number = Number(matches?.[1] ?? 0);
let unit: string = matches?.[2] ?? 'vp'
switch (unit.toLowerCase()) {
case 'px':
length = px2vp(length)
break
case 'fp':
length = px2vp(fp2px(length))
break
case 'lpx':
length = px2vp(lpx2px(length))
break
case '%':
length = length / 100 * px2vp(defaultDisplaySync.width);
break
case 'vp':
break
default:
break
}
return length
default:
return Number.NEGATIVE_INFINITY
}
}
private getApplyMaxSize(): ConstraintSizeOptions {
let applyMaxWidth: number | undefined = undefined;
let applyMaxHeight: number | undefined = undefined;
let applyMaxSize: ConstraintSizeOptions | undefined = undefined;
let defaultDisplaySync: display.Display | undefined = undefined;
let maxWidthSize = 400;
try {
defaultDisplaySync = display.getDefaultDisplaySync()
} catch (error) {
console.error(`Ace PopupV2 getDefaultDisplaySync, error: ${error.toString()}`);
this.messageMaxWeight = 400
return applyMaxSize = { maxWidth: 400, maxHeight: 480 }
}
if (this.maxWidth !== undefined) {
if (typeof this.maxWidth === 'number' && this.maxWidth >= 0) {
maxWidthSize = this.maxWidth;
} else if (typeof this.maxWidth === 'number' && this.maxWidth < 0) {
maxWidthSize = POPUP_DEFAULT_MAXWIDTH
} else {
maxWidthSize = this.toVp(this.maxWidth);
}
}
if (px2vp(defaultDisplaySync.width) > maxWidthSize) {
applyMaxWidth = maxWidthSize
} else {
if (defaultDisplaySync.width != 0) {
applyMaxWidth = px2vp(defaultDisplaySync.width)
} else {
// The previewer does not support the display interface to use abnormal values
applyMaxWidth = -1
}
}
if (px2vp(defaultDisplaySync.height) > 480) {
applyMaxHeight = 480
} else {
applyMaxHeight = px2vp(defaultDisplaySync.height) - 40 - 40
}
applyMaxSize = { maxWidth: applyMaxWidth, maxHeight: applyMaxHeight }
this.messageMaxWidth = applyMaxWidth;
this.messageMaxWeight = this.getMessageMaxWeight()
return applyMaxSize
}
private getTitleTextAlign(): TextAlign {
let titleAlign = TextAlign.Start;
if ((Configuration.getLocale().dir === 'rtl') &&
(this.popupDirection === Direction.Auto || this.popupDirection === undefined)) {
titleAlign = TextAlign.End;
}
return titleAlign
}
build() {
Row() {
if (this.icon !== '' && this.icon !== void (0)) {
Image(this.getIconImage())
.direction(this.popupDirection)
.width(this.getIconWidth())
.height(this.getIconHeight())
.margin(this.getIconMargin())
.fillColor(this.getIconFillColor())
.borderRadius(this.getIconBorderRadius())
.draggable(false)
.attributeModifier(this.iconModifier)
}
if (this.title !== '' && this.title !== void (0)) {
Column() {
Flex({ alignItems: ItemAlign.Start }) {
Text(this.getTitleText())
.direction(this.popupDirection)
.flexGrow(1)
.maxLines(2)
.align(Alignment.Start)
.padding(this.getTitlePadding())
.minFontSize(this.getTitleMinFontSize())
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontWeight(this.getTitleFontWeight())
.fontSize(this.getTitleFontSize())
.fontColor(this.getTitleFontColor())
.constraintSize({ minHeight: this.getCloseButtonHeight() })
.textAlign(this.getTitleTextAlign())
.attributeModifier(this.titleModifier)
.maxFontScale(Math.min(this.appMaxFontScale, MAX_FONT_SCALE))
if (this.showClose || this.showClose === void (0)) {
Button() {
SymbolGlyph()
.fontColor([this.getCloseButtonFillColor()])
.fontSize(this.getCloseButtonSymbolSize())
.direction(this.popupDirection)
.attributeModifier(this.theme.closeButton.symbolStyle)
.focusable(true)
.draggable(false)
}
.direction(this.popupDirection)
.width(this.getCloseButtonWidth())
.height(this.getCloseButtonHeight())
.padding(this.getCloseButtonPadding())
.backgroundColor(this.closeButtonBackgroundColor)
.flexShrink(0)
.accessibilityText(this.theme.closeButton.accessibilityMessage)
.responseRegion(this.getCloseBtnResponseRegion())
.onHover((isHover: boolean) => {
if (isHover) {
this.closeButtonBackgroundColor = this.getCloseButtonHoverColor()
} else {
this.closeButtonBackgroundColor = this.getCloseButtonBackgroundColor()
}
})
.onClick(() => {
if (this.onClose) {
this.onClose();
}
})
}
}
.direction(this.popupDirection)
.width('100%')
.margin(this.getTitleMargin())
.onAreaChange((_, rect) => {
this.titleHeight = rect.height as number
this.setScrollMaxHeight(undefined);
})
Scroll() {
Text(this.getMessageText())
.direction(this.popupDirection)
.fontSize(this.getMessageFontSize())
.fontColor(this.getMessageFontColor())
.fontWeight(this.getMessageFontWeight())
.constraintSize({ minHeight: this.getCloseButtonHeight() })
.textAlign(this.getTitleTextAlign())
.attributeModifier(this.messageModifier)
.maxFontScale(Math.min(this.appMaxFontScale, MAX_FONT_SCALE))
.onAreaChange((_, rect) => {
this.textHeight = rect.height as number
this.setScrollMaxHeight(undefined);
})
}
.direction(this.popupDirection)
.width('100%')
.align(Alignment.TopStart)
.padding(this.getMessagePadding())
.scrollBar(BarState.Auto)
.scrollable(ScrollDirection.Vertical)
.constraintSize({ maxHeight: this.scrollMaxHeight })
.edgeEffect(EdgeEffect.Spring, { alwaysEnabled: false })
Flex({ wrap: FlexWrap.Wrap }) {
if (this.buttons?.[0]?.text !== '' && this.buttons?.[0]?.text !== void (0)) {
Button() {
Text(this.getFirstButtonText())
.direction(this.popupDirection)
.maxLines(2)
.focusable(true)
.fontSize(this.getFirstButtonFontSize())
.fontColor(this.getFirstButtonFontColor())
.fontWeight(this.getButtonFontWeight())
.minFontSize(this.getButtonMinFontSize())
.textOverflow({ overflow: TextOverflow.Ellipsis })
.attributeModifier(this.buttons?.[0]?.buttonTextModifier)
.maxFontScale(Math.min(this.appMaxFontScale, MAX_FONT_SCALE))
}
.type(ButtonType.Normal)
.borderRadius($r('sys.float.popup_button_border_radius'))
.direction(this.popupDirection)
.margin(this.getButtonMargin())
.padding(this.getButtonTextPadding())
.backgroundColor(this.firstButtonBackgroundColor)
.onHover((isHover: boolean) => {
if (isHover) {
this.firstButtonBackgroundColor = this.getButtonHoverColor()
} else {
this.firstButtonBackgroundColor = this.getButtonBackgroundColor()
}
})
.onClick(() => {
if (this.buttons?.[0]?.action) {
this.buttons?.[0]?.action();
}
})
.onAreaChange((_, rect) => {
this.firstButtonHeight = rect.height as number;
})
.responseRegion(this.getNormalBtnResponseRegion(this.firstButtonHeight))
}
if (this.buttons?.[1]?.text !== '' && this.buttons?.[1]?.text !== void (0)) {
Button() {
Text(this.getSecondButtonText())
.direction(this.popupDirection)
.maxLines(2)
.focusable(true)
.fontSize(this.getSecondButtonFontSize())
.fontColor(this.getSecondButtonFontColor())
.fontWeight(this.getButtonFontWeight())
.minFontSize(this.getButtonMinFontSize())
.textOverflow({ overflow: TextOverflow.Ellipsis })
.attributeModifier(this.buttons?.[1]?.buttonTextModifier)
.maxFontScale(Math.min(this.appMaxFontScale, MAX_FONT_SCALE))
}
.type(ButtonType.Normal)
.borderRadius($r('sys.float.popup_button_border_radius'))
.direction(this.popupDirection)
.margin(this.getButtonMargin())
.padding(this.getButtonTextPadding())
.backgroundColor(this.secondButtonBackgroundColor)
.onHover((isHover: boolean) => {
if (isHover) {
this.secondButtonBackgroundColor = this.getButtonHoverColor()
} else {
this.secondButtonBackgroundColor = this.getButtonBackgroundColor()
}
})
.onClick(() => {
if (this.buttons?.[1]?.action) {
this.buttons?.[1]?.action();
}
})
.onAreaChange((_, rect) => {
this.secondButtonHeight = rect.height as number;
})
.responseRegion(this.getNormalBtnResponseRegion(this.secondButtonHeight))
}
}
.direction(this.popupDirection)
.margin(this.getButtonTextMargin())
.flexGrow(1)
.onAreaChange((_, rect) => {
if ((this.buttons?.[0]?.text !== '' && this.buttons?.[0]?.text !== void (0)) ||
(this.buttons?.[1]?.text !== '' && this.buttons?.[1]?.text !== void (0))) {
this.buttonHeight = rect.height as number
} else {
this.buttonHeight = 0
}
this.setScrollMaxHeight(undefined);
})
}
.direction(this.popupDirection)
.layoutWeight(this.getLayoutWeight())
} else {
Column() {
Flex().height(0).onAreaChange((_, rect) => {
this.titleHeight = rect.height as number
this.setScrollMaxHeight(undefined);
})
Row() {
Scroll() {
Text(this.getMessageText())
.direction(this.popupDirection)
.fontSize(this.getMessageFontSize())
.fontColor(this.getMessageFontColor())
.fontWeight(this.getMessageFontWeight())
.constraintSize({ maxWidth: this.messageMaxWeight, minHeight: this.getCloseButtonHeight() })
.textAlign(this.getTitleTextAlign())
.attributeModifier(this.messageModifier)
.maxFontScale(Math.min(this.appMaxFontScale, MAX_FONT_SCALE))
.onAreaChange((_, rect) => {
this.textHeight = rect.height as number
this.setScrollMaxHeight(undefined);
})
}
.direction(this.popupDirection)
.layoutWeight(this.getLayoutWeight())
.edgeEffect(EdgeEffect.Spring, { alwaysEnabled: false })
.align(Alignment.TopStart)
.padding(this.getMessagePadding())
.scrollBar(BarState.Auto)
.scrollable(ScrollDirection.Vertical)
.constraintSize({ maxHeight: this.scrollMaxHeight })
if (this.showClose || this.showClose === void (0)) {
Button() {
SymbolGlyph()
.fontColor([this.getCloseButtonFillColor()])
.fontSize(this.getCloseButtonSymbolSize())
.direction(this.popupDirection)
.attributeModifier(this.theme.closeButton.symbolStyle)
.focusable(true)
.draggable(false)
}
.direction(this.popupDirection)
.width(this.getCloseButtonWidth())
.height(this.getCloseButtonHeight())
.padding(this.getCloseButtonPadding())
.backgroundColor(this.closeButtonBackgroundColor)
.flexShrink(0)
.accessibilityText(this.theme.closeButton.accessibilityMessage)
.responseRegion(this.getCloseBtnResponseRegion())
.onHover((isHover: boolean) => {
if (isHover) {
this.closeButtonBackgroundColor = this.getCloseButtonHoverColor()
} else {
this.closeButtonBackgroundColor = this.getCloseButtonBackgroundColor()
}
})
.onClick(() => {
if (this.onClose) {
this.onClose();
}
})
}
}
.direction(this.popupDirection)
.alignItems(VerticalAlign.Top)
Flex({ wrap: FlexWrap.Wrap }) {
if (this.buttons?.[0]?.text !== '' && this.buttons?.[0]?.text !== void (0)) {
Button() {
Text(this.getFirstButtonText())
.direction(this.popupDirection)
.maxLines(2)
.focusable(true)
.fontSize(this.getFirstButtonFontSize())
.fontColor(this.getFirstButtonFontColor())
.fontWeight(this.getButtonFontWeight())
.minFontSize(this.getButtonMinFontSize())
.textOverflow({ overflow: TextOverflow.Ellipsis })
.attributeModifier(this.buttons?.[0]?.buttonTextModifier)
.maxFontScale(Math.min(this.appMaxFontScale, MAX_FONT_SCALE))
}
.type(ButtonType.Normal)
.borderRadius($r('sys.float.popup_button_border_radius'))
.direction(this.popupDirection)
.margin(this.getButtonMargin())
.padding(this.getButtonTextPadding())
.backgroundColor(this.firstButtonBackgroundColor)
.onHover((isHover: boolean) => {
if (isHover) {
this.firstButtonBackgroundColor = this.getButtonHoverColor()
} else {
this.firstButtonBackgroundColor = this.getButtonBackgroundColor()
}
})
.onClick(() => {
if (this.buttons?.[0]?.action) {
this.buttons?.[0]?.action();
}
})
.onAreaChange((_, rect) => {
this.firstButtonHeight = Number(rect.height) as number;
})
.responseRegion(this.getNormalBtnResponseRegion(this.firstButtonHeight))
}
if (this.buttons?.[1]?.text !== '' && this.buttons?.[1]?.text !== void (0)) {
Button() {
Text(this.getSecondButtonText())
.direction(this.popupDirection)
.maxLines(2)
.focusable(true)
.fontSize(this.getSecondButtonFontSize())
.fontColor(this.getSecondButtonFontColor())
.fontWeight(this.getButtonFontWeight())
.minFontSize(this.getButtonMinFontSize())
.textOverflow({ overflow: TextOverflow.Ellipsis })
.attributeModifier(this.buttons?.[1]?.buttonTextModifier)
.maxFontScale(Math.min(this.appMaxFontScale, MAX_FONT_SCALE))
}
.type(ButtonType.Normal)
.borderRadius($r('sys.float.popup_button_border_radius'))
.direction(this.popupDirection)
.margin(this.getButtonMargin())
.padding(this.getButtonTextPadding())
.backgroundColor(this.secondButtonBackgroundColor)
.onHover((isHover: boolean) => {
if (isHover) {
this.secondButtonBackgroundColor = this.getButtonHoverColor()
} else {
this.secondButtonBackgroundColor = this.getButtonBackgroundColor()
}
})
.onClick(() => {
if (this.buttons?.[1]?.action) {
this.buttons?.[1]?.action();
}
})
.onAreaChange((_, rect) => {
this.secondButtonHeight = rect.height as number;
})
.responseRegion(this.getNormalBtnResponseRegion(this.secondButtonHeight))
}
}
.direction(this.popupDirection)
.margin(this.getButtonTextMargin())
.flexGrow(1)
.onAreaChange((_, rect) => {
if ((this.buttons?.[0]?.text !== '' && this.buttons?.[0]?.text !== void (0)) ||
(this.buttons?.[1]?.text !== '' && this.buttons?.[1]?.text !== void (0))) {
this.buttonHeight = rect.height as number
} else {
this.buttonHeight = 0
}
this.setScrollMaxHeight(undefined);
})
}
.direction(this.popupDirection)
.layoutWeight(this.getLayoutWeight())
}
}
.direction(this.popupDirection)
.alignItems(VerticalAlign.Top)
.padding(this.getWindowsPadding())
.constraintSize(this.applySizeOptions)
.constraintSize(this.getApplyMaxSize())
.key(this.applycontentKey)
.onAreaChange((_, rect) => {
this.applyHeight = rect.height as number
this.setScrollMaxHeight(this.applyHeight)
})
}
}