/*
* Copyright (c) Huawei Device Co., Ltd. 2024-2025. All rights reserved.
* 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 lazy { common } from '@kit.AbilityKit';
import lazy { window } from '@kit.ArkUI';
import lottie, { AnimationItem } from '@ohos/lottie';
import lazy { AnimSpecifications } from '../../../animation/AnimSpecifications';
import lazy { FunctionId } from '../../../function/core/functionproperty/FunctionId';
import lazy { OhCombinedState, Unsubscribe, reduxSubscribe } from '../../../redux';
import lazy { CommonConstants } from '../../../statistics/CommonConstants';
import lazy { HiLog } from '../../../../ets/utils/HiLog';
/* instrument ignore file */
const IMAGE_SIZE = '64vp';
const TEXT_EDITABLE_DIALOG = '18.3fp';
const TEXT_SIZE_GLOBAL_EXPOSURE = '8fp';
const MAX_DIALOG = '256vp';
const MIN_DIALOG = '216vp';
const ANGLE_90 = 90;
export declare interface IconItem {
iconRes: ResourceStr;
isEnabled: boolean;
label?: ResourceStr;
isCanvasIcon?: boolean;
canvasPath?: string;
action?: () => void;
isSymbolIcon?: boolean;
}
/**
* 适老化适配,1.75倍数字体下长按控件才会显示的dialog
* */
@CustomDialog
export struct LongPressDialogView {
controller?: CustomDialogController
iconItem: IconItem = {
iconRes: '',
isEnabled: true,
isCanvasIcon: false,
isSymbolIcon: false
}
textRes?: ResourceStr = '';
functionId?: FunctionId = FunctionId.NONE;
isTreasureBox?: boolean = false;
@StorageLink('fontSizeScale') fontSizeScale: number = 1;
@State windowWidth: number = 0;
private mSubscriber: Unsubscribe = {
destroy: () => {
}
};
@State maxLines: number = 1;
verticalScreenLines: number = 6;
horizontalsScreenLines: number = 1;
isOnlyShowText: boolean = false;
@State rotateAngle: number = 0;
@State isShowSemiCollapsed: boolean = false;
@State globalExposureValue: number = 0;
// 针对需要fill color的icon
needFillColor: boolean = false;
mainWindowStage: window.Window | undefined = undefined;
cancel: () => void = () => {
}
confirm: () => void = () => {
}
private antiAliasingSetting: RenderingContextSettings = new RenderingContextSettings(true);
private canvasContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.antiAliasingSetting);
private animationItem: AnimationItem | undefined = undefined;
@Builder
SingleTextBuilder() {
Column() {
Text(this.textRes)
.fontSize(TEXT_EDITABLE_DIALOG)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(2)
.width('100%')
.textAlign(TextAlign.Center)
.fontColor($r('sys.color.ohos_id_color_text_primary_contrary'))
}
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
@Builder
private CanvasItemBuilder() {
Canvas(this.canvasContext)
.width(IMAGE_SIZE)
.height(IMAGE_SIZE)
.onReady((): void => {
this.animationItem = lottie.loadAnimation({
container: this.canvasContext,
renderer: 'canvas',
loop: false,
autoplay: false,
path: this.iconItem.canvasPath,
});
})
.onDisAppear((): void => {
this.animationItem?.destroy();
})
.margin({
top: $r('sys.float.padding_level24'),
bottom: $r('sys.float.padding_level8'),
})
}
@Builder
IconBuilder(needMargin: boolean) {
if (this.iconItem.isSymbolIcon) {
SymbolGlyph(this.iconItem.iconRes as Resource)
.renderingStrategy(SymbolRenderingStrategy.SINGLE)
.fontColor([Color.White])
.draggable(false)
.fontSize(IMAGE_SIZE)
.maxFontScale(1)
} else {
if (this.needFillColor) {
Image(this.iconItem.iconRes)
.width(IMAGE_SIZE)
.height(IMAGE_SIZE)
.objectFit(ImageFit.Contain)
.fillColor(Color.White)
.margin({
top: needMargin ? $r('sys.float.padding_level24') : undefined,
bottom: needMargin ? $r('sys.float.padding_level8') : undefined,
})
} else {
Image(this.iconItem.iconRes)
.width(IMAGE_SIZE)
.height(IMAGE_SIZE)
.objectFit(ImageFit.Contain)
.margin({
top: needMargin ? $r('sys.float.padding_level24') : undefined,
bottom: needMargin ? $r('sys.float.padding_level8') : undefined,
})
}
}
}
@Builder
globalExposureBuilder() {
Column() {
Stack() {
Text((this.globalExposureValue > 0 ? '+' : '') + this.globalExposureValue?.toFixed(1))
.fontSize(TEXT_SIZE_GLOBAL_EXPOSURE)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(this.maxLines)
.width('100%')
.textAlign(TextAlign.Center)
.margin({ bottom: 16 })
.fontColor($r('sys.color.ohos_id_color_text_primary_contrary'))
.visibility((this.globalExposureValue === 0 && this.isTreasureBox) ? Visibility.Hidden : Visibility.Visible);
Image(this.iconItem.iconRes)
.width(IMAGE_SIZE)
.height(IMAGE_SIZE)
.objectFit(ImageFit.Contain)
}
.width('100%')
.height(IMAGE_SIZE)
}
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
@Builder
ImageAndTextBuilder() {
Column() {
if (this.iconItem.isCanvasIcon) {
this.CanvasItemBuilder();
} else {
this.IconBuilder(true);
}
Column() {
Text(this.textRes)
.fontSize(TEXT_EDITABLE_DIALOG)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(this.maxLines)
.width('100%')
.textAlign(TextAlign.Center)
.fontColor($r('sys.color.ohos_id_color_text_primary_contrary'))
}
.width('100%')
.padding({
left: $r('sys.float.padding_level4'),
right: $r('sys.float.padding_level4'),
bottom: $r('sys.float.padding_level12'),
})
}
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
@Builder
SingleImageBuilder() {
Column() {
if (this.iconItem.isCanvasIcon) {
Canvas(this.canvasContext)
.width(IMAGE_SIZE)
.height(IMAGE_SIZE)
.onReady((): void => {
this.animationItem = lottie.loadAnimation({
container: this.canvasContext,
renderer: 'canvas',
loop: false,
autoplay: false,
path: this.iconItem.canvasPath,
});
})
.onDisAppear((): void => {
this.animationItem?.destroy();
})
} else {
this.IconBuilder(false);
}
}
.justifyContent(FlexAlign.Center)
}
build() {
Stack() {
Stack() {
if (this.isOnlyShowText) {
this.SingleTextBuilder();
} else if (this.textRes) {
this.ImageAndTextBuilder();
} else {
this.SingleImageBuilder();
}
}.rotate({
angle: this.isShowSemiCollapsed ? ANGLE_90 : this.rotateAngle,
})
.animation({
duration: AnimSpecifications.ANIM_DURATION_300,
curve: Curve.Friction,
iterations: 1,
playMode: PlayMode.Normal,
})
}
.backgroundColor($r('app.color.long_press_dialog_background_color'))
.backgroundBlurStyle(BlurStyle.NONE)
.shadow(ShadowStyle.OUTER_DEFAULT_LG)
.borderRadius($r('sys.float.corner_radius_level10'))
.width(this.fontSizeScale === CommonConstants.TEXT_SIZE_HUGE_LEVEL4 ? MAX_DIALOG : MIN_DIALOG)
.constraintSize({
minHeight: this.fontSizeScale === CommonConstants.TEXT_SIZE_HUGE_LEVEL4 ?
MAX_DIALOG : MIN_DIALOG
})
}
async aboutToAppear(): Promise<void> {
this.mSubscriber = reduxSubscribe((state: OhCombinedState) => {
this.windowWidth = state.get<number>('windowReducer', 'windowWidth');
this.isShowSemiCollapsed = state.get<boolean>('collapsReducer', 'isShowSemiCollapsed');
this.globalExposureValue = state.get<number>('globalExposureReducer', 'globalExposureValue');
this.rotateAngle = state.get<number>('contextReducer', 'rotateAngle');
}, null);
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let height: number = 0;
try {
this.mainWindowStage = context.windowStage.getMainWindowSync();
let properties: window.WindowProperties = this.mainWindowStage.getWindowProperties();
height = properties.windowRect.height;
} catch (err) {
HiLog.e('LongPressDialogView', `getMainWindowSync fail. ${err?.code}`);
height = 0;
}
if (px2vp(height) > this.windowWidth) {
this.maxLines = this.verticalScreenLines;
} else {
this.maxLines = this.horizontalsScreenLines;
}
}
aboutToDisappear(): void {
this.mSubscriber.destroy();
}
}