/**
* Copyright (c) 2024 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 { LogDomain, LogHelper, Trace, CheckEmptyUtils } from '@ohos/basicutils';
import { GlobalContext, IconResourceManager } from '@ohos/frameworkwrapper';
import curves from '@ohos.curves';
import { CommonConstants } from '../constants/CommonConstants';
import { AppIconShadowData } from '../bean/AppIconShadowData';
import ServiceExtensionContext from 'application/ServiceExtensionContext';
import { DockContinuableInfo } from '../bean/DockContinuableInfo';
import { IconPicType } from '@ohos/frameworkwrapper/src/main/ets/resourcemanager/IconInfo';
import { AppItemInfo } from '../bean/AppItemInfo';
const TAG = 'AppIconShadowViewModel';
const log: LogHelper = LogHelper.getLogHelper(LogDomain.HOME, TAG);
export class AppIconShadowViewModel {
private mouseX: number = 0;
private mouseY: number = 0;
private curve1: curves.ICurve = curves.cubicBezierCurve(0.2, 0.0, 0.2, 1.0);
private currentForegroundMaxTranslate: number = 0;
private currentShadowMaxTranslate: number = 0;
private is2DVersion: boolean = false;
private iconSize: number = 0;
private appIconShadowData: AppIconShadowData;
private isContinueItem: boolean = false;
private onAppIconUpdate: Function = (data: DockContinuableInfo): Promise<void> => this.appEventIconUpdate(data);
private desktopContext?: ServiceExtensionContext = GlobalContext.getContext();
private iconLoadCallback?: Function;
public constructor(appIconShadowData: AppIconShadowData) {
this.appIconShadowData = appIconShadowData;
}
public init(is2DVersion: boolean, iconSize: number, isContinueItem: boolean, iconLoadCallback: Function): void {
this.is2DVersion = is2DVersion;
this.iconSize = iconSize;
this.isContinueItem = isContinueItem;
this.iconLoadCallback = iconLoadCallback;
if (this.isContinueItem) {
this.desktopContext?.eventHub.on('continueItemChange', this.onAppIconUpdate);
}
log.showInfo(`init, ${this.is2DVersion},${this.iconSize},${this.isContinueItem}`);
}
public destroy(): void {
if (this.isContinueItem) {
this.desktopContext?.eventHub.off('continueItemChange', this.onAppIconUpdate);
}
log.showInfo(`destroy, ${this.isContinueItem}`);
}
public getAppIconShadowData(): AppIconShadowData {
return this.appIconShadowData;
}
private async appEventIconUpdate(appInfo: DockContinuableInfo): Promise<void> {
if (CheckEmptyUtils.isEmpty(appInfo) || CheckEmptyUtils.isEmpty(appInfo.bundleName) ||
CheckEmptyUtils.isEmpty(appInfo.moduleName) || !this.iconLoadCallback) {
return;
}
log.showInfo(`update bundleName, ${appInfo.bundleName} moduleName, ${appInfo.moduleName} abilityName, ${appInfo.abilityName} iconSize: ${this.iconSize}`);
let icon = await IconResourceManager.getInstance().getIconResourceBySize(appInfo.bundleName, appInfo.moduleName,
appInfo.abilityName, this.iconSize);
const isAdaptiveIcon: boolean = icon.iconType === IconPicType.ADAPTIVE ? true : false;
if (isAdaptiveIcon) {
this.iconLoadCallback(icon, isAdaptiveIcon, appInfo);
} else {
this.iconLoadCallback(icon.combinePic, isAdaptiveIcon, appInfo);
}
}
public onHoverIconHandler(isHover: boolean): void {
if (this.is2DVersion) {
return;
}
log.showInfo(`handleHoverState ${isHover}`);
if (isHover) {
this.onHoverIconInAnimation();
} else {
this.onHoverIconOutAnimation();
}
}
private onHoverIconInAnimation() {
log.showInfo('onHoverIconInAnimation');
let x = this.mouseX;
let y = this.mouseY;
const size = this.iconSize;
const halfSize = size / 2;
let expectAngleX = (y / halfSize - 1) * CommonConstants.BACKGROUND_ROTATE_ANGLE_X;
let expectAngleY = (x / halfSize - 1) * CommonConstants.BACKGROUND_ROTATE_ANGLE_Y;
let angle = Math.sqrt(Math.pow(expectAngleX, 2) + Math.pow(expectAngleY, 2))
let maxDis = Math.sqrt(Math.pow(halfSize, 2) + Math.pow(halfSize, 2));
let curDis = Math.sqrt(Math.pow(x - halfSize, 2) + Math.pow(y - halfSize, 2));
let currentForegroundTranslate = CommonConstants.FOREGROUND_BASE_TRANSLATE *
this.curve1.interpolate((maxDis - curDis) / (maxDis));
this.currentForegroundMaxTranslate = Math.max(this.currentForegroundMaxTranslate, currentForegroundTranslate);
let currentShadowTranslate = CommonConstants.SHADOW_BASE_TRANSLATE *
this.curve1.interpolate((maxDis - curDis) / (maxDis));
this.currentShadowMaxTranslate = Math.max(this.currentShadowMaxTranslate, currentShadowTranslate);
animateTo({
curve: curves.springCurve(0, 1, 322, 30),
}, () => {
this.appIconShadowData.shadowRotateX = expectAngleX;
this.appIconShadowData.shadowRotateY = expectAngleY;
this.appIconShadowData.shadowRotateAngle = angle * CommonConstants.FOREGROUND_ROTATE_ANGLE_MULTIPLE;
this.appIconShadowData.shadowTranslateX = -(x - halfSize) / halfSize * this.currentShadowMaxTranslate;
this.appIconShadowData.shadowTranslateY = -(y - halfSize) / halfSize * this.currentShadowMaxTranslate;
this.appIconShadowData.shadowScale = CommonConstants.FIXED_SHADOW_SCALE;
this.appIconShadowData.shadowOpacity = CommonConstants.SHADOW_OPACITY;
});
}
private onHoverIconOutAnimation(): void {
log.showInfo('onHoverIconOutAnimation');
animateTo({
curve: curves.responsiveSpringMotion(0.35, 0.86, 0.25),
onFinish: () => {
}
}, () => {
this.appIconShadowData.shadowRotateX = 0;
this.appIconShadowData.shadowRotateY = 0;
this.appIconShadowData.shadowRotateAngle = 0;
this.appIconShadowData.shadowTranslateX = 0;
this.appIconShadowData.shadowTranslateY = 0;
this.appIconShadowData.shadowScale = 1.0;
this.appIconShadowData.shadowOpacity = 0;
});
}
public onMouseIconHandler(event: MouseEvent): void {
if (this.is2DVersion) {
return;
}
Trace.start('onMouseIconHandler');
let x = event.x;
let y = event.y;
const size = this.iconSize;
const halfSize = size / 2;
let expectAngleX = (y / halfSize - 1) * CommonConstants.BACKGROUND_ROTATE_ANGLE_X;
let expectAngleY = (x / halfSize - 1) * CommonConstants.BACKGROUND_ROTATE_ANGLE_Y;
let angle = Math.sqrt(Math.pow(expectAngleX, 2) + Math.pow(expectAngleY, 2))
let maxDis = Math.sqrt(Math.pow(halfSize, 2) + Math.pow(halfSize, 2));
let curDis = Math.sqrt(Math.pow(x - halfSize, 2) + Math.pow(y - halfSize, 2));
let currentForegroundTranslate = CommonConstants.FIXED_FOREGROUND_BASE_TRANSLATE *
this.curve1.interpolate((maxDis - curDis) / (maxDis));
this.currentForegroundMaxTranslate = Math.max(this.currentForegroundMaxTranslate, currentForegroundTranslate);
let currentShadowTranslate = CommonConstants.FIXED_SHADOW_BASE_TRANSLATE *
this.curve1.interpolate((maxDis - curDis) / (maxDis));
this.currentShadowMaxTranslate = Math.max(this.currentShadowMaxTranslate, currentShadowTranslate);
animateTo({
curve: curves.springCurve(0, 1, 322, 30),
}, () => {
this.appIconShadowData.shadowRotateX = expectAngleX;
this.appIconShadowData.shadowRotateY = expectAngleY;
this.appIconShadowData.shadowRotateAngle = angle * CommonConstants.FOREGROUND_ROTATE_ANGLE_MULTIPLE;
this.appIconShadowData.shadowTranslateX = -(x - halfSize) / halfSize * this.currentShadowMaxTranslate;
this.appIconShadowData.shadowTranslateY = -(y - halfSize) / halfSize * this.currentShadowMaxTranslate;
});
Trace.end('onMouseIconHandler');
}
public onIconShadowAnimateInForPc(event: MouseEvent): void {
if (this.is2DVersion) {
return;
}
if (this.appIconShadowData.shadowScale !== CommonConstants.FIXED_SHADOW_SCALE &&
this.appIconShadowData.shadowOpacity !== CommonConstants.PC_SHADOW_OPACITY) {
animateTo({
curve: curves.springCurve(0, 1, 322, 30),
}, () => {
this.appIconShadowData.shadowScale = CommonConstants.FIXED_SHADOW_SCALE;
this.appIconShadowData.shadowOpacity = CommonConstants.PC_SHADOW_OPACITY;
});
}
this.onMouseIconHandler(event);
}
public onIconShadowAnimateOutForPc(): void {
this.onHoverIconOutAnimation();
}
public getPcResidentIconName(item: AppItemInfo) {
let iconName: string = '';
switch (item.abilityName) {
case CommonConstants.APPCENTER_ABILITY:
iconName = 'adaptive_appcenter_foreground';
break;
case CommonConstants.RECENT_ABILITY:
iconName = 'adaptive_multitask_foreground';
break;
case CommonConstants.RECYCLE_BIN_ABILITY:
iconName = 'adaptive_recycle_bin_foreground';
break;
default:
break;
}
return iconName;
}
}