1/** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { Log } from '@ohos/common'; 17import { Trace } from '@ohos/common'; 18import { CheckEmptyUtils } from '@ohos/common'; 19import { MenuInfo } from '@ohos/common'; 20import { MissionInfo } from '@ohos/common'; 21import { DockItemInfo } from '@ohos/common'; 22import { windowManager } from '@ohos/common'; 23import { layoutConfigManager } from '@ohos/common'; 24import { amsMissionManager }from '@ohos/common'; 25import { launcherAbilityManager } from '@ohos/common'; 26import { CommonConstants } from '@ohos/common'; 27import { BaseViewModel } from '@ohos/common'; 28import SmartDockStartAppHandler from '../common/SmartDockStartAppHandler'; 29import SmartDockModel from '../model/SmartDockModel'; 30import SmartDockDragHandler from '../common/SmartDockDragHandler'; 31import { SmartDockStyleConfig } from '../config/SmartDockStyleConfig'; 32import SmartDockConstants from '../common/constants/SmartDockConstants'; 33import { SmartDockLayoutConfig } from '../config/SmartDockLayoutConfig'; 34 35const TAG = 'SmartDockViewModel'; 36 37/** 38 * SmartDock Viewmodel 39 */ 40export default class SmartDockViewModel extends BaseViewModel { 41 private readonly mSmartDockLayoutConfig: SmartDockLayoutConfig; 42 private readonly mSmartDockStyleConfig: SmartDockStyleConfig; 43 private readonly mSmartDockDragHandler: SmartDockDragHandler; 44 private readonly mSmartDockStartAppHandler: SmartDockStartAppHandler; 45 private readonly mSmartDockModel: SmartDockModel; 46 private mSelectedItem: DockItemInfo; 47 private mSelectedDockType = 0; 48 private mDevice = CommonConstants.DEFAULT_DEVICE_TYPE; 49 50 constructor() { 51 super(); 52 this.mSmartDockLayoutConfig = layoutConfigManager.getFunctionConfig(SmartDockLayoutConfig.SMART_DOCK_LAYOUT_INFO); 53 this.mSmartDockStyleConfig = layoutConfigManager.getStyleConfig(SmartDockStyleConfig.APP_LIST_STYLE_CONFIG, SmartDockConstants.FEATURE_NAME); 54 this.mSmartDockDragHandler = SmartDockDragHandler.getInstance(); 55 this.mSmartDockStartAppHandler = SmartDockStartAppHandler.getInstance(); 56 this.mSmartDockModel = SmartDockModel.getInstance(); 57 } 58 59 static getInstance(): SmartDockViewModel{ 60 if (globalThis.SmartDockViewModel == null) { 61 globalThis.SmartDockViewModel = new SmartDockViewModel(); 62 } 63 return globalThis.SmartDockViewModel; 64 } 65 66 /** 67 * get SmartDockStyleConfig 68 */ 69 getStyleConfig(): SmartDockStyleConfig{ 70 return layoutConfigManager.getStyleConfig(SmartDockStyleConfig.APP_LIST_STYLE_CONFIG, SmartDockConstants.FEATURE_NAME); 71 } 72 73 /** 74 * resident dock item onClick function 75 * @param event 76 * @param item 77 * @param callback 78 */ 79 residentOnClick(event, item, callback?) { 80 // AppCenter entry 81 AppStorage.SetOrCreate('startAppTypeFromPageDesktop', CommonConstants.OVERLAY_TYPE_APP_RESIDENTIAL); 82 if (item.abilityName == CommonConstants.APPCENTER_ABILITY && callback != null) { 83 callback(); 84 return; 85 } 86 if (item.abilityName == CommonConstants.RECENT_ABILITY) { 87 globalThis.createWindowWithName(windowManager.RECENT_WINDOW_NAME, windowManager.RECENT_RANK); 88 Trace.start(Trace.CORE_METHOD_START_RECENTS); 89 return; 90 } 91 // app entry 92 Trace.start(Trace.CORE_METHOD_START_APP_ANIMATION); 93 this.setStartAppInfo(item); 94 launcherAbilityManager.startLauncherAbility(item.abilityName, item.bundleName, item.moduleName); 95 } 96 97 /** 98 * recent dock item onClick function 99 * @param event 100 * @param item 101 */ 102 public recentOnClick(event, item, callback?) { 103 AppStorage.SetOrCreate('startAppTypeFromPageDesktop', CommonConstants.OVERLAY_TYPE_APP_RECENT); 104 let missionInfoList = []; 105 missionInfoList = AppStorage.Get('missionInfoList'); 106 Log.showDebug(TAG, `recentOnClick missionInfoList.length: ${missionInfoList.length}`); 107 if (!CheckEmptyUtils.isEmptyArr(missionInfoList)) { 108 for (let i = 0; i < missionInfoList.length; i++) { 109 if (missionInfoList[i].bundleName === item.bundleName) { 110 let missionList = missionInfoList[i]?.missionInfoList; 111 Log.showDebug(TAG, 'recentOnClick missionList.length:' + missionList.length); 112 if (!CheckEmptyUtils.isEmptyArr(missionList) && missionList.length > 1) { 113 Log.showDebug(TAG, 'recentOnClick callback'); 114 callback(); 115 } else if (!CheckEmptyUtils.isEmptyArr(missionList) && missionList.length === 1) { 116 let missionId = missionInfoList[i]?.missionInfoList[0]?.missionId; 117 amsMissionManager.moveMissionToFront(missionId).then(() => {}, () => {}); 118 // set start app info 119 Trace.start(Trace.CORE_METHOD_START_APP_ANIMATION); 120 this.setStartAppInfo(item); 121 } 122 break; 123 } 124 } 125 } 126 } 127 128 /** 129 * what SmartDockContent.dockItemList onChange 130 */ 131 onDockListChange() { 132 this.updateDockParams().then(() => {}, () => {}); 133 } 134 135 /** 136 * update drag effective area when dockList changed 137 */ 138 async updateDockParams() { 139 const screenWidth: number = AppStorage.Get('screenWidth'); 140 const screenHeight: number = AppStorage.Get('screenHeight'); 141 const sysUIBottomHeight: number = AppStorage.Get('sysUIBottomHeight'); 142 const dockHeight: number = AppStorage.Get('dockHeight'); 143 let mResidentWidth: number = this.getListWidth(AppStorage.Get('residentList')); 144 if (AppStorage.Get("deviceType") === CommonConstants.DEFAULT_DEVICE_TYPE) { 145 const maxDockNum = this.getStyleConfig().mMaxDockNum; 146 mResidentWidth = this.mSmartDockStyleConfig.mDockPadding * 2 + maxDockNum * (this.mSmartDockStyleConfig.mListItemWidth) + (maxDockNum - 1) * (this.mSmartDockStyleConfig.mListItemGap); 147 } 148 AppStorage.SetOrCreate('residentWidth', mResidentWidth); 149 AppStorage.SetOrCreate("dockPadding", this.getDockPadding(mResidentWidth)); 150 const mRecentWidth: number = this.getListWidth(AppStorage.Get('recentList')); 151 Log.showDebug(TAG, `updateDockParams screenWidth:${screenWidth}, screenHeight:${screenHeight}, sysUIBottomHeight:${sysUIBottomHeight}, dockHeight:${dockHeight}, mResidentWidth:${mResidentWidth}, mRecentWidth:${mRecentWidth}`); 152 if (typeof (this.mSmartDockDragHandler) != 'undefined') { 153 let left = mResidentWidth === 0 ? 0 : (screenWidth - mResidentWidth - (mRecentWidth === 0 ? 0 : (this.mSmartDockStyleConfig.mDockGap + mRecentWidth))) / 2; 154 let right = mResidentWidth === 0 ? screenWidth : (screenWidth - mResidentWidth - (mRecentWidth === 0 ? 0 : (this.mSmartDockStyleConfig.mDockGap + mRecentWidth))) / 2 + mResidentWidth; 155 if (AppStorage.Get('deviceType') == CommonConstants.DEFAULT_DEVICE_TYPE) { 156 left = (screenWidth - mResidentWidth) / 2; 157 right = screenWidth - left; 158 } 159 this.mSmartDockDragHandler.setDragEffectArea({ 160 left: left, 161 right: right, 162 top: screenHeight - sysUIBottomHeight - dockHeight, 163 bottom: screenHeight - sysUIBottomHeight - this.mSmartDockStyleConfig.mMarginBottom 164 }); 165 } 166 } 167 168 private getDockPadding(residentWidth: number): {right: number, left: number, top: number, bottom: number} { 169 let paddingNum: number = this.mSmartDockStyleConfig.mDockPadding; 170 const residentList: [] = AppStorage.Get('residentList'); 171 if (AppStorage.Get("deviceType") === CommonConstants.DEFAULT_DEVICE_TYPE) { 172 paddingNum = (residentWidth - (residentList.length * this.mSmartDockStyleConfig.mListItemWidth + (residentList.length - 1) * (this.mSmartDockStyleConfig.mListItemGap))) / 2; 173 } 174 Log.showDebug(TAG, `getDockPadding paddingNum: ${paddingNum}`); 175 return {right: paddingNum, left: paddingNum, top: this.mSmartDockStyleConfig.mDockPadding, bottom: this.mSmartDockStyleConfig.mDockPadding}; 176 } 177 178 /** 179 * build menu for @Component CustomOverlay 180 * @param appInfo 181 * @param dockType 182 * @param callback 183 */ 184 buildMenuInfoList(appInfo, dockType, showAppcenter, callback?) { 185 const menuInfoList = new Array<MenuInfo>(); 186 const shortcutInfo = this.mSmartDockModel.getShortcutInfo(appInfo.bundleName); 187 if (shortcutInfo) { 188 let menu = null; 189 shortcutInfo.forEach((value) => { 190 menu = new MenuInfo(); 191 menu.menuType = CommonConstants.MENU_TYPE_DYNAMIC; 192 menu.menuImgSrc = value.icon; 193 menu.menuText = value.label; 194 menu.shortcutIconId = value.iconId; 195 menu.shortcutLabelId = value.labelId; 196 menu.bundleName = value.bundleName; 197 menu.moduleName = value.moduleName; 198 menu.onMenuClick = () => { 199 Trace.start(Trace.CORE_METHOD_START_APP_ANIMATION); 200 launcherAbilityManager.startLauncherAbility(value.wants[0].targetClass, value.wants[0].targetBundle, value.wants[0].targetModule); 201 }; 202 value.bundleName == appInfo.bundleName && value.moduleName == appInfo.moduleName && menuInfoList.push(menu); 203 }); 204 } 205 206 let open = new MenuInfo(); 207 open.menuType = CommonConstants.MENU_TYPE_FIXED; 208 open.menuImgSrc = '/common/pics/ic_public_add_norm.svg'; 209 open.menuText = $r('app.string.app_menu_open'); 210 open.onMenuClick = () => { 211 this.residentOnClick(null, appInfo, showAppcenter); 212 }; 213 menuInfoList.push(open); 214 215 if (appInfo.itemType != CommonConstants.TYPE_FUNCTION) { 216 this.mDevice = AppStorage.Get('deviceType'); 217 if (this.mDevice === CommonConstants.PAD_DEVICE_TYPE && dockType === SmartDockConstants.RESIDENT_DOCK_TYPE) { 218 const addToWorkSpaceMenu = new MenuInfo(); 219 addToWorkSpaceMenu.menuType = CommonConstants.MENU_TYPE_FIXED; 220 addToWorkSpaceMenu.menuImgSrc = '/common/pics/ic_public_copy.svg'; 221 addToWorkSpaceMenu.menuText = $r('app.string.app_center_menu_add_desktop'); 222 addToWorkSpaceMenu.onMenuClick = () => { 223 Log.showDebug(TAG, 'onMenuClick item add to pageDesk:' + appInfo.bundleName); 224 this.mSmartDockModel.addToPageDesk(appInfo); 225 }; 226 menuInfoList.push(addToWorkSpaceMenu); 227 } 228 229 const removeMenu = new MenuInfo(); 230 removeMenu.menuType = CommonConstants.MENU_TYPE_FIXED; 231 removeMenu.menuImgSrc = this.mDevice === CommonConstants.PAD_DEVICE_TYPE ? '/common/pics/ic_public_remove.svg' : '/common/pics/ic_public_delete.svg'; 232 removeMenu.menuText = this.mDevice === CommonConstants.PAD_DEVICE_TYPE ? $r('app.string.delete_app') : $r('app.string.uninstall'); 233 removeMenu.onMenuClick = () => { 234 Log.showDebug(TAG, `onMenuClick item remove: ${JSON.stringify(appInfo)}`); 235 const cacheKey = appInfo.appLabelId + appInfo.bundleName + appInfo.moduleName; 236 appInfo.keyName = appInfo.bundleName + appInfo.abilityName + appInfo.moduleName; 237 const appName = this.mSmartDockModel.getAppName(cacheKey); 238 Log.showDebug(TAG, `onMenuClick item remove appName: ${appName}`); 239 if (appName != null) { 240 appInfo.appName = appName; 241 } 242 this.mSelectedItem = appInfo; 243 this.mSelectedDockType = dockType; 244 AppStorage.SetOrCreate('uninstallAppInfo', appInfo); 245 callback(); 246 }; 247 removeMenu.menuEnabled = appInfo.isUninstallAble; 248 menuInfoList.push(removeMenu); 249 } 250 return menuInfoList; 251 } 252 253 deleteDockItem(dockItem: {bundleName: string | undefined, keyName: string | undefined}, dockType: number) { 254 this.mSmartDockModel.deleteDockItem(dockItem, dockType); 255 } 256 257 getSelectedItem(): any { 258 Log.showDebug(TAG, `getSelectedItem: ${JSON.stringify(this.mSelectedItem)}`); 259 return this.mSelectedItem; 260 } 261 262 getSelectedDockType(): any { 263 Log.showDebug(TAG, `getSelectedDockType: ${JSON.stringify(this.mSelectedDockType)}`); 264 return this.mSelectedDockType; 265 } 266 267 /** 268 * calcaulate dock list width after list change 269 * @param itemList 270 */ 271 private getListWidth(itemList: []): number { 272 let width = 0; 273 if (typeof itemList === 'undefined' || itemList == null || itemList.length === 0) { 274 return width; 275 } 276 const num = itemList.length; 277 width = this.mSmartDockStyleConfig.mDockPadding * 2 + num * (this.mSmartDockStyleConfig.mListItemWidth) + (num - 1) * (this.mSmartDockStyleConfig.mListItemGap); 278 return width; 279 } 280 281 /** 282 * get snapshot 283 * 284 * @param missionIds missionid list 285 * @return snapshot list 286 */ 287 async getSnapshot(missionIds: MissionInfo[], name: string) { 288 const snapshotList: { 289 name: string, 290 image: any, 291 missionId: number, 292 boxSize: number, 293 bundleName: string, 294 left?: number, 295 right?: number, 296 }[] = await this.mSmartDockModel.getSnapshot(missionIds, name); 297 return snapshotList; 298 } 299 300 /** 301 * set start app info 302 */ 303 private setStartAppInfo(item) { 304 if (CheckEmptyUtils.isEmpty(item)) { 305 Log.showError(TAG, `setStartAppInfo with item`) 306 return; 307 } 308 item.icon = globalThis.ResourceManager.getCachedAppIcon(item.appIconId, item.bundleName, item.moduleName) 309 AppStorage.SetOrCreate('startAppItemInfo', item); 310 this.mSmartDockStartAppHandler.setAppIconSize(this.mSmartDockStyleConfig.mIconSize); 311 this.mSmartDockStartAppHandler.setAppIconInfo(); 312 } 313}