/**
* 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 {
AppItemInfo,
AppStatus,
CardItemInfo,
CloseAppManager,
FormCenterViewManager,
FormModel,
LayoutViewModel,
ReceiveEventInfo,
ShortcutViewModel,
AppCenterModel,
AppLockUtils
} from '@ohos/launchercommon';
import { LogDomain, LogHelper, CheckEmptyUtils, StartType, SingleContext } from '@ohos/basicutils'
import { windowManager } from '@ohos/componentdrag'
import { SCBConstants, DragConstants } from '@ohos/commonconstants'
import { SCBPropertyChangeReason, SCBScreenProperty, SCBScreenSessionManager } from '@ohos/windowscene'
import { GlobalContext, localEventManager, HiSysEventUtil, ApsUtils, ViewType } from '@ohos/frameworkwrapper'
import { SCBSceneSessionManager } from '@ohos/windowscene';
import { RTLUtil } from '@ohos/componenthelper';
import type ctx from '@ohos.app.ability.common';
import { StyleConstants } from '@ohos/launchercommon';
import { CommonConstants } from '@ohos/launchercommon';
import { EventConstants } from '@ohos/launchercommon';
import { UninstallDialog } from '@ohos/launchercommon/src/main/ets/uicomponents/UninstallDialog';
import { MenuInfo } from '@ohos/launchercommon';
import { StartSubtype } from '@ohos/launchercommon';
import { PageDesktopViewModel } from '@ohos/pagedesktop';
import { FormManagerDialog } from '@ohos/form';
import { FormCenterViewParam } from '@ohos/launchercommon/src/main/ets/manager/FormCenterViewManager';
import { AppCenterAppGrid } from './AppCenterAppGrid';
import { AppCenterGridStyleConfig } from '../common/AppCenterGridStyleConfig';
import { AppGridPresenter } from '../common/presenter/AppGridPresenter';
import { AppLayoutInfo } from '../common/viewmodel/AppLayoutInfo';
import { AppCenterViewModel } from '../common/viewmodel/AppCenterViewModel';
import { AppListPresenter } from '../common/presenter/AppListPresenter';
import { AppCenterDragMgr } from '../controller/AppCenterDragMgr';
import AppGridLayoutUtil from '../common/util/AppGridLayoutUtil';
import AppGridLayoutCacheManager from '../common/cache/AppGridLayoutCacheManager';
import { AppCenterDropFrame } from './AppCenterDropFrame';
import { curves } from '@kit.ArkUI';
// import apsManager from '@hms.graphic.apsManager';
import { AppCenterSearchResultTask } from '../common/model/AppCenterSearchResultTask';
import { FoldedDeviceAcViewModel, FoldStatusChangeEvent, SCBFoldedState } from '../folded/FoldedDeviceAcViewModel';
import FeatureConstants from '../common/constants/FeatureConstants';
import { APP_CENTER_SWIPER_KEY } from '../constants/LayoutConstants';
import { LazyDataSource } from '@ohos/launchercommon/src/main/ets/uicomponents/LazyDataSource';
const TAG = 'AppGridLayout';
const log = LogHelper.getLogHelper(LogDomain.HOME, TAG);
const COLOR_ARROW = '#19ffffff';
const COLOR_ARROW_PRESS = '#26ffffff';
const SIZE_ARROW = '32vp';
const SIZE_ARROW_BACKGROUND = '40vp';
const INDICATOR_MARGIN_BOTTOM = '54';
const SWAP_PAGE_DELAY: number = 1000;
const SWAP_PAGE_DELAY_HPR: number = 700;
const MOVE_NEXT_DELAY: number = 500;
const HOT_EREA_ADJUSTMENT:number = 50;
const CROSS_SCREEN: string = 'crossScreen';
const UNINSTALLDIALOG_FOLDED_B_APP: Offset = { dx: 0, dy: -465 }; // hopper 折叠屏无磁吸键盘时B屏弹窗,在B屏
const UNINSTALLDIALOG_FOLDED_C_APP: Offset = { dx: 0, dy: 465 };
const UNINSTALLDIALOG_FOLDED_B_KEYBOARD_APP: Offset = { dx: 0, dy: 0 }; // hopper 折叠屏时磁吸键盘B屏弹窗,在B屏
const UNFOLDED_VERTICAL_INDICATOR_HEIGHT: number = 875;
const UNFOLDED_HORIZONAL_INDICATOR_HEIGHT: number = 674;
const DEFAULT_INDICATOR_HEIGHT: number = 435;
const DEFAULT_INDICATOR_RIGHT_HPR: number = 67;
const DEFAULT_INDICATOR_RIGHT_HORIZONTAL_HPR: number = 72;
const INDICATOR_ANIM_DURATION = 400;
@Component
export struct AppGridLayout {
@State
columns: number = StyleConstants.DEFAULT_APP_GRID_COLUMN;
@State
rows: number = StyleConstants.DEFAULT_APP_GRID_ROW;
@Link screenProp: SCBScreenProperty;
@Prop singleContext?: SingleContext;
@State pages: number[] = [];
@StorageLink('appCenterLayoutInfo') @Watch('appLayoutInfoChange')
appGridList: AppLayoutInfo[] = [];
@StorageLink('openAppCenterPageIndex')
pageIndex: number = 0;
private searchPageIndex: number = 0;
@StorageLink('isDropAnimationGoing') @Watch('onDropAnimationStatusChanged') isDropAnimationGoing: boolean = false;
private appGridPresenter: AppGridPresenter | null = null;
private gridStyleConfig: AppCenterGridStyleConfig | undefined = undefined;
private mLayoutVM: LayoutViewModel = LayoutViewModel.getInstance(this.singleContext);
private selectItem: AppItemInfo | null = null;
private clearForm?: Function;
private readonly mFormModel: FormModel = FormModel.getInstance();
@StorageLink('isAppCenterShow')
@Watch('onAppCenterShow') isAppCenterShow: boolean = false;
@Link @Watch('onSearchInputChange')
searchInputText: string;
@State isShowEmptyStatus: boolean = false;
@State arrowLeftIsHover: boolean = false;
@State arrowRightIsHover: boolean = false;
private swiperController: SwiperController = new SwiperController();
private sreachSwiperController: SwiperController = new SwiperController();
@Prop isGainFocus: boolean = false;
@State showDropFrame: boolean = true;
private apsApsSessionId: string = '';
private swapPageDelayTime: number = 0;
private isCrossScreenTimerId: boolean = false;
@State indicatorHeightForFoldedDevice: number = this.getIndicatorHeight();
@State searchAppPageList?: LazyDataSource<AppLayoutInfo> = new LazyDataSource<AppLayoutInfo>();
@State updateTag: boolean = false;
@State swiperEnabled: boolean = true;
@State needTwoArrow: boolean = true;
@State swiperItemSpace: number = 0;
@State swiperDsCount: number = 1;
@State swiperMultiPages: boolean = false;
@State swiperVertical: boolean = false;
@State swiperPaddingBottom: number = 0;
@State columnHeightOfAppCenter: Length = StyleConstants.PERCENTAGE_100;
private appItemPosX: number[] = [];
private rtlAppItemPosX: number[] = [];
private appItemPosY: number[] = [];
private appItemOpacity: number[] = [];
private bkOpacity: number = 0;
swiperPaddingTop = 0;
private swiperCachedCount: number = 1;
private movePageTimerId: number | undefined = undefined;
// 搜索任务map key:index value:cancelFlag
private searchTask: Map<string, boolean> = new Map();
private dialogController: CustomDialogController = this.getDialogController();
private dialogHalfFoldedBController: CustomDialogController = this.getDialogController(UNINSTALLDIALOG_FOLDED_B_APP);
private dialogHalfFoldedCController: CustomDialogController = this.getDialogController(UNINSTALLDIALOG_FOLDED_C_APP);
private dialogHalfFoldedBKeyBoardController: CustomDialogController =
this.getDialogController(UNINSTALLDIALOG_FOLDED_B_KEYBOARD_APP);
private currentScreenHeight: number = this.screenProp.height;
private currentScreenWidth: number = this.screenProp.width;
@Link @Watch('handleEnterKeyEvent') isEnterKeyEvent: boolean;
@State lazyAppLayPageInfo: LazyDataSource<AppLayoutInfo> = new LazyDataSource<AppLayoutInfo>();
private handleEnterKeyEvent(): void {
if (!this.isEnterKeyEvent) {
log.showInfo('handleEnterKeyEvent-not enter key');
return;
}
this.isEnterKeyEvent = false;
if (!this.searchInputText || this.searchAppPageList?.totalCount() !== 1) {
log.showInfo(`handleEnterKeyEvent-two pages-${this.searchInputText}`);
return;
}
if (this.searchAppPageList?.getData(0).pageInfo.length !== 1) {
log.showInfo(`handleEnterKeyEvent-two apps-${this.searchInputText}`);
return;
}
let appItemInfo: AppItemInfo = this.searchAppPageList.getData(0).pageInfo[0];
log.showInfo(`handleEnterKeyEvent-${this.searchInputText}`);
if (AppCenterViewModel.getInstance().isChangedAfterEnter(this.searchInputText)) {
log.showInfo('handleEnterKeyEvent-enter key but not for open app');
AppCenterViewModel.getInstance().updateSearchInputTextBeforeEnter(this.searchInputText);
return;
}
this.appGridItemClickCallback(appItemInfo);
AppCenterViewModel.getInstance().updateSearchInputTextBeforeEnter(this.searchInputText);
}
public getDialogController(offset?: Offset): CustomDialogController {
let dialogController: CustomDialogController = new CustomDialogController({
builder: UninstallDialog({
singleContext: this.singleContext,
cancel: () => {
this.doCloseUninstallDialog();
},
confirm: () => {
this.onAccept()
},
dialogName: this.getUninstallDialog(),
isFromAppCenter: true,
isBusinessStyle: true,
bundleName: this.selectItem?.bundleName
}),
cancel: () => {
},
autoCancel: true,
customStyle: true,
showInSubWindow: true,
offset: offset ?? { dx: 0, dy: 0 }
});
return dialogController;
}
private openUninstallDialog(item: AppItemInfo): void {
if (item === undefined || item === null) {
log.showInfo(`item is null.`);
return;
}
if (!FoldedDeviceAcViewModel.getInstance().isFoldedDevice()) {
this.dialogController.open();
return;
}
// HOPPER折叠屏,磁吸键盘,在B屏显示子窗
if (FoldedDeviceAcViewModel.getInstance().isKeyboardOnCSide()) {
this.dialogHalfFoldedBKeyBoardController.open();
return;
}
// HOPPER折叠屏,无磁吸键盘,在B屏显示子窗
if (FoldedDeviceAcViewModel.getInstance().isHalfFolded()) {
if (item.page !== undefined && item.page % 2 === 0) {
this.dialogHalfFoldedBController.open();
return;
}
this.dialogHalfFoldedCController.open();
return;
}
if (FoldedDeviceAcViewModel.getInstance().isHalfFoldedVirtualKeyboard()) {
this.dialogHalfFoldedBController.open();
return;
}
this.dialogController.open();
}
private doCloseUninstallDialog(): void {
this.dialogController.close();
this.dialogHalfFoldedBController.close();
this.dialogHalfFoldedCController.close();
this.dialogHalfFoldedBKeyBoardController.close();
}
private readonly foldStateChangeListener: ReceiveEventInfo = {
onReceiveEvent: (event: string, params: FoldStatusChangeEvent): void => {
log.showInfo(`hopper state change event received: ${event}, params: ${JSON.stringify(params)}`);
let cs: number = params.curState;
let ts: number = params.tarState;
this.doIndicatorAnimationForFoldedDevice();
AppGridLayoutUtil.setExtraPaddingTopOffset(
FoldedDeviceAcViewModel.getInstance(this.screenProp.screenId).getSwiperItemSpace(), this.screenProp.screenId);
this.resetSwiperDsCount(ts);
this.resetColumnHeightOfAppCenter();
if (cs === SCBFoldedState.UNFOLDED_VERTICAL && ts === SCBFoldedState.UNFOLDED_HORIZONTAL ||
cs === SCBFoldedState.UNFOLDED_HORIZONTAL && ts === SCBFoldedState.UNFOLDED_VERTICAL) {
this.refreshAppGridLayout();
AppGridLayoutCacheManager.getInstance().sortAllData();
this.updateLazyAppPageInfo(AppGridLayoutCacheManager.getInstance().getAppGridLayoutItemList());
AppCenterDragMgr.getInstance().updateAppCenterLayoutInfo(FeatureConstants.AC_SCENE_LANDSCAPE_PORTRAIT_SWITCH);
log.showInfo(`hopper state change-${this.lazyAppLayPageInfo.totalCount()}`);
}
if (ts === SCBFoldedState.HALF_FOLDED) {
if (this.gridStyleConfig) {
FoldedDeviceAcViewModel.getInstance(
this.screenProp.screenId).recalculateAcDraggableAreaBottom(this.gridStyleConfig);
}
AppCenterDragMgr.getInstance().updateAppCenterDragData(this.screenProp.screenId, true,
this.screenProp.width, this.screenProp.height);
log.showInfo(`hopper state changed to half-folded`);
}
this.doCloseUninstallDialog();
log.showInfo(`hopper state change - ${cs}-${ts}`);
}
};
formManagerDialogController: CustomDialogController = new CustomDialogController({
builder: FormManagerDialog({
singleContext: this.singleContext,
cancel: (callback?: Function) => {
// delete all form
if (callback !== undefined) {
this.clearForm = callback;
} else {
log.showError('FormManagerDialog callback error'); // 维测日志
}
},
confirm: (formCardItem: CardItemInfo) => {
// add form to desktop
log.showInfo(`createCardToDeskTop formCardItem: ${JSON.stringify(formCardItem)}`);
PageDesktopViewModel.getInstance(this.singleContext).createCardToDeskTop(formCardItem);
// delete other form
},
bundleName: AppStorage.get<AppItemInfo>('formAppInfo')?.bundleName,
appName: AppStorage.get<AppItemInfo>('formAppInfo')?.appName,
appLabelId: AppStorage.get<AppItemInfo>('formAppInfo')?.applicationLabelId,
isPcEditCard: AppStorage.get<string>('device') !== CommonConstants.DEFAULT_DEVICE_TYPE
}),
cancel: this.cancelFormDialog,
autoCancel: true,
customStyle: true,
showInSubWindow: true
});
private openAppEnable: boolean = true;
public aboutToAppear(): void {
log.showInfo('aboutToAppear');
this.initSwapPageDelayTime();
this.appGridPresenter = AppGridPresenter.getInstance();
if (this.screenProp.screenId === 0) {
this.appGridPresenter.loadAppCenterData();
}
// 生命周期开始时appGridList,转成LazyDataSource类型,避免扩展屏应用中心图标为空
this.updateLazyAppPageInfo(this.appGridList);
this.gridStyleConfig = AppCenterViewModel.getInstance().getAppGridStyleConfig(this.screenProp.screenId);
AppCenterViewModel.getInstance().setSwiperController(this.swiperController, this.screenProp.screenId);
LayoutViewModel.getInstance(this.singleContext)
.registerRefreshLayoutCallback(this.screenProp.screenId, this.refreshAppGridLayout);
SCBScreenSessionManager.getInstance()
.registerScreenPropertyChangeCallbacks(this.onScreenPropertyChange, this.screenProp.screenId);
this.registerEventHub();
this.refreshAppGridLayout();
if (FoldedDeviceAcViewModel.getInstance().isFoldedDevice()) {
this.initFoldDevice();
localEventManager.registerEventListener(this.foldStateChangeListener,
[FoldedDeviceAcViewModel.FOLD_STATE_CHANGE_EVT_NAME]);
}
}
aboutToDisappear(): void {
log.showInfo('aboutToDisappear');
this.unRegisterEventHub();
LayoutViewModel.getInstance(this.singleContext)
.unregisterRefreshLayoutCallback(this.screenProp.screenId, this.refreshAppGridLayout);
if (FoldedDeviceAcViewModel.getInstance().isFoldedDevice()) {
localEventManager.unregisterEventListener(this.foldStateChangeListener);
}
SCBScreenSessionManager.getInstance()
.unRegisterScreenPropertyChangeCallbacks(this.onScreenPropertyChange, this.screenProp.screenId);
// 在生命周期结束之后进行数据清理,避免OOM
this.lazyAppLayPageInfo?.clear();
this.searchAppPageList?.clear();
this.doCloseUninstallDialog();
}
onScreenPropertyChange = (screenProperty: SCBScreenProperty, reason: SCBPropertyChangeReason) => {
if (this.screenProp.screenId !== screenProperty.screenId) {
log.showInfo(`screen id not equal: ${this.screenProp.screenId} ${screenProperty.screenId}`);
return;
}
if (this.currentScreenHeight === screenProperty.height &&
this.currentScreenWidth === screenProperty.width) {
log.showInfo('screen width or height not change');
return;
}
if (FoldedDeviceAcViewModel.getInstance().isFoldedDevice()) {
log.showInfo('fold device');
return;
}
if (!this.mLayoutVM) {
this.mLayoutVM = LayoutViewModel.getInstance(this.singleContext);
}
this.currentScreenHeight = screenProperty.height;
this.currentScreenWidth = screenProperty.width;
this.gridStyleConfig?.initConfig(screenProperty.screenId, true, screenProperty.width, screenProperty.height);
this.initGridPosition(screenProperty.screenId);
// 更新应用中心拖拽数据
AppCenterDragMgr.getInstance().updateAppCenterDragData(
screenProperty.screenId, true, screenProperty.width, screenProperty.height);
log.showInfo(`onScreenPropertyChange ${screenProperty.width} ${screenProperty.height}`);
}
onAppCenterShow(): void {
log.showInfo(`onAppCenterShow ${this.isAppCenterShow}`);
if (!this.isAppCenterShow) {
this.swiperEnabled = false;
return;
} else {
this.swiperEnabled = true;
}
this.openAppEnable = true;
}
private getViewType(): ViewType {
return this.isMainScreen(this.screenProp.screenId) ? ViewType.APP_CENTER : ViewType.APP_CENTER_EXT;
}
private isMainScreen(screenId: number): boolean {
return SCBSceneSessionManager.getInstance().mainScreenId === screenId;
}
private initFoldDevice(): void {
this.needTwoArrow = false;
this.swiperItemSpace = 20;
this.swiperDsCount = 2;
this.swiperMultiPages = true;
this.swiperVertical = true;
this.swiperCachedCount = 1;
this.resetSwiperDsCount(FoldedDeviceAcViewModel.getInstance().getCurrentFoldState());
// 只有主屏才会走的场景,折叠态重启开机
if (FoldedDeviceAcViewModel.getInstance().isHalfFolded()) {
AppGridLayoutUtil.setExtraPaddingTopOffset(
FoldedDeviceAcViewModel.getInstance().getSwiperItemSpace(), this.screenProp.screenId);
}
}
private resetSwiperDsCount(cs: number): void {
if (cs === SCBFoldedState.UNFOLDED_VERTICAL) {
log.showInfo(`hopper state change - to unfolded_vertical`);
this.swiperDsCount = 2;
this.swiperMultiPages = true;
} else if (cs === SCBFoldedState.UNFOLDED_HORIZONTAL) {
log.showInfo(`hopper state change - to unfolded_horizontal`);
this.swiperDsCount = 2;
this.swiperMultiPages = true;
} else if (cs === SCBFoldedState.HALF_FOLDED) {
log.showInfo(`hopper state change - to half_folded`);
this.swiperDsCount = 2;
this.swiperMultiPages = true;
} else {
log.showInfo(`hopper state change - to other state`);
this.swiperDsCount = 1;
this.swiperMultiPages = false;
}
log.showInfo(`hopper curstate - ${cs}, setSwiperDsCount to ${this.swiperDsCount}`);
}
private refreshAppGridLayout = () => {
this.gridStyleConfig?.initConfig(this.screenProp.screenId, true, this.screenProp.width, this.screenProp.height);
this.initGridPosition(this.screenProp.screenId);
// 更新应用中心拖拽数据
AppCenterDragMgr.getInstance().updateAppCenterDragData(
this.screenProp.screenId, true, this.screenProp.width, this.screenProp.height);
}
private getUninstallDialog(): string | Resource {
if (this.selectItem?.appIndex !== undefined && this.selectItem?.appIndex > 0) {
return $r('app.string.is_delete', this.selectItem?.appName)
} else {
return $r('app.string.isUninstall', this.selectItem?.appName)
}
}
private getPaddingTop(): number {
if (!this.gridStyleConfig) {
log.showInfo('getPaddingTop-cfg null');
return 0;
}
if (FoldedDeviceAcViewModel.getInstance().isFoldedDevice()) {
return this.gridStyleConfig.mAppCenterMarginTop + FoldedDeviceAcViewModel.getInstance(
this.screenProp.screenId).getAcGridPaddingTop();
} else {
return this.gridStyleConfig.mAppCenterMarginTop;
}
}
private getItemSpace(): number {
if (FoldedDeviceAcViewModel.getInstance().isFoldedDevice()) {
return FoldedDeviceAcViewModel.getInstance(this.screenProp.screenId).getSwiperItemSpace();
} else {
return 0;
}
}
private initGridPosition(screenId: number = 0): void {
if (this.gridStyleConfig) {
log.showInfo(`initGridPosition-${JSON.stringify(this.gridStyleConfig)} ${screenId}`);
AppGridLayoutUtil.initGridPositionRound({
// 配置整数
paddingLeft: this.gridStyleConfig.mAppCenterMarginLeft,
// 配置整数
paddingTop: this.getPaddingTop(),
// 计算整数
row: this.gridStyleConfig.mRows,
// 计算整数
column: this.gridStyleConfig.mColumns,
// 配置整数
rowGap: this.gridStyleConfig.mRowsGap,
// 配置整数
columnGap: this.gridStyleConfig.mColumnsGap,
// 计算值,不确保整数
gridWidth: this.gridStyleConfig.mGridWidth,
// 计算值,不确保整数
gridHeight: this.gridStyleConfig.mGridHeight
}, {
paddingTop: this.gridStyleConfig.mRowsGap / StyleConstants.DEFAULT_2,
paddingBottom: this.gridStyleConfig.mRowsGap / StyleConstants.DEFAULT_2,
paddingLeft: this.gridStyleConfig.mColumnsGap / StyleConstants.DEFAULT_2,
paddingRight: this.gridStyleConfig.mColumnsGap / StyleConstants.DEFAULT_2
}, this.getItemSpace(), screenId);
}
}
registerEventHub(): void {
this.getContext()?.eventHub.on(DragConstants.WHITE_BOX_CHANGE_EVENT, (state: boolean) => {
AppCenterDragMgr.getInstance().setWhiteBoxState(state);
AppCenterDragMgr.getInstance().initCurrentMouse();
});
}
unRegisterEventHub(): void {
this.getContext()?.eventHub.off(DragConstants.WHITE_BOX_CHANGE_EVENT);
}
private onDropAnimationStatusChanged(): void {
log.showInfo(`onDropAnimationStatusChanged isDropAnimationGoing ${this.isDropAnimationGoing} isAnimating ${AppCenterDragMgr.getInstance().isAnimating()}`);
if (!this.isDropAnimationGoing && AppCenterDragMgr.getInstance().isAnimating()) {
AppCenterDragMgr.getInstance().onDropAnimationEnd(false);
}
}
private cancelFormDialog() {
log.showInfo('cancel form dialog');
this.clearForm?.();
}
private appLayoutInfoChange(): void {
log.showInfo('appLayoutInfoChange start');
this.pages = AppGridLayoutCacheManager.getInstance().getPages();
this.appGridList?.forEach((pageInfo: AppLayoutInfo) => {
pageInfo?.pageInfo?.forEach((itemInfo: AppItemInfo) => {
log.showInfo(`appLayoutInfoChange: bundleName: ${itemInfo?.bundleName}, column: ${itemInfo?.column}, row: ${itemInfo?.row}, page: ${itemInfo?.page}`);
});
});
log.showInfo(`appLayoutInfoChange end. appGridList.length: ${this.appGridList?.length}, ${this.pages}`);
// 原appGridList转成datalazysource类型
this.updateLazyAppPageInfo(this.appGridList);
}
/**
* 延迟翻页
* @param callback
*/
private movePageTimer(callback: () => void, reason?: string) {
if (reason === CROSS_SCREEN) {
if ((this.movePageTimerId) && !this.isCrossScreenTimerId) {
this.clearMovePageTimer();
this.isCrossScreenTimerId = true;
}
if (!this.movePageTimerId) {
this.movePageTimerId = setTimeout(() => {
if (!AppCenterDragMgr.getInstance().isAnimating()) {
callback();
}
this.movePageTimerId = undefined;
this.isCrossScreenTimerId = false;
}, MOVE_NEXT_DELAY);
}
} else {
if (!this.movePageTimerId) {
this.movePageTimerId = setTimeout(() => {
if (!AppCenterDragMgr.getInstance().isAnimating()) {
callback();
}
this.movePageTimerId = undefined;
}, MOVE_NEXT_DELAY);
}
}
}
/**
* 清除定时器
*/
private clearMovePageTimer(): void {
if (this.movePageTimerId) {
clearTimeout(this.movePageTimerId);
this.movePageTimerId = undefined;
}
}
private getContext(): ctx.ServiceExtensionContext {
return GlobalContext.getContext();
}
private onAccept(): void {
if (this.selectItem == null) {
return;
}
let bundleName: string = this.selectItem.bundleName === undefined ? '' : this.selectItem.bundleName;
let isUninstallAble: boolean = this.selectItem.isUninstallAble === undefined ? false :
this.selectItem.isUninstallAble;
let appIndex: number = this.selectItem?.appIndex ?? 0;
this.appGridPresenter?.uninstallApp(bundleName, isUninstallAble, appIndex);
this.doCloseUninstallDialog();
this.searchInputText = '';
}
private buildMenuInfoList(appInfo: AppItemInfo): MenuInfo[] {
let menuInfoList = new Array<MenuInfo>();
if (appInfo === undefined) {
return menuInfoList;
}
let bundleName: string = appInfo.bundleName === undefined ? '' : appInfo.bundleName;
let open = new MenuInfo();
open.menuType = CommonConstants.MENU_TYPE_FIXED;
open.menuImgSrc = '/common/pics/ic_public_add_norm.svg';
open.menuText = $r('app.string.app_menu_open');
open.onMenuClick = (params: Map<string, Object>) => {
CloseAppManager.getInstance().setStartAppType(StartType.APP_CENTER_APP, undefined,
CommonConstants.APPCENTER_ICON_EXTRA_ID);
CloseAppManager.getInstance().setStartAppSubtype(StartSubtype.ICON_FROM_APP_CENTER);
let abilityName: string = appInfo.abilityName === undefined ? '' : appInfo.abilityName;
let moduleName: string = appInfo.moduleName === undefined ? '' : appInfo.moduleName;
params.set(SCBConstants.IS_START_BY_LAUNCHTYPE_CONFIG, true);
if (appInfo?.enableNewAppInstance) {
log.showInfo('is multiInstance:' + bundleName);
params.set(SCBConstants.CREATE_NEW_APP_INSTANCE_KEY, true);
}
params.set(SCBConstants.OPEN_IN_NEW_WINDOW, true);
if (appInfo?.appIndex !== undefined && appInfo?.appIndex > 0) {
params.set(SCBConstants.START_APP_CLONE_INDEX, appInfo?.appIndex);
}
this.appGridPresenter?.jumpTo(abilityName, bundleName, moduleName, params, this.screenProp.screenId);
if (GlobalContext.getInstance().hasObject('hideAppCenterWithAnimation')) {
let hideAppCenterWithAnimation = (GlobalContext.getInstance()
.getObject('hideAppCenterWithAnimation')) as Function;
hideAppCenterWithAnimation(this.screenProp.screenId);
}
windowManager.hideWindow(windowManager.RECENT_WINDOW_NAME);
log.showInfo('click menu item add to open entry, bundleName = ' + appInfo.bundleName);
};
menuInfoList.push(open);
const formInfoList = this.mFormModel.getAppItemFormInfo(appInfo.bundleName as string,
item => this.mFormModel.isFormCenterSupportCard(item));
// 后续和副屏桌面工作区需求同步上
if (this.screenProp.screenId === SCBSceneSessionManager.getInstance().mainScreenId) {
if (!CheckEmptyUtils.isEmptyArr(formInfoList)) {
let addFormToDeskTopMenu = new MenuInfo();
addFormToDeskTopMenu.menuType = CommonConstants.MENU_TYPE_FIXED;
addFormToDeskTopMenu.menuImgSrc = '/common/pics/ic_form_center.svg';
addFormToDeskTopMenu.menuText = $r('app.string.add_form_to_desktop');
addFormToDeskTopMenu.onMenuClick = (appParams?: Map<string, Object>): void => {
log.showInfo(`add_form AppCenter`);
let param: FormCenterViewParam = new FormCenterViewParam();
param.bundleName = appInfo.bundleName;
param.entrancePosition = FormCenterViewManager.getInstance().getEntrancePos(appInfo);
FormCenterViewManager.getInstance().openFormCenterView(param);
let hideAppCenterWithAnimation = (GlobalContext.getInstance()
.getObject('hideAppCenterWithAnimation')) as Function;
hideAppCenterWithAnimation(this.screenProp.screenId);
};
menuInfoList.push(addFormToDeskTopMenu);
}
}
let addToDockMenu = new MenuInfo();
addToDockMenu.menuType = CommonConstants.MENU_TYPE_FIXED;
addToDockMenu.menuImgSrc = '/common/pics/ic_public_copy.svg';
addToDockMenu.menuText = $r('app.string.app_center_menu_add_dock');
addToDockMenu.onMenuClick = () => {
HiSysEventUtil.reportEventById(bundleName, 'appCenter add to dock');
if (typeof (appInfo.typeId) === 'undefined') {
// 应用中心typeId的默认为app
appInfo.typeId = CommonConstants.TYPE_APP;
}
log.showInfo(`click menu item add to Dock entry, bundleName = ${appInfo.bundleName} appindex:${appInfo.appIndex}` );
localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_DOCK_ITEM_ADD, appInfo);
};
menuInfoList.push(addToDockMenu);
// 后续和副屏桌面工作区需求同步上
if (this.screenProp.screenId === SCBSceneSessionManager.getInstance().mainScreenId) {
let addToDeskMenu = new MenuInfo();
addToDeskMenu.menuType = CommonConstants.MENU_TYPE_FIXED;
addToDeskMenu.menuImgSrc = '/common/pics/ic_public_copy.svg';
addToDeskMenu.menuText = $r('app.string.app_center_menu_add_desktop');
addToDeskMenu.onMenuClick = () => {
log.showInfo(`click menu item add to Desktop entry, bundleName = ${appInfo.bundleName} appindex:${appInfo.appIndex}` );
HiSysEventUtil.reportEventById(bundleName, 'appCenter add to desktop');
appInfo.keyName =
appInfo.bundleName + appInfo.abilityName + appInfo.moduleName + appInfo.appIndex;
localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_ADD, appInfo);
};
menuInfoList.push(addToDeskMenu);
}
if (appInfo.isUninstallAble) {
let uninstallMenu = new MenuInfo();
uninstallMenu.menuType = CommonConstants.MENU_TYPE_FIXED;
uninstallMenu.menuImgSrc = '/common/pics/ic_public_delete.svg';
if (appInfo.appIndex !== undefined && appInfo.appIndex > 0) {
uninstallMenu.menuText = $r('app.string.delete');
} else {
uninstallMenu.menuText = $r('app.string.uninstall');
}
uninstallMenu.onMenuClick = (): void => {
log.showInfo(`click menu item uninstall: ${appInfo.bundleName}`);
let appName = this.appGridPresenter?.getAppName(appInfo);
if (appName != null) {
appInfo.appName = appName;
}
this.selectItem = appInfo;
this.openUninstallDialog(appInfo);
AppStorage.setOrCreate('uninstallAppInfo', appInfo);
};
uninstallMenu.menuEnabled = appInfo.isUninstallAble;
menuInfoList.push(uninstallMenu);
}
ShortcutViewModel.getInstance().checkShortCutInfo(appInfo, menuInfoList, this.screenProp.screenId);
let appLockMenu: MenuInfo | undefined = AppLockUtils.getInstance().buildAppLockMenu(appInfo);
if(appLockMenu !== undefined) {
menuInfoList.push(appLockMenu);
}
return menuInfoList;
}
private appGridItemClickCallback(item: AppItemInfo): void {
if (!this.openAppEnable || !AppCenterModel.getInstance().isShow(this.screenProp.screenId)) {
log.showWarn(`appGridItemClickCallback return. ${this.openAppEnable}`);
return;
}
this.openAppEnable = false;
CloseAppManager.getInstance().setStartAppType(StartType.APP_CENTER_APP, undefined,
CommonConstants.APPCENTER_ICON_EXTRA_ID);
CloseAppManager.getInstance().setStartAppSubtype(StartSubtype.ICON_FROM_APP_CENTER);
let abilityName: string = item.abilityName === undefined ? '' : item.abilityName;
let bundleName: string = item.bundleName === undefined ? '' : item.bundleName;
let moduleName: string = item.moduleName === undefined ? '' : item.moduleName;
log.showInfo(`open app abilityName: ${JSON.stringify(item)}`);
log.showInfo(`open app abilityName: ${item?.appIndex}`);
let params = new Map<string, Object>();
if (item?.appIndex !== undefined && item?.appIndex > 0) {
params.set(SCBConstants.START_APP_CLONE_INDEX, item?.appIndex);
}
this.appGridPresenter?.openApplication(abilityName, bundleName, moduleName, params, this.screenProp.screenId);
if (GlobalContext.getInstance().hasObject('hideAppCenterWithAnimation')) {
log.showInfo(`appGridItemClickCallback hideAppCenterWithAnimation: ${TAG}`);
let hideAppCenterWithAnimation = (GlobalContext.getInstance()
.getObject('hideAppCenterWithAnimation')) as Function;
hideAppCenterWithAnimation(this.screenProp.screenId);
}
windowManager.hideWindow(windowManager.RECENT_WINDOW_NAME);
}
// 便利搜索任务map 如果存在则将其置为false.然后添加新任务
private insertSearchTask(searchValue: string) {
this.searchTask.forEach((value: boolean, key: string) => {
if (value) {
this.searchTask.set(key, false);
}
});
this.searchTask.set(searchValue, true);
}
/**
* 响应App搜索
*/
private onSearchInputChange() {
this.searchPageIndex = 0;
if (!this.searchInputText) {
log.showInfo(`onSearchInputChange searchInputText empty, not need to search`);
this.searchAppPageList?.clear();
this.isShowEmptyStatus = this.needShowSearchEmptyResult();
this.resetColumnHeightOfAppCenter();
HiSysEventUtil.reportOperateTypeAppCenter(HiSysEventUtil.APPCENTER_TYPE_OPERATE_SEARCH);
return;
}
this.isShowEmptyStatus = false;
log.showInfo('startSearch:');
let fusionSearchStartTime: number = Date.now();
this.insertSearchTask(this.searchInputText);
AppCenterViewModel.getInstance().inputChangeEvent(this.searchInputText)
.then((appCenterSearchResultTask: AppCenterSearchResultTask) => {
log.showInfo(`getResult time: ${Date.now() -
fusionSearchStartTime}=searchText:${this.searchInputText} resultListSize:${appCenterSearchResultTask?.resultList?.length}`);
let validTask = this.searchTask.get(appCenterSearchResultTask.searchKey) as boolean;
if (!validTask) {
return;
}
let appItems = AppCenterViewModel.getInstance().convertToAllList(this.appGridList);
let searchResultItems: Set<AppItemInfo> = new Set();
// 去重处理
for (let resultModel of appCenterSearchResultTask.resultList) {
log.showInfo(`search app: ${resultModel.bundleName} ${resultModel.appName}`);
for (let appItem of appItems) {
let appItemName = appItem?.appIndex ?? 0 > 0 ? `${appItem.bundleName}${appItem.appIndex}` : appItem.bundleName;
if (resultModel.bundleName === appItem.bundleName) {
log.showInfo(`appcenter resultModel:${appItemName}`);
searchResultItems.add(appItem);
}
}
}
this.updateLazySearchAppPageInfo(AppCenterViewModel.getInstance().doAppCenterDataPaging(
Array.from(searchResultItems), new Date().getTime()));
this.isShowEmptyStatus = this.needShowSearchEmptyResult();
this.resetColumnHeightOfAppCenter();
AppCenterViewModel.getInstance().setCurSearchPageIndex(0);
log.showInfo(`display result time: ${Date.now() - fusionSearchStartTime} searchText:${this.searchInputText} result:${searchResultItems.size}`);
HiSysEventUtil.reportOperateTypeAppCenter(HiSysEventUtil.APPCENTER_TYPE_OPERATE_SEARCH);
});
}
private updateLazyAppPageInfo(appLayPageInfo: AppLayoutInfo[]): void {
for (let index = 0; index < appLayPageInfo.length; index++) {
// 新增空白页,进行数据插入
if (index >= this.lazyAppLayPageInfo.totalCount()) {
this.lazyAppLayPageInfo.insertItem(appLayPageInfo[index], index);
}
// 存在相同页签,进行数据替换
if (index < this.lazyAppLayPageInfo.totalCount()){
this.lazyAppLayPageInfo.indexOf(appLayPageInfo[index]);
}
}
// 删除多与的空白页
if (appLayPageInfo.length < this.lazyAppLayPageInfo.totalCount()) {
this.lazyAppLayPageInfo.deleteItemByIndex(appLayPageInfo.length);
}
log.showInfo(`updateLazyAppPageInfo lazyAppLayPageInfo:${this.lazyAppLayPageInfo.totalCount()}`)
}
private updateLazySearchAppPageInfo(appLayPageInfo: AppLayoutInfo[]): void {
// 应用搜索每次都是更新搜索内容
this.searchAppPageList?.clear()
appLayPageInfo.forEach((item) => {
this.searchAppPageList?.pushItem(item as AppLayoutInfo);
})
log.showInfo(`updateLazySearchAppPageInfo searchAppPageList:${this.searchAppPageList?.totalCount()}`)
}
private getForeachKey(item: AppLayoutInfo): string {
if (this.searchInputText) {
if (this.searchAppPageList === undefined || this.searchAppPageList.totalCount() === 0) {
log.showInfo(`page_search`+ this.searchInputText);
return 'page_search' + this.searchInputText;
} else {
log.showInfo('page_search' + item.index + this.searchInputText + this.searchAppPageList.getData(item.index)?.pageInfo.length);
return 'page_search' + item.index + this.searchInputText + this.searchAppPageList.getData(item.index)?.pageInfo.length;
}
} else {
log.showInfo('page' + item.index);
return 'page' + item.index;
}
}
/**
* 是否需要翻页标记显示
* @returns
*/
private needShowIndicator(): boolean {
let preHeatingAppCenter: boolean | undefined = AppStorage.get('preHeatingAppCenter');
if (!this.isAppCenterShow || preHeatingAppCenter) {
return false;
}
if (!this.searchInputText) {
return AppGridLayoutCacheManager.getInstance().beyondOneScreen(this.lazyAppLayPageInfo.totalCount());
} else {
if (this.searchAppPageList) {
return AppGridLayoutCacheManager.getInstance().beyondOneScreen(this.searchAppPageList.totalCount());
} else {
return false;
}
}
}
/**
* 是否显示搜索结果空页
* @returns
*/
private needShowSearchEmptyResult(): boolean {
log.showInfo('needShowSearchEmptyResult searchInputText:' + this.searchInputText);
if (!this.isAppCenterShow) {
return false;
}
if (!this.searchInputText) {
return false;
}
return this.searchAppPageList?.totalCount() === 0;
}
private resetColumnHeightOfAppCenter(): void {
if (this.isShowEmptyStatus && FoldedDeviceAcViewModel.getInstance().isFoldedDevice()) {
switch (FoldedDeviceAcViewModel.getInstance().getCurrentFoldState()) {
case SCBFoldedState.HALF_FOLDED_VIRTUAL_KEYBOARD:
case SCBFoldedState.HALF_FOLDED_PHYSICAL_KEYBOARD:
this.columnHeightOfAppCenter = StyleConstants.PERCENTAGE_50;
break;
default :
this.columnHeightOfAppCenter = StyleConstants.PERCENTAGE_100;
break;
}
} else {
this.columnHeightOfAppCenter = StyleConstants.PERCENTAGE_100;
}
}
private onDragMoveEvent(
event: DragEvent, extraParams?: string, screenId?: number): void {
log.showInfo('onDragMove');
this.itemMove(event);
AppCenterDragMgr.getInstance().onDragMove(event, undefined, this.getUIContext(), screenId);
}
private itemMove(event: DragEvent): void {
if (FoldedDeviceAcViewModel.getInstance().isFoldedDevice()) {
if (FoldedDeviceAcViewModel.getInstance().isKeyboardOnCSide()) {
this.doItemMoveForOthers(event);
} else {
this.doItemMoveForFolded(event);
}
} else {
this.doItemMoveForOthers(event);
}
}
private doItemMoveForOthers(event: DragEvent): void {
if (!event) {
log.showWarn('itemMove invalid event!');
return;
}
if (AppCenterDragMgr.getInstance().getIsSwaggingPage()) {
log.showWarn('skip swagging time!');
return;
}
if (!this.gridStyleConfig) {
return;
}
const moveX: number = event.getWindowX();
const moveY: number = event.getWindowY();
const iconSize: number = this.gridStyleConfig.mIconSize;
const horizontalMargin: number = this.gridStyleConfig.mAppCenterMarginLeft;
const mGridWidth: number = this.gridStyleConfig.mGridWidth;
const gridHeight: number = this.mLayoutVM.getScreenHeight() - this.mLayoutVM.getDockHeight();
log.showInfo(`itemMove gridHeight ${gridHeight}`);
// 条件:1.当前图标拖出左侧1/4; 2.当前页码大于0,不合适;3.拖拽y值在工作区内
const isDragInLeftMarginArea: boolean =
((moveX - iconSize / 4) < horizontalMargin) && (this.pageIndex > 0) && (moveY < gridHeight);
const isLeftRtl: boolean = ((moveX - iconSize / 4) < horizontalMargin) && (moveY < gridHeight);
const isRightRtl: boolean =
((moveX + iconSize / 4) > (horizontalMargin + mGridWidth)) && (this.pageIndex > 0) && (moveY < gridHeight);
const isDragInRightMarginArea: boolean =
((moveX + iconSize / 4) > (horizontalMargin + mGridWidth)) && (moveY < gridHeight);
log.showInfo(`itemMove left-RTL: ${isLeftRtl}, right: ${isRightRtl}`);
log.showInfo(`itemMove left: ${isDragInLeftMarginArea}, right: ${isDragInRightMarginArea}`);
let needShowPrevious = RTLUtil.isRTL() ? isRightRtl : isDragInLeftMarginArea;
let needShowNext = RTLUtil.isRTL() ? isLeftRtl : isDragInRightMarginArea;
if (needShowPrevious) {
const callback = () => {
log.showInfo(`itemMove isDragInLeftMarginArea`);
AppCenterViewModel.getInstance().showPrevious(this.screenProp.screenId);
this.movingIconSwapPageDelay();
}
this.movePageTimer(callback);
} else if (needShowNext) {
const callback = () => {
log.showInfo(`itemMove isDragInRightMarginArea`);
this.moveItemToNext();
}
this.movePageTimer(callback);
} else {
this.clearMovePageTimer();
}
}
private doItemMoveForFolded(event: DragEvent): void {
if (!event) {
log.showWarn('itemMove invalid event!');
return;
}
if (AppCenterDragMgr.getInstance().getIsSwaggingPage()) {
log.showWarn('skip swagging time!');
return;
}
const moveX: number = event.getWindowX();
const moveY: number = event.getWindowY();
if (!this.gridStyleConfig) {
return;
}
const iconSize: number = this.gridStyleConfig.mIconSize;
const horizontalMargin: number = this.gridStyleConfig.mAppCenterMarginLeft;
const gridWidth: number = this.gridStyleConfig.mGridWidth;
const gridHeight: number = this.gridStyleConfig.mGridHeight;
const rowGap = this.gridStyleConfig.mRowsGap;
let paddingTop = this.getPaddingTop();
let firstPageBottom: number = gridHeight + paddingTop;
let space = this.getItemSpace();
let secondPageTop: number = gridHeight + paddingTop + space;
let dragStartPage = AppCenterDragMgr.getInstance().getStartDragPage();
log.showInfo(`doItemMoveForFolded-${dragStartPage}-${firstPageBottom}-${secondPageTop}-${moveX}-${moveY}` +
`-${paddingTop}-${space}-${iconSize}-${horizontalMargin}-${gridWidth}-${rowGap}`);
if (dragStartPage === undefined) {
log.showInfo('Ignore drag when drag start page invalid');
return;
}
let isInLeftMarginArea: boolean = (moveX - iconSize / 4) < horizontalMargin + HOT_EREA_ADJUSTMENT;
let isInRightMarginArea: boolean = (moveX + iconSize / 4) > (horizontalMargin + gridWidth - HOT_EREA_ADJUSTMENT);
const pageCount: number = AppGridLayoutCacheManager.getInstance().getPageCount();
const appLayoutInfo: AppLayoutInfo[] = AppGridLayoutCacheManager.getInstance().getAppGridLayoutItemList();
let needShowPrevious: boolean = (moveY < paddingTop - iconSize) && this.pageIndex !== 0;
let needShowNext: boolean = (isInLeftMarginArea || isInRightMarginArea) &&
(moveY > secondPageTop + gridHeight + iconSize / 4) &&
(this.pageIndex + 2 <= pageCount) &&
appLayoutInfo[this.pageIndex].pageInfo.length !== 0 &&
appLayoutInfo[this.pageIndex + 1].pageInfo.length !== 0;
if (needShowPrevious || needShowNext) {
this.doItemMoveForFoldedCrossScreen(needShowPrevious, needShowNext);
return;
}
const middleAreaHeight: number = FoldedDeviceAcViewModel.getInstance().getMiddleAreaHeight();
const middleLine: number = firstPageBottom + middleAreaHeight / 2;
let curDragPage: number = AppCenterDragMgr.getInstance().getDraggingPageIndex();
let isStartFromBSide = curDragPage % 2 === 0;
let workingPage: number = isStartFromBSide ? (moveY > middleLine ?
curDragPage + 1 : curDragPage) :
(moveY < middleLine ? curDragPage - 1 : curDragPage);
if (curDragPage === workingPage) {
log.showInfo(`doItemMoveForFolded directly return. repeatly Cross page drag - ${workingPage}, moveY: ${moveY}, middleLine: ${middleLine}, currentScreenHeight: ${px2vp(this.currentScreenHeight)}`);
return;
}
log.showInfo(`doItemMoveForFolded end. curDragPage: ${curDragPage}, isStartFromBSide: ${isStartFromBSide}, workingPage: ${workingPage}, moveY: ${moveY}, middleLine: ${middleLine}, currentScreenHeight: ${px2vp(this.currentScreenHeight)}`);
if (workingPage > curDragPage) {
this.moveItemToNextForFolded(curDragPage);
} else {
AppCenterDragMgr.getInstance().updateDragPageIndex(false);
this.movingIconSwapPageDelay();
}
}
private doItemMoveForFoldedCrossScreen(needShowPrevious: boolean, needShowNext: boolean): void {
if (needShowPrevious) {
AppCenterDragMgr.getInstance().setDragCrossScreen(true);
const callback = () => {
log.showInfo(`itemMove needShowPrevious crossScreen`);
AppCenterDragMgr.getInstance().setDraggingCrossScreen(true);
AppCenterViewModel.getInstance().showPrevious(this.screenProp.screenId);
AppCenterDragMgr.getInstance().setDraggingCrossScreen(false);
this.movingIconSwapPageDelay();
}
this.movePageTimer(callback, CROSS_SCREEN);
} else if (needShowNext) {
AppCenterDragMgr.getInstance().setDragCrossScreen(true);
const callback = () => {
log.showInfo(`itemMove needShowNext crossScreen`);
AppCenterDragMgr.getInstance().setDraggingCrossScreen(true);
this.moveItemToNextForFoldedCrossScreen();
AppCenterDragMgr.getInstance().setDraggingCrossScreen(false);
}
this.movePageTimer(callback, CROSS_SCREEN);
} else {
this.clearMovePageTimer();
}
}
private moveItemToNextForFoldedCrossScreen(): void {
log.showInfo('move folded item cross screen');
const pageCount: number = AppGridLayoutCacheManager.getInstance().getPageCount();
const appLayoutInfo: AppLayoutInfo[] = AppGridLayoutCacheManager.getInstance().getAppGridLayoutItemList();
const isBlankPage: boolean = (this.pageIndex < pageCount) && appLayoutInfo[this.pageIndex].pageInfo.length === 0;
log.showInfo(`move to next page from current: ${this.pageIndex}, blank=${isBlankPage}, totalPage=${pageCount}`);
// 需要增页,刚切过来会有这种情况
const foldedDreateNewPageStatus = (this.pageIndex >= pageCount - 2 && this.pageIndex <= pageCount) && !isBlankPage;
if (this.pageIndex < pageCount - 1) {
AppCenterViewModel.getInstance().showNext(this.screenProp.screenId);
}
this.movingIconSwapPageDelay(foldedDreateNewPageStatus);
}
private moveItemToNextForFolded(curDragPage: number): void {
let pageCount: number = AppGridLayoutCacheManager.getInstance().getPageCount();
const appLayoutInfo: AppLayoutInfo[] = AppGridLayoutCacheManager.getInstance().getAppGridLayoutItemList();
const isBlankPage: boolean = (curDragPage < pageCount) && appLayoutInfo[curDragPage].pageInfo.length === 0;
log.showInfo(`move to next moveItemToNext page from current: ${curDragPage}, totalPage: ${pageCount},isBlankPage:${isBlankPage}`);
// 需要增页,刚切过来会有这种情况
const foldedDreateNewPageStatus = (curDragPage === pageCount - 1 || curDragPage === pageCount) && !isBlankPage;
if (curDragPage <= pageCount - 1) {
AppCenterDragMgr.getInstance().updateDragPageIndex(true);
}
this.movingIconSwapPageDelay(foldedDreateNewPageStatus);
}
private createNewPageForFolded(): void {
let pageCount: number = AppGridLayoutCacheManager.getInstance().getPageCount();
pageCount = AppGridLayoutCacheManager.getInstance().addBlankPage() ? (pageCount + 1) : pageCount;
// s刷新新的页签
AppListPresenter.getInstance().refreshAppGridLayout(this.screenProp?.screenId,
FeatureConstants.AC_UPDATE_PAGE_REASON_NEW_BLANK_PAGE);
// 更新锁定状态
AppCenterDragMgr.getInstance().updateDragPageIndex(true);
// 进行翻页
this.moveItemToNext();
}
private moveItemToNext(): void {
const pageCount: number = AppGridLayoutCacheManager.getInstance().getPageCount();
const appLayoutInfo: AppLayoutInfo[] = AppGridLayoutCacheManager.getInstance().getAppGridLayoutItemList();
const isBlankPage: boolean = (this.pageIndex < pageCount) && appLayoutInfo[this.pageIndex].pageInfo.length === 0;
log.showInfo(`move to next page from current: ${this.pageIndex}`);
// 需要增页,刚切过来会有这种情况
if ((this.pageIndex === pageCount - 1 || this.pageIndex === pageCount) && !isBlankPage) {
AppGridLayoutCacheManager.getInstance().addBlankPage();
localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_APP_GRID_REFRESH_FINISHED, null);
}
if (this.pageIndex < pageCount - 1) {
AppCenterViewModel.getInstance().showNext(this.screenProp.screenId);
}
this.movingIconSwapPageDelay();
}
private movingIconSwapPageDelay(foldedDreateNewPageStatus?: boolean): void {
log.showInfo(`movingIconSwapPageDelay movingIconSwapPageDelay:${foldedDreateNewPageStatus}`);
AppCenterDragMgr.getInstance().setIsSwaggingPage(true);
setTimeout(() => {
// folded设备,在热区等待之后创建新的空白页,然后进行换页
if (foldedDreateNewPageStatus) {
this.createNewPageForFolded();
}
AppCenterDragMgr.getInstance().setIsSwaggingPage(false);
}, this.swapPageDelayTime);
}
private initSwapPageDelayTime(): void {
this.swapPageDelayTime =
!FoldedDeviceAcViewModel.getInstance().isFoldedDevice() ? SWAP_PAGE_DELAY : SWAP_PAGE_DELAY_HPR;
}
public buildNotInstalledAppMenu(item: AppItemInfo): Map<AppStatus, MenuInfo[]> {
let menuInfoList = new Map<AppStatus, MenuInfo[]>();
if (item === undefined) {
return menuInfoList;
}
let bundleName: string = item.bundleName === undefined ? '' : item.bundleName as string;
menuInfoList = AppListPresenter.getInstance().buildNotInstalledAppMenu(bundleName);
return menuInfoList;
}
private itemDragStart(): void {
log.showInfo('itemDragStart');
}
private itemDragEnd(): void {
log.showInfo('itemDragEnd');
}
private getPageIdx(): number {
log.showInfo(`getIdx-${this.searchInputText}-${this.pageIndex}`);
return this.searchInputText ? this.searchPageIndex : this.pageIndex;
}
private onSwiperChange(index: number): void {
log.showInfo(`onChange index: ${index}-${this.pageIndex}, searchInputText : ${this.searchInputText}`);
if (this.searchInputText) {
if (this.isAppCenterShow) {
this.searchPageIndex = index;
AppCenterViewModel.getInstance().setCurSearchPageIndex(index);
}
return;
}
if (!this.isAppCenterShow && this.pageIndex === 0 && index > 0) {
// avoid arkui swiper bug
log.showWarn('onChange no need to change pageIndex');
return;
}
this.pageIndex = index;
AppCenterDragMgr.getInstance().setDragPageIndex(this.pageIndex);
AppCenterDragMgr.getInstance().removeDropAnim();
}
private onSwiperAnimationStart(index: number): void {
AppStorage.setOrCreate<boolean>('isAppCenterSwiping', FoldedDeviceAcViewModel.getInstance().isFoldedDevice());
ContextMenu.close();
log.showInfo('onAnimationStart');
AppCenterDragMgr.getInstance().removeDropAnim();
focusControl.requestFocus(CommonConstants.APP_CENTER_REQUEST_FOCUS_KEY + index);
this.showDropFrame = false;
// ApsUtils.stopApsSession(this.apsApsSessionId);
this.apsApsSessionId = '';
// ApsUtils.setApsScene(apsManager.SceneAnimation.APPCENTER_SWIPE, StyleConstants.DEFAULT_1);
}
private onSwiperAnimationEnd(index: number, extraInfo: SwiperAnimationEvent): void {
if (extraInfo.currentOffset === 0) {
AppStorage.setOrCreate<boolean>('isAppCenterSwiping', false);
}
log.showInfo(`onAnimationEnd ${extraInfo.currentOffset}`);
// ApsUtils.setApsScene(apsManager.SceneAnimation.APPCENTER_SWIPE, StyleConstants.DEFAULT_0);
animateTo({
duration: 200,
curve: curves.interpolatingSpring(0.5, 1, 228, 30)
}, () => {
this.showDropFrame = true;
});
}
private onSwiperGestureSwipe(index: number, extraInfo: SwiperAnimationEvent): void {
AppCenterDragMgr.getInstance().removeDropAnim();
ContextMenu.close();
AppStorage.setOrCreate<boolean>('isAppCenterSwiping', FoldedDeviceAcViewModel.getInstance().isFoldedDevice());
if (this.apsApsSessionId === '') {
// this.apsApsSessionId = ApsUtils.startApsPersistentSession(apsManager.SceneAnimation.APPCENTER_SWIPE_MOVING);
} else {
if (!ApsUtils.pulseApsSession(this.apsApsSessionId)) {
// this.apsApsSessionId = ApsUtils.startApsPersistentSession(apsManager.SceneAnimation.APPCENTER_SWIPE_MOVING);
}
}
}
@Builder
buildSearchAppSwiper() {
Swiper(this.sreachSwiperController) {
LazyForEach(this.searchAppPageList, (item: AppLayoutInfo) => {
AppCenterAppGrid({
singleContext: this.singleContext,
appGridList: item.pageInfo,
pageIndex: item.index,
isScroll: false,
appGridStyleConfig: this.gridStyleConfig,
onItemClick: (event: ClickEvent, item: AppItemInfo) => {
this.appGridItemClickCallback(item);
},
getIndexInSwiper: (): number => this.pageIndex,
buildMenu: (item: AppItemInfo) => this.buildMenuInfoList(item),
buildNotInstalledAppMenu: (item: AppItemInfo) => this.buildNotInstalledAppMenu(item),
// appcenter show badge
enableBadge: true,
dragAllowed: true,
inSearch: this.searchInputText ? true : false,
isGainFocus: this.isGainFocus,
dragStart: () => this.itemDragStart(),
dragEnd: ()=> this.itemDragEnd(),
swiperPaddingBottom: this.swiperPaddingBottom,
screenProp: this.screenProp,
appItemPosX: this.appItemPosX,
appItemPosY: this.appItemPosY,
appItemOpacity: this.appItemOpacity,
bkOpacity: this.bkOpacity,
rtlAppItemPosX: this.rtlAppItemPosX
})
}, (item: AppLayoutInfo) => this.getForeachKey(item))
}
.id(APP_CENTER_SWIPER_KEY)
.visibility(this.searchInputText ? Visibility.Visible : Visibility.None)
.pageFlipMode(PageFlipMode.SINGLE)
.displayCount(this.swiperDsCount, this.swiperMultiPages)
.vertical(this.swiperVertical)
.indicator(this.needShowIndicator())
.width(StyleConstants.PERCENTAGE_100)
.height(StyleConstants.PERCENTAGE_100)
.disableSwipe(!this.swiperEnabled)
.dragStyle()
.indicatorStyle(this.getIndicatorStyle())
.effectMode(EdgeEffect.None)
.index(this.getPageIdx())
.padding({
top: this.swiperPaddingTop,
bottom: this.swiperPaddingBottom
})
.onChange((index: number) => {
this.onSwiperChange(index);
})
.onAnimationStart((index: number) => {
this.onSwiperAnimationStart(index);
})
.onAnimationEnd((index: number, extraInfo: SwiperAnimationEvent) => {
this.onSwiperAnimationEnd(index, extraInfo);
})
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
this.onSwiperGestureSwipe(index, extraInfo);
})
.loop(false)
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Up) {
log.showInfo('onTouch Up');
AppStorage.setOrCreate<boolean>('isAppCenterSwiping', false);
}
})
}
@Builder
buildAppSwiper() {
Swiper(this.swiperController) {
LazyForEach(this.lazyAppLayPageInfo, (item: AppLayoutInfo) => {
AppCenterAppGrid({
singleContext: this.singleContext,
appGridList: item.pageInfo,
pageIndex: item.index,
isScroll: false,
appGridStyleConfig: this.gridStyleConfig,
onItemClick: (event: ClickEvent, item: AppItemInfo) => {
this.appGridItemClickCallback(item);
},
getIndexInSwiper: (): number => this.pageIndex,
buildMenu: (item: AppItemInfo) => this.buildMenuInfoList(item),
buildNotInstalledAppMenu: (item: AppItemInfo) => this.buildNotInstalledAppMenu(item),
enableBadge: true,
dragAllowed: true,
inSearch: this.searchInputText ? true : false,
isGainFocus: this.isGainFocus,
dragStart: () => this.itemDragStart(),
dragEnd: () => this.itemDragEnd(),
swiperPaddingBottom: this.swiperPaddingBottom,
screenProp: this.screenProp,
appItemPosX: this.appItemPosX,
appItemPosY: this.appItemPosY,
appItemOpacity: this.appItemOpacity,
bkOpacity: this.bkOpacity,
rtlAppItemPosX: this.rtlAppItemPosX
})
}, (item: AppLayoutInfo) => this.getForeachKey(item))
}
.id(APP_CENTER_SWIPER_KEY)
.visibility(this.searchInputText ? Visibility.None : Visibility.Visible)
.pageFlipMode(PageFlipMode.SINGLE)
.displayCount(this.swiperDsCount, this.swiperMultiPages)
.vertical(this.swiperVertical)
.indicator(this.needShowIndicator())
.width(StyleConstants.PERCENTAGE_100)
.height(StyleConstants.PERCENTAGE_100)
.disableSwipe(!this.swiperEnabled)
.dragStyle()
.indicatorStyle(this.getIndicatorStyle())
.effectMode(EdgeEffect.None)
.index(this.getPageIdx())
.padding({
top: this.swiperPaddingTop,
bottom: this.swiperPaddingBottom
})
.onChange((index: number) => {
this.onSwiperChange(index);
})
.onAnimationStart((index: number) => {
this.onSwiperAnimationStart(index);
})
.onAnimationEnd((index: number, extraInfo: SwiperAnimationEvent) => {
this.onSwiperAnimationEnd(index, extraInfo);
})
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
this.onSwiperGestureSwipe(index, extraInfo);
})
.loop(false)
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Up) {
log.showInfo('onTouch Up');
AppStorage.setOrCreate<boolean>('isAppCenterSwiping', false);
}
})
}
private getArrowBackground(isLeft: boolean): Resource | string {
if (isLeft) {
return this.arrowLeftIsHover ? COLOR_ARROW : StyleConstants.DEFAULT_TRANSPARENT_COLOR
}
return this.arrowRightIsHover ? COLOR_ARROW : StyleConstants.DEFAULT_TRANSPARENT_COLOR
}
private getArrowDisabled(isLeft: boolean): boolean {
log.showInfo(`pages: ${this.pages}`);
if (isLeft) {
return this.pages?.slice(0)[0] === this.pageIndex ? false : true
}
return this.pages?.slice(-1)[0] === this.pageIndex ? false : true
}
private getOpacity(isLeft: boolean): Resource | number {
if (isLeft) {
return this.pages?.slice(0)[0] === this.pageIndex ? $r('sys.float.ohos_id_alpha_disabled') : 1
}
return this.pages?.slice(-1)[0] === this.pageIndex ? $r('sys.float.ohos_id_alpha_disabled') : 1
}
private checkIfLeftRTL(isUp: boolean) {
return RTLUtil.isRTL() ? !isUp : isUp;
}
private getIndicatorStyle(): IndicatorStyle {
return FoldedDeviceAcViewModel.getInstance().isFoldedDevice() ?
{
color: '#33ffffff',
selectedColor: '#ffffff',
top: this.indicatorHeightForFoldedDevice,
right: this.getIndicatorRight()
} :
{
color: '#33ffffff',
selectedColor: '#ffffff',
bottom: INDICATOR_MARGIN_BOTTOM
};
}
@Builder
AppIconBackgroundBuilder(isLeft: boolean) {
Stack() {
Stack() {
}
.width(SIZE_ARROW)
.height(SIZE_ARROW)
.backgroundColor(COLOR_ARROW)
.borderRadius(SIZE_ARROW)
.align(Alignment.Center)
WithTheme({ colorMode: ThemeColorMode.DARK }) {
Stack() {
SymbolGlyph(this.checkIfLeftRTL(isLeft) ? $r('sys.symbol.chevron_left') : $r('sys.symbol.chevron_right'))
.align(Alignment.Center)
.fontColor([$r('sys.color.icon_on_primary')])
.alignSelf(ItemAlign.Center)
.fontWeight(FontWeight.Normal)
.fontSize('24vp')
.align(Alignment.Center)
.opacity(this.getOpacity(this.checkIfLeftRTL(isLeft)))
}
.width(SIZE_ARROW)
.height(SIZE_ARROW)
.borderRadius(SIZE_ARROW)
.enabled(this.getArrowDisabled(this.checkIfLeftRTL(isLeft)))
.stateStyles({
pressed: {
.backgroundColor(COLOR_ARROW_PRESS)
},
normal: {
.backgroundColor(this.getArrowBackground(this.checkIfLeftRTL(isLeft)))
},
disabled: {
.opacity(this.getOpacity(this.checkIfLeftRTL(isLeft)))
}
})
.align(Alignment.Center)
}
}
.onHover((isHover: boolean) => {
log.showInfo(`appGridItemClickCallback hideAppCenterWithAnimation: ${this.arrowLeftIsHover}`);
if (this.checkIfLeftRTL(isLeft)) {
this.arrowLeftIsHover = isHover
} else {
this.arrowRightIsHover = isHover
}
})
.onClick(() => {
if (this.checkIfLeftRTL(isLeft) && !this.searchInputText) {
this.swiperController.showPrevious();
} else if (this.checkIfLeftRTL(isLeft) && this.searchInputText) {
this.sreachSwiperController.showPrevious();
} else if (this.searchInputText) {
this.sreachSwiperController.showNext()
} else {
this.swiperController.showNext();
}
AppCenterDragMgr.getInstance().removeDropAnim();
})
.width(SIZE_ARROW_BACKGROUND)
.height(SIZE_ARROW_BACKGROUND)
.backgroundColor(Color.Transparent)
.borderRadius(SIZE_ARROW)
.align(Alignment.Center)
}
private doIndicatorAnimationForFoldedDevice(): void {
if (!this.isAppCenterShow) {
this.indicatorHeightForFoldedDevice = this.getIndicatorHeight();
return;
}
animateTo({
duration: INDICATOR_ANIM_DURATION,
curve: Curve.Friction,
}, () => {
this.indicatorHeightForFoldedDevice = this.getIndicatorHeight();
})
}
private getIndicatorRight(): number {
if (FoldedDeviceAcViewModel.getInstance().isUnFoldedHorizontal()) {
return DEFAULT_INDICATOR_RIGHT_HORIZONTAL_HPR;
}
return DEFAULT_INDICATOR_RIGHT_HPR;
}
private getIndicatorHeight(): number {
if (FoldedDeviceAcViewModel.getInstance().isUnFoldedHorizontal()) {
if (this.screenProp.screenId === 0) {
return UNFOLDED_HORIZONAL_INDICATOR_HEIGHT;
} else {
return px2vp(this.screenProp.height / 2);
}
}
if (FoldedDeviceAcViewModel.getInstance().isUnFoldedVertical()) {
return UNFOLDED_VERTICAL_INDICATOR_HEIGHT;
}
return DEFAULT_INDICATOR_HEIGHT;
}
@Styles
dragStyle() {
.onDragEnter((event: DragEvent, extraParams?: string) => {
log.showInfo('onDragEnter');
AppCenterDragMgr.getInstance().onDragEnter(this.screenProp);
})
.onDragMove((event: DragEvent, extraParams?: string) => {
this.onDragMoveEvent(event, extraParams, this.screenProp.screenId);
})
.onDrop((event?: DragEvent, extraParams?: string) => {
log.showInfo('onDrop');
if (event) {
event.useCustomDropAnimation = true;
event.setResult(DragResult.DRAG_FAILED);
}
this.clearMovePageTimer();
AppCenterDragMgr.getInstance().onDrop(this.getUIContext(), this.screenProp);
})
.onDragLeave((event: DragEvent, extraParams?: string) => {
log.showInfo('onDragLeave');
this.clearMovePageTimer();
AppCenterDragMgr.getInstance().onDragLeave();
})
}
build() {
Column() {
// 搜索结果为空
if (this.isShowEmptyStatus) {
Text($r('app.string.search_no_result'))
.fontColor($r('sys.color.font_on_primary'))
.textOverflow({ overflow: TextOverflow.Ellipsis })
.textAlign(TextAlign.Center)
.fontSize(20)
.lineHeight('27px')
.fontWeight(FontWeight.Regular)
.clip(false)
.align(Alignment.Center)
.visibility(this.isAppCenterShow ? Visibility.Visible : Visibility.None)
} else {
Stack() {
AppCenterDropFrame({
appGridStyleConfig: this.gridStyleConfig,
singleContext: this.singleContext,
pageIndex: this.pageIndex,
showDropFrame: this.showDropFrame,
screenProp: this.screenProp
})
this.buildSearchAppSwiper();
this.buildAppSwiper();
if (this.needTwoArrow) {
Stack({ alignContent: Alignment.Start }) {
this.AppIconBackgroundBuilder(true)
}
.visibility(this.needShowIndicator() ? Visibility.Visible : Visibility.None)
.translate({ x: -(this.getUIContext()?.px2vp(this.screenProp.width) as number) / 2 + 56 })
Stack({ alignContent: Alignment.End }) {
this.AppIconBackgroundBuilder(false)
}
.visibility(this.needShowIndicator() ? Visibility.Visible : Visibility.None)
.translate({ x: (this.getUIContext()?.px2vp(this.screenProp.width) as number) / 2 - 56 })
}
}
}
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.backgroundImageSize(ImageSize.Cover)
.width(StyleConstants.PERCENTAGE_100)
.height(this.columnHeightOfAppCenter)
}
}