* Copyright (c) 2023-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 { BusinessType, CommonConstants } from '../constants/CommonConstants';
import { EventConstants } from '../constants/EventConstants';
import type { DockItemInfo } from '../bean/DockItemInfo';
import { FolderModel } from './FolderModel';
import { PageDesktopModel } from '../pagedesktop/model/PageDesktopModel';
import { RdbStoreManager } from '../db/RdbStoreManager';
import { promptAction } from '@kit.ArkUI';
import {
CheckEmptyUtils,
LogDomain,
LogHelper,
ObjUtil,
} from '@ohos/basicutils';
import { DeviceHelper, localEventManager, ResourceManager, } from '@ohos/frameworkwrapper';
import { desktopUtil } from '@ohos/componenthelper';
import { ResUtils, SCBScreenSessionManager, } from '@ohos/windowscene';
import { BaseViewModel } from '../base/BaseViewModel';
import type GridLayoutItemInfo from '../bean/GridLayoutItemInfo';
import GridLayoutInfoColumns from '../db/column/GridLayoutInfoColumns';
import { SettingsModel } from '../model/SettingsModel';
import GridLayoutUtil from '../utils/GridLayoutUtil';
import type { FolderAppItemInfo } from './FolderItemInfo';
import { FolderLayoutCacheManager } from '../cache/layout/FolderLayoutCacheManager';
import { FolderData } from './model/FolderData';
import { AppItemInfo, Cache2RdbHelper, ResidentLayoutCacheMgr, StyleConstants } from '../TsIndex';
import { AppCategoryInfoManager } from '../manager/AppCategoryInfoManager';
import { AppCategoryUtils } from '../utils/AppCategoryUtils';
const TAG = 'FolderViewModel';
const log: LogHelper = LogHelper.getLogHelper(LogDomain.HOME, TAG);
export abstract class FolderViewModel extends BaseViewModel {
protected readonly mSettingsModel: SettingsModel;
protected readonly mFolderModel: FolderModel;
protected readonly mPageDesktopModel: PageDesktopModel;
protected readonly mFolderLayout: FolderLayoutCacheManager;
private foldStatusChangeCallbacksInFolder: Set<Function> = new Set<Function>();
private folderLayoutChangeCallback: Map<string, FolderLayoutChangeListener[]> = new Map();
protected constructor() {
super();
this.mSettingsModel = SettingsModel.getInstance();
this.mFolderModel = FolderModel.getInstance();
this.mPageDesktopModel = PageDesktopModel.getInstance();
this.mFolderLayout = FolderLayoutCacheManager.getInstance();
}
* 自定义拖拽多个应用进文件夹
* 原addAppsToFolder方法中对每一个app都执行了一遍搜索桌面全局获取文件夹,搜索文件夹内全部图标以筛选被移除的图标,更新桌面图标的操作
* 对性能影响较大,故在此将其中可抽出的方法进行抽出重写
* @param apps 多个应用的数组
* @param folderId 文件夹的id
*/
public addAppsToFolder(apps: GridLayoutItemInfo[], folderId: string, isRefreshView: boolean = true,
isOperateDb: boolean = true): void {
let appListInfo: GridLayoutItemInfo[] = this.mSettingsModel.getAppListInfo();
let folderItem: GridLayoutItemInfo | undefined = this.mFolderLayout.selectGridLayoutItemByFolderId(folderId, false);
if (!folderItem) {
log.showInfo(`do not find the folderItem as folderId ${folderId}`);
return;
}
if (FolderViewModel.isFolderFull(folderItem)) {
log.showInfo('addOneAppToFolder folder full: ' + folderItem.folderName);
return;
}
const releaseLock = Cache2RdbHelper.getInstance().addLock(CommonConstants.DRAG_RDB_EVENT, 'addAppsToFolder');
RdbStoreManager.getInstance()
.queryItemByInfoId(folderItem.folderId ?? '')
.then((rdbFolderItem: GridLayoutItemInfo) => {
log.showWarn(` query folderData ${JSON.stringify(rdbFolderItem)}`);
if (!rdbFolderItem) {
return;
}
apps.forEach(item => item.container = rdbFolderItem.id);
})
.catch((error: Error) => {
log.showWarn(`get folder from rdb error:${error?.message}`);
})
.finally(() => {
releaseLock?.();
});
let needInsertAppList: GridLayoutItemInfo[] = [];
apps.forEach((appInfo: GridLayoutItemInfo) => {
appListInfo = appListInfo.filter(item => item.keyName !== appInfo.keyName);
let isAppExist: boolean | undefined = folderItem?.layoutInfo?.flat().
find((item) => item.keyName === appInfo.keyName) !== undefined;
if (isAppExist) {
log.showInfo('not addOneAppToFolder as the app is exist in this folder');
return;
}
let badgeNum: number = 0;
if (folderItem?.badgeNumber && folderItem.badgeNumber > 0) {
badgeNum = folderItem.badgeNumber + (appInfo.badgeNumber ?? 0);
} else {
badgeNum = (appInfo.badgeNumber ?? 0);
}
needInsertAppList.push(appInfo);
Cache2RdbHelper.getInstance().addItem(CommonConstants.DRAG_RDB_EVENT, appInfo);
this.mFolderLayout.updateBadgeNumberByFolderId(badgeNum, folderId, BusinessType.BUSINESS_FOLDER);
});
if (!folderItem.layoutInfo) {
return;
}
const lastPageItems: GridLayoutItemInfo[] = folderItem.layoutInfo[folderItem.layoutInfo.length - 1];
if (CheckEmptyUtils.isEmpty(lastPageItems)) {
log.showInfo(`addOneAppToFolder lastPageItems empty`);
return;
}
this.mFolderLayout.insertAppListToFolderByFolderId(folderId, needInsertAppList, isRefreshView, isOperateDb);
this.mSettingsModel.setAppListInfo(appListInfo);
this.deleteAppLayoutItems(apps);
}
* Update Folder App Location.
*
* @param folderAppInfo folderAppInfo
*/
public updateFolderAppLocation(folderAppInfo?: GridLayoutItemInfo[]): void {
if (!folderAppInfo) {
return;
}
let folderOpenColumn = FolderModel.getInstance().getFolderOpenLayout()?.column;
let folderOpenRow = FolderModel.getInstance().getFolderOpenLayout()?.row;
for (let i = 0; i < folderAppInfo.length; i++) {
if (!folderOpenColumn || !folderOpenRow) {
continue;
}
folderAppInfo[i].column = i % folderOpenColumn;
folderAppInfo[i].row = Math.floor(i / folderOpenColumn % folderOpenRow);
folderAppInfo[i].page = Math.floor(i / (folderOpenColumn * folderOpenRow));
}
}
* 注册文件夹名称变更监听
* @param info 文件夹item信息
* @param listener 文件夹重命名监听接口实例
*/
registerFolderLayoutChangeListener(info: GridLayoutItemInfo, listener: FolderLayoutChangeListener): void {
if (info && info.folderId) {
const callbacks: FolderLayoutChangeListener[] = this.folderLayoutChangeCallback.get(info.folderId) || [];
callbacks.push(listener);
this.folderLayoutChangeCallback.set(info.folderId, callbacks);
}
}
* 反注册文件夹名称变更监听
* @param info 文件夹item信息
* @param listener 文件夹重命名监听接口实例
*/
unregisterFolderLayoutChangeListener(info: GridLayoutItemInfo, listener: FolderLayoutChangeListener): void {
if (info && info.folderId) {
let callbacks: FolderLayoutChangeListener[] = this.folderLayoutChangeCallback.get(info.folderId) || [];
callbacks = callbacks.filter(item => item !== listener);
this.folderLayoutChangeCallback.set(info.folderId, callbacks);
}
}
* Modify folder name.
*
* @param folderInfo folderInfo
* @param isInit true indicates folder is new created
*/
public modifyFolderName(folderInfo: GridLayoutItemInfo, isInit: boolean = false, isOperateDb: boolean = true): void {
log.showDebug(`modifyFolderName isInit:${isInit}`);
const residentList = this.mSettingsModel.getResidentList();
for (const dockItem of residentList) {
if (dockItem.typeId === CommonConstants.TYPE_FOLDER && dockItem.bundleName === folderInfo.folderId) {
dockItem.appName = folderInfo.folderName ?? '';
this.mSettingsModel.setResidentList(residentList);
if (!isOperateDb) {
continue;
}
this.dealRdbStoreManager(isInit, dockItem);
}
}
this.renameCallback(folderInfo);
FolderLayoutCacheManager.getInstance().updateFolderName(
folderInfo.folderName ?? '', folderInfo.folderId ?? '', isInit, BusinessType.BUSINESS_FOLDER, isOperateDb);
FolderData.getInstance().refreshView('modifyFolderName', folderInfo.folderId ?? '');
}
private dealRdbStoreManager(isInit: boolean, dockItem: DockItemInfo): void {
if (isInit) {
if (dockItem.layoutInfo) {
RdbStoreManager.getInstance().insertFolderLayout(GridLayoutUtil.dockItemToGridLayout(dockItem),
dockItem.layoutInfo.flat());
}
} else {
RdbStoreManager.getInstance().updateGridInfoById(dockItem.bundleName, GridLayoutInfoColumns.INFO_NAME,
dockItem.appName);
}
}
private renameCallback(folderInfo: GridLayoutItemInfo): void {
for (const layoutChangeCallback of this.folderLayoutChangeCallback.get(folderInfo.folderId ?? '') || []) {
layoutChangeCallback?.rename?.(folderInfo.folderName ?? '');
}
}
* 获取合成文件夹的应用的二级分类id(id个数小于等于2时,返回有效的id集合)
*
* @param targetItem 目标元素
* @param dragItems 拖拽元素
* @returns 应用二级分类id的集合
*/
protected getAppCatIdInFolder(targetItem: GridLayoutItemInfo, dragItems: GridLayoutItemInfo[] | DockItemInfo[]):
number[] {
let instance = AppCategoryInfoManager.getInstance();
let targetItemCatId = instance.readCatIdFromCache(targetItem.bundleName);
let bundleNames = AppCategoryUtils.getBundleNameList(dragItems);
let appCatIdList: number[] = [];
if (targetItemCatId == null || !bundleNames || bundleNames.length === 0) {
log.showWarn('getAppCatIdInFolder, targetItemCatId or bundleName is null');
return appCatIdList;
}
let catIdSet: Set<number> = new Set();
catIdSet.add(targetItemCatId);
for (let bundleName of bundleNames) {
let catId = instance.readCatIdFromCache(bundleName);
if (catId == null) {
log.showWarn(`bundleName = ${bundleName}, categoryId is null`);
return appCatIdList;
}
catIdSet.add(catId);
if (catIdSet.size > 2) {
log.showInfo('the number of categoryId in folder exceeds 2');
return appCatIdList;
}
}
let dragItemsCatId: number = -1;
if (catIdSet.size === 1) {
dragItemsCatId = targetItemCatId;
appCatIdList = [targetItemCatId];
} else if (catIdSet.size === 2) {
dragItemsCatId = Array.from(catIdSet)[1];
appCatIdList = [targetItemCatId, dragItemsCatId];
}
log.showInfo(`getAppCatIdInFolder, targetItemCatId: ${targetItemCatId}, dragItemsCatId: ${dragItemsCatId}`);
return appCatIdList;
}
* Generate folder name.
*
* @returns the folder name.
*/
protected generateFolderName(): string {
log.showDebug('generateFolderName start');
const folderList = this.getAllFolderList();
const folderNamePrefix: string = '${new_folder_name}';
let folderName = folderNamePrefix;
let suffixNumberList: number[] = [];
const isNumberRegExp = new RegExp('^[1-9][0-9]*$');
folderList.forEach((element, index, self) => {
const suffixNumber = this.getFolderNameSuffixNumber(element.folderName ?? '', folderNamePrefix, isNumberRegExp);
if (!Number.isNaN(suffixNumber)) {
suffixNumberList.push(suffixNumber);
}
});
const residentList = this.mSettingsModel.getResidentList();
residentList.forEach((dockItem, index, self) => {
if (dockItem.typeId === CommonConstants.TYPE_FOLDER) {
const suffixNumber = this.getFolderNameSuffixNumber(dockItem.appName, folderNamePrefix, isNumberRegExp);
if (!Number.isNaN(suffixNumber)) {
suffixNumberList.push(suffixNumber);
}
}
});
const uniqueSuffixNumberList = Array.from(new Set(suffixNumberList));
uniqueSuffixNumberList.sort((suffix1: number, suffix2: number) => {
return suffix1 - suffix2;
});
let nameNumber = 1;
for (let i = 0; i < uniqueSuffixNumberList.length; i++) {
if (uniqueSuffixNumberList[i] !== nameNumber) {
break;
}
nameNumber++;
}
folderName = folderNamePrefix + nameNumber;
log.showDebug(`generateFolderName folderName:${folderName}`);
return folderName;
}
private getFolderNameSuffixNumber(folderName: string, folderNamePrefix: string, isNumberRegExp: RegExp): number {
if (!folderName) {
return Number.NaN;
}
if (folderName.startsWith(folderNamePrefix) && isNumberRegExp.test(folderName.substring(folderNamePrefix.length))) {
return Number(folderName.substring(folderNamePrefix.length));
}
return Number.NaN;
}
* Get new folder name.
*
* @returns new folder name.
*/
public abstract getNewFolderName(): Promise<string>;
* Get all folders in PageDesktop.
*
* @returns an array contains all folders.
*/
private getAllFolderList(): GridLayoutItemInfo[] {
log.showDebug('getAllFolderList start');
const folderList: GridLayoutItemInfo[] = this.mFolderLayout.selectGridLayoutItemsByType(CommonConstants.TYPE_FOLDER);
AppStorage.setOrCreate('allFolderList', folderList);
return folderList;
}
public static isFolderInCurrentPageOfDesktop(folderPage: number): boolean {
let currentPage: number = desktopUtil.getPageIndexValue();
if (SCBScreenSessionManager.getInstance().isFoldablePhoneExpandStatus()) {
return Math.floor(currentPage / 2) === Math.floor(folderPage / 2);
}
return currentPage === folderPage;
}
* Get folder name after replace resource string.
*
* @returns folder name after replace i18n value.
*/
public getRealFolderName(originFolderName: string): string {
if (ObjUtil.isInvalid(originFolderName)) {
log.showWarn('getRealFolderName, originFolderName is invalid');
return originFolderName;
}
let isIntelFolder: boolean = originFolderName.startsWith('#');
if (isIntelFolder) {
let realFoldrName = AppCategoryUtils.getIntelFolderName(originFolderName);
log.showInfo(`getRealFolderName realFoldrName: ${realFoldrName}`);
if (!CheckEmptyUtils.checkStrIsEmpty(realFoldrName)) {
return realFoldrName;
}
}
let reg: RegExp = /^\$\{([^{}]+)\}(.*)/;
let ret: RegExpMatchArray | null = originFolderName.match(reg);
if (ret) {
if (ret.length === 2) {
return ResourceManager.getInstance().getStringByName(ret[1]);
} else if (ret.length === 3 ) {
return ResourceManager.getInstance().getStringByName(ret[1], parseInt(ret[2]) || 1);
}
}
return originFolderName.trim();
}
* Delete apps in PageDesktop.
*
* @param appListInfo the apps to delete
*/
public deleteAppLayoutItems(appListInfo: GridLayoutItemInfo[], folderAppInfo = [], isOuter?: boolean): void {
for (let i = 0; i < appListInfo.length; i++) {
this.mFolderLayout.deleteAppItemByKeyName(appListInfo[i].keyName ?? '', BusinessType.BUSINESS_FOLDER, false,
isOuter);
}
if (this.isFolderDisappearing()) {
setTimeout(() => {
if (folderAppInfo.length > 0) {
this.updateFolderAppLocation(folderAppInfo);
}
localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_LIGHT_REFRESH, null);
}, CommonConstants.FOLDER_MISSION_TIMEOUT);
} else {
if (folderAppInfo.length > 0) {
this.updateFolderAppLocation(folderAppInfo);
}
localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_ADD_TO_FOLDER, null);
}
}
public registerFolderStatusChangeListener(listener: Function): void {
if (!listener && DeviceHelper.isFoldButNotSmallFoldProduct()) {
return;
}
this.foldStatusChangeCallbacksInFolder.add(listener);
}
public unregisterFolderStatusChangeListener(listener: Function): void {
if (!listener && DeviceHelper.isFoldButNotSmallFoldProduct()) {
return;
}
this.foldStatusChangeCallbacksInFolder.delete(listener);
}
public reLayoutFolder(): void {
this.reLayoutResident();
this.foldStatusChangeCallbacksInFolder?.forEach((listener: Function) => {
listener?.();
});
}
private reLayoutResident(): void {
let residentList: DockItemInfo[] = ResidentLayoutCacheMgr.getInstance().getAllDockItems();
let newResidentList: Array<DockItemInfo> = [];
for (let i = 0; i < residentList.length; i++) {
let mLayoutInfo = residentList[i].layoutInfo;
if (residentList[i].typeId !== CommonConstants.TYPE_FOLDER || !mLayoutInfo || mLayoutInfo.length === 0) {
newResidentList.push(residentList[i]);
continue;
}
let folderApps: GridLayoutItemInfo[] = mLayoutInfo.flat();
this.updateFolderAppLocation(folderApps);
residentList[i].layoutInfo = this.translateFolderLayout(folderApps);
newResidentList.push(residentList[i]);
RdbStoreManager.getInstance().addInfoToFolder(residentList[i].appId ?? '', folderApps);
}
this.mSettingsModel.setResidentList(newResidentList);
ResidentLayoutCacheMgr.getInstance().updateAllDockItems(TAG.concat('_reLayout'), residentList, true);
}
* translate appInfos to FolderLayout
* appInfos是一维数组,folderItem.layoutInfo是二维分页
*
* @param {GridLayoutItemInfo[]} appInfos.
* @return {GridLayoutItemInfo[][]} folderItem layout
*/
public translateFolderLayout(appInfos: GridLayoutItemInfo[]): GridLayoutItemInfo[][] {
let folderLayout: GridLayoutItemInfo[][] = [];
let folderOpenColumn = this.mFolderModel.getFolderOpenLayout()?.column ?? 0;
let folderOpenRow = this.mFolderModel.getFolderOpenLayout()?.row ?? 0;
const allCount = folderOpenColumn * folderOpenRow;
if (appInfos.length > allCount && allCount > 0) {
let integer = Math.floor(appInfos.length / allCount);
let remainder = appInfos.length % allCount;
for (let i = 0; i < integer; i++) {
folderLayout.push(appInfos.slice(i * allCount, (i + 1) * allCount));
}
if (remainder !== 0) {
folderLayout.push(appInfos.slice(integer * allCount, integer * allCount + remainder));
}
} else {
folderLayout = [appInfos];
}
return folderLayout;
}
* 是否在文件夹解散过程中
*/
public isFolderDisappearing(): boolean {
let disappearLastAppData: DisappearLastAppData | undefined = AppStorage.get('disappearLastAppData');
let isDisappearFolderIdValid: boolean = typeof disappearLastAppData?.folderId !== 'undefined';
let isDisappearFolderIdNotEmpty: boolean = disappearLastAppData?.folderId !== '';
log.showInfo('isDisappearFolderIdValid = %{public}s, isDisappearFolderIdNotEmpty = %{public}s',
isDisappearFolderIdValid, isDisappearFolderIdNotEmpty);
return isDisappearFolderIdValid && isDisappearFolderIdNotEmpty;
}
* 设置文件夹解散全局变量
*/
public setDisappearFolderData(folderId: string, lastAppKeyName: string, hiddenAppKeyName: string): void {
log.showInfo('setDisappearFolderData, folderId=%{public}s', folderId);
let isFolderIdEmpty: boolean = CheckEmptyUtils.checkStrIsEmpty(folderId);
if (isFolderIdEmpty || folderId === CommonConstants.INVALID_FOLDER_ID) {
log.showError('Invalid FolderId, isFolderIdEmpty = %{public}s', isFolderIdEmpty);
return;
}
const disappearLastAppData: DisappearLastAppData = {
folderId: folderId,
lastAppKeyName: lastAppKeyName,
hiddenAppKeyName: hiddenAppKeyName,
};
AppStorage.setOrCreate('disappearLastAppData', disappearLastAppData);
}
public isFolderClose(): boolean {
let openFolderStatus: number = AppStorage.get<number>('openFolderStatus') as number;
let openFolderId: string | undefined = AppStorage.get('openFolderId');
return openFolderId === '-1' && openFolderStatus === CommonConstants.OPEN_FOLDER_STATUS_TRANSITION_START;
}
* 获取文件夹最大应用数量
*/
public static getMaxAppCount(): number {
let numPerPage: number = StyleConstants.DEFAULT_FOLDER_OPEN_ROW_SIZE * StyleConstants.DEFAULT_FOLDER_OPEN_COL_SIZE;
if (DeviceHelper.isFold() || DeviceHelper.isPad()) {
numPerPage = StyleConstants.DEFAULT_FOLDER_OPEN_ROW_SIZE_EXPENDED * StyleConstants.DEFAULT_FOLDER_OPEN_COL_SIZE;
}
return numPerPage * StyleConstants.FOLDER_APP_MAX_PAGES;
}
* 将布局元素中包含的空元素过滤掉.
*
* @returns 返回不包含空白元素的布局列表.
*/
public static filterEmptyItemInLayout(layout: GridLayoutItemInfo[]): GridLayoutItemInfo[] {
if (ObjUtil.isInvalid(layout)) {
log.showInfo('filterEmptyItemInLayout is empty');
return [];
}
let res: GridLayoutItemInfo[] = layout.filter((item: GridLayoutItemInfo, index: number) => {
if (ObjUtil.isInvalid(item)) {
log.showInfo('filterEmptyItemInLayout item invalid, index: ' + index);
return false;
}
return true;
});
return res;
}
* 将文件夹布局元素中包含的空元素过滤掉.
*
* @returns 返回不包含空白元素的文件夹布局列表.
*/
public static filterEmptyItemInFolder(layout: FolderAppItemInfo[]): FolderAppItemInfo[] {
if (ObjUtil.isInvalid(layout)) {
log.showInfo('filterEmptyItemInFolder is empty');
return [];
}
let res: FolderAppItemInfo[] = layout.filter((item: FolderAppItemInfo, index: number) => {
if (ObjUtil.isInvalid(item)) {
log.showInfo('filterEmptyItemInFolder item invalid, index: ' + index);
return false;
}
return true;
});
return res;
}
* 判断一个文件夹是否已满
*/
public static isFolderFull(itemInfo: GridLayoutItemInfo): boolean {
if (ObjUtil.isInvalid(itemInfo)) {
return false;
}
if (itemInfo.typeId !== CommonConstants.TYPE_FOLDER) {
return false;
}
return FolderViewModel.isLayoutFull(itemInfo.layoutInfo);
}
* 多选拖拽进文件夹时判断一个文件夹是否能装下拖拽图标
*
* @param itemInfo 落位所在位置的图标
* @param dragItems 拖拽图标
* @returns 文件夹是否能装下拖拽图标
*/
public static canFolderDropIn(itemInfo: GridLayoutItemInfo, dragItems: GridLayoutItemInfo[]): boolean {
let limit: number = FolderViewModel.getMaxAppCount();
if (ObjUtil.isInvalid(itemInfo)) {
return false;
}
if (GridLayoutUtil.isIconType(itemInfo.typeId)) {
if (dragItems.length + 1 <= limit) {
return true;
}
return false;
}
let items: GridLayoutItemInfo[] = itemInfo.layoutInfo?.flat() ?? [];
let appCount: number = items.length;
return (appCount + dragItems.length) <= limit;
}
* 判断要拖入的应用是不是在文件夹布局内
*/
public static isInFolder(itemInfo: GridLayoutItemInfo, dragItemInfo: GridLayoutItemInfo): boolean {
if (ObjUtil.isInvalid(itemInfo) || ObjUtil.isInvalid(dragItemInfo)) {
return false;
}
if (itemInfo.typeId !== CommonConstants.TYPE_FOLDER) {
return false;
}
let items: GridLayoutItemInfo[] = itemInfo.layoutInfo?.flat() ?? [];
let dragKeyName: string = AppItemInfo.getKeyName(dragItemInfo);
let index: number = items.findIndex((item: GridLayoutItemInfo) => {
return AppItemInfo.getKeyName(item) === dragKeyName;
});
return index >= 0;
}
* 判断应用能否拖入到文件夹内
*/
public static canDragIn(itemInfo: GridLayoutItemInfo, dragItemInfo: GridLayoutItemInfo): boolean {
if (FolderViewModel.isInFolder(itemInfo, dragItemInfo)) {
return true;
};
return !FolderViewModel.isFolderFull(itemInfo);
}
* 判断二维数组布局是否为满文件夹
*/
public static isLayoutFull(layoutInfo: GridLayoutItemInfo[][] | undefined): boolean {
let limit: number = FolderViewModel.getMaxAppCount();
return FolderViewModel.getAppCountWithoutAdd(layoutInfo) >= limit;
}
public static showToast(resId: string): void {
try {
promptAction.showToast({
message: $r(resId)
});
} catch (err) {
log.showError('showToast failed: ${public}d: %{public}s', err.code, err.message);
}
}
* 获取一个二维数组布局的应用数量,排除掉最后一个ADD
*/
public static getAppCountWithoutAdd(layoutInfo: GridLayoutItemInfo[][] | undefined): number {
let items: GridLayoutItemInfo[] = layoutInfo?.flat() ?? [];
let appCount: number = items.length;
if (items[appCount - 1]?.typeId === CommonConstants.TYPE_ADD) {
return appCount - 1;
}
return appCount;
}
}
* 文件夹重命名监听
*/
export interface FolderLayoutChangeListener {
rename?: (name: string) => void
}
export class DisappearLastAppData {
folderId: string = '';
lastAppKeyName: string | undefined = '';
hiddenAppKeyName: string = '';
restApp?: GridLayoutItemInfo | undefined = undefined;
uninstallApp?: GridLayoutItemInfo | undefined = undefined;
}
export enum SmallFolderRegion {
LEFT_UP_REGION = 0,
RIGHT_UP_REGION = 1,
LEFT_DOWN_REGION = 2,
RIGHT_DOWN_REGION = 3
};