1/* 2 * Copyright (c) 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 '../utils/Log'; 17import { SettingsModel } from '../model/SettingsModel'; 18import { StyleConstants } from '../constants/StyleConstants'; 19import { CommonConstants } from '../constants/CommonConstants'; 20import { PresetStyleConstants } from '../constants/PresetStyleConstants'; 21import { layoutConfigManager } from '../layoutconfig/LayoutConfigManager'; 22import { LauncherLayoutStyleConfig } from '../layoutconfig/LauncherLayoutStyleConfig'; 23 24const TAG = 'LayoutViewModel'; 25 26/** 27 * layout viewmodel 28 */ 29export class LayoutViewModel { 30 private mIsPad = true; 31 private mScreenHeight: number | undefined; 32 private mScreenWidth: number | undefined; 33 private mWorkSpaceHeight: number | undefined; 34 private mDockHeight: number | undefined; 35 private mSysUITopHeight: number | undefined; 36 private mSysUIBottomHeight: number | undefined; 37 private mIndicatorHeight: number | undefined; 38 private readonly mLauncherLayoutStyleConfig: LauncherLayoutStyleConfig; 39 private mNavigationBarStatus = false; 40 private mDesktopGap: number | undefined; 41 private mDesktopIconMarginLeft: number | undefined; 42 private mDesktopIconMarginTop: number | undefined; 43 private mDesktopNameHeight: number | undefined; 44 private mDesktopNameLines: number | undefined; 45 private mDesktopIconNameMargin: number | undefined; 46 private mDesktopIconSize: number | undefined; 47 private mDesktopItemSize: number | undefined; 48 private mDesktopNameSize: number | undefined; 49 private mDesktopFolderSize: number | undefined; 50 private mGridRealHeight: number | undefined; 51 private mCommonDialogWidth = ''; 52 53 private constructor() { 54 this.mLauncherLayoutStyleConfig = layoutConfigManager.getStyleConfig( 55 LauncherLayoutStyleConfig.LAUNCHER_COMMON_STYLE_CONFIG, LauncherLayoutStyleConfig.LAUNCHER_PRODUCT_STYLE_CONFIG); 56 } 57 58 /** 59 * get the LayoutViewModel instance 60 * 61 * @return LayoutViewModel 62 */ 63 static getInstance(): LayoutViewModel { 64 if (globalThis.LayoutViewModelInstance == null) { 65 globalThis.LayoutViewModelInstance = new LayoutViewModel(); 66 globalThis.LayoutViewModelInstance.initScreen(); 67 } 68 return globalThis.LayoutViewModelInstance; 69 } 70 71 /** 72 * init screen info 73 * 74 * @param navigationBarStatus 75 */ 76 initScreen(navigationBarStatus?: string): void { 77 this.mScreenWidth = AppStorage.get('screenWidth'); 78 this.mScreenHeight = AppStorage.get('screenHeight'); 79 Log.showDebug(TAG, `initScreen screenWidth: ${this.mScreenWidth}, screenHeight: ${this.mScreenHeight}`); 80 this.mSysUITopHeight = this.mLauncherLayoutStyleConfig.mSysTopHeight; 81 this.mNavigationBarStatus = navigationBarStatus === '0' ? true : false; 82 83 if (!this.mNavigationBarStatus) { 84 if (this.mScreenWidth > this.mScreenHeight) { 85 this.mSysUIBottomHeight = this.mLauncherLayoutStyleConfig.mSysBottomHeight * this.mScreenWidth / 1280; 86 } else { 87 this.mSysUIBottomHeight = this.mLauncherLayoutStyleConfig.mSysBottomHeight * this.mScreenWidth / 360; 88 } 89 } else { 90 this.mSysUIBottomHeight = 0; 91 } 92 AppStorage.setOrCreate('sysUIBottomHeight', this.mSysUIBottomHeight); 93 this.mIndicatorHeight = this.mLauncherLayoutStyleConfig.mIndicatorHeight; 94 Log.showDebug(TAG, `initScreen SysUIBottomHeight: ${this.mSysUIBottomHeight}, 95 IndicatorHeight: ${this.mIndicatorHeight}, SysUITopHeight: ${this.mSysUITopHeight}, 96 SysUIBottomHeight: ${this.mSysUIBottomHeight}`); 97 this.mCommonDialogWidth = this.mLauncherLayoutStyleConfig.mCommonDialogWidth; 98 } 99 100 /** 101 * set device type 102 * 103 * @param deviceType: Device type 104 */ 105 setDevice(deviceType: string): void { 106 this.mIsPad = deviceType === CommonConstants.PAD_DEVICE_TYPE; 107 AppStorage.setOrCreate('isPad', this.mIsPad); 108 } 109 110 getSysUITopHeight(): number { 111 return this.mSysUITopHeight; 112 } 113 114 getSysUIBottomHeight(): number { 115 return this.mSysUIBottomHeight; 116 } 117 118 /** 119 * get workSpaceHeight 120 */ 121 getWorkSpaceHeight(): number { 122 return this.mWorkSpaceHeight; 123 } 124 125 /** 126 * get dockHeight 127 */ 128 getDockHeight(): number { 129 return this.mDockHeight; 130 } 131 132 /** 133 * get UninstallDialogWidth 134 */ 135 getCommonDialogWidth(): string { 136 return this.mCommonDialogWidth; 137 } 138 139 /** 140 * get indicatorHeight 141 */ 142 getIndicator(): number { 143 return this.mIndicatorHeight; 144 } 145 146 /** 147 * calculate dock 148 */ 149 calculateDock(): any { 150 Log.showInfo(TAG, 'calculateDock start'); 151 let margin = this.mLauncherLayoutStyleConfig.mDockSaveMargin; 152 let dockGap = this.mLauncherLayoutStyleConfig.mDockGutter; 153 let iconSize = this.mLauncherLayoutStyleConfig.mDockIconSize; 154 let listItemGap = this.mLauncherLayoutStyleConfig.mDockItemGap; 155 let dockPadding = this.mLauncherLayoutStyleConfig.mDockPadding; 156 let marginBottom = this.mLauncherLayoutStyleConfig.mDockMarginBottomHideBar; 157 if (!this.mNavigationBarStatus) { 158 marginBottom = this.mLauncherLayoutStyleConfig.mDockMarginBottom; 159 } 160 let maxDockNum = 0; 161 let dockSpaceWidth = this.mScreenWidth - 2 * margin; 162 let maxRecentNum = 3; 163 if (this.mScreenWidth < PresetStyleConstants.DEFAULT_DOCK_RECENT_WIDTH || !this.mIsPad) { 164 maxRecentNum = 0; 165 maxDockNum = ~~((dockSpaceWidth - 2 * dockPadding + listItemGap) / (iconSize + listItemGap)); 166 } else { 167 let maxNum = ~~((dockSpaceWidth - dockGap - 4 * dockPadding + 2 * listItemGap) / (iconSize + listItemGap)); 168 maxDockNum = maxNum - maxRecentNum; 169 } 170 this.mDockHeight = iconSize + 2 * dockPadding + marginBottom; 171 this.mWorkSpaceHeight = this.mScreenHeight - this.mSysUIBottomHeight - this.mDockHeight; 172 let result = { 173 mDockGap: dockGap, 174 mIconSize: iconSize, 175 mListItemWidth: iconSize, 176 mListItemHeight: iconSize, 177 mListItemGap: listItemGap, 178 mDockPadding: dockPadding, 179 mMaxRecentNum: maxRecentNum, 180 mMaxDockNum: maxDockNum, 181 mDockHeight: iconSize + 2 * dockPadding, 182 mMarginBottom: marginBottom 183 }; 184 return result; 185 } 186 187 /** 188 * calculate desktop 189 */ 190 calculateDesktop(): any { 191 Log.showInfo(TAG, 'calculateDesktop start'); 192 let margin = this.mLauncherLayoutStyleConfig.mMargin; 193 let realWidth = this.mScreenWidth - 2 * margin; 194 let realHeight = this.mWorkSpaceHeight - this.mIndicatorHeight - this.mSysUITopHeight; 195 if (this.mNavigationBarStatus) { 196 realHeight = realHeight - this.mLauncherLayoutStyleConfig.mSysBottomHeight; 197 } 198 let itemSize = this.mLauncherLayoutStyleConfig.mAppItemSize; 199 let minGutter = this.mLauncherLayoutStyleConfig.mGridGutter; 200 let column = ~~((realWidth + minGutter) / (itemSize + minGutter)); 201 let userWidth = (realWidth + minGutter - (itemSize + minGutter) * column); 202 let gutter = (userWidth / (column - 1)) + minGutter; 203 let row = ~~((realHeight + gutter) / (itemSize + gutter)); 204 let marginTop = ((realHeight + gutter - (itemSize + gutter) * row) / 2); 205 if (!this.mIsPad) { 206 if (row > 6) { 207 row = 6; 208 } 209 210 if (this.mNavigationBarStatus) { 211 realHeight = realHeight + this.mLauncherLayoutStyleConfig.mSysBottomHeight; 212 } 213 let remainHeight = (realHeight + gutter - (itemSize + gutter) * row) 214 realHeight -= remainHeight 215 marginTop = remainHeight / 2 + this.mSysUITopHeight 216 } 217 //set desktop icon 218 let ratio = this.mLauncherLayoutStyleConfig.mIconRatio; 219 let lines = this.mLauncherLayoutStyleConfig.mNameLines; 220 let appTextSize = this.mLauncherLayoutStyleConfig.mNameSize; 221 let nameHeight = this.mLauncherLayoutStyleConfig.mNameHeight; 222 let iconNameMargin = this.mLauncherLayoutStyleConfig.mIconNameGap; 223 let iconMarginVertical = ratio * itemSize; 224 let iconHeight = itemSize - 2 * iconMarginVertical - nameHeight - iconNameMargin; 225 let iconMarginHorizontal = (itemSize - iconHeight) / 2; 226 if (AppStorage.get('isPortrait') ) { 227 row = 11; 228 column = 5; 229 } 230 this.updateGrid(row, column); 231 232 this.mDesktopGap = gutter; 233 this.mDesktopIconMarginLeft = iconMarginHorizontal; 234 this.mDesktopIconMarginTop = iconMarginVertical; 235 this.mDesktopNameLines = lines; 236 this.mDesktopNameHeight = nameHeight; 237 this.mDesktopIconNameMargin = iconNameMargin; 238 this.mDesktopIconSize = iconHeight; 239 this.mDesktopItemSize = itemSize; 240 this.mDesktopNameSize = appTextSize; 241 this.mGridRealHeight = realHeight; 242 //set desktop config 243 let result = { 244 mMargin: margin, 245 mColumnsGap: gutter, 246 mRowsGap: gutter, 247 mColumns: column, 248 mRows: row, 249 mDesktopMarginTop: marginTop, 250 mGridWidth: realWidth, 251 mGridHeight: realHeight, 252 mAppItemSize: itemSize, 253 mNameSize: appTextSize, 254 mNameHeight: nameHeight, 255 mIconNameMargin: iconNameMargin, 256 mIconSize: iconHeight, 257 mNameLines: lines, 258 mIconMarginHorizontal: iconMarginHorizontal, 259 mIconMarginVertical: iconMarginVertical 260 }; 261 return result; 262 } 263 264 /** 265 * calculate desktop folder 266 * 267 * @param layoutInfo folder layoutInfo 268 */ 269 calculateFolder(layoutInfo: any): any { 270 Log.showInfo(TAG, 'calculateFolder start'); 271 let itemSize = this.mLauncherLayoutStyleConfig.mAppItemSize; 272 let gap = this.mDesktopGap; 273 let iconMargin = this.mDesktopIconMarginLeft; 274 let gridColumn = SettingsModel.getInstance().getGridConfig().row; 275 let folderSize = this.mGridRealHeight / gridColumn + itemSize - iconMargin * 2; 276 let folderGutter = this.mLauncherLayoutStyleConfig.mFolderGutterRatio * folderSize; 277 let folderMargin = this.mLauncherLayoutStyleConfig.mFolderMarginRatio * folderSize; 278 279 let column = layoutInfo?.column; 280 let iconSize = (folderSize - folderGutter * 2 - folderMargin * 2) / column; 281 let nameHeight = this.mDesktopNameHeight; 282 let nameLines = this.mDesktopNameLines; 283 let iconNameMargin = this.mDesktopIconNameMargin; 284 285 this.mDesktopFolderSize = folderSize; 286 let result = { 287 mGridSize: folderSize, 288 mFolderAppSize: iconSize, 289 mFolderGridGap: folderGutter, 290 mGridMargin: folderMargin, 291 mNameHeight: nameHeight, 292 mNameLines: nameLines, 293 mIconNameMargin: iconNameMargin 294 }; 295 return result; 296 } 297 298 /** 299 * calculate open folder 300 * 301 * @param openFolderConfig layoutInfo 302 */ 303 calculateOpenFolder(openFolderConfig: any): any { 304 Log.showInfo(TAG, 'calculateOpenFolder start'); 305 let row = openFolderConfig?.row; 306 let column = openFolderConfig?.column; 307 let gutter = this.mLauncherLayoutStyleConfig.mFolderOpenGutter; 308 let padding = this.mLauncherLayoutStyleConfig.mFolderOpenPADDING; 309 let margin = this.mLauncherLayoutStyleConfig.mFolderOpenMargin; 310 let title = this.mLauncherLayoutStyleConfig.mFolderOpenTitle; 311 let itemSize = this.mDesktopItemSize; 312 let layoutWidth = column * itemSize + (column - 1) * gutter + 2 * padding; 313 let layoutHeight = row * itemSize + (row - 1) * gutter + 2 * padding; 314 let layoutSwiperHeight = row * itemSize + (row - 1) * gutter + 2 * padding + itemSize; 315 let result = { 316 mOpenFolderGridWidth: layoutWidth, 317 mOpenFolderGridHeight: layoutHeight, 318 mOpenFolderSwiperHeight: layoutSwiperHeight, 319 mOpenFolderAddIconSize: this.mDesktopIconSize, 320 mOpenFolderIconSize: this.mDesktopIconSize, 321 mOpenFolderAppSize: this.mDesktopItemSize, 322 mOpenFolderAppNameSize: this.mDesktopNameSize, 323 mOpenFolderAppNameHeight: this.mDesktopNameHeight, 324 mOpenFolderGridRow: row, 325 mOpenFolderGridColumn: column, 326 mOpenFolderGridGap: gutter, 327 mOpenFolderGridPadding: padding, 328 mFolderOpenMargin: margin, 329 mFolderOpenTitle: title, 330 mOpenFolderGridIconTopPadding: this.mDesktopIconMarginTop 331 }; 332 return result; 333 } 334 335 /** 336 * calculate add app 337 * 338 * @param addFolderConfig 339 */ 340 calculateFolderAddList(addFolderConfig: any): any { 341 Log.showInfo(TAG, 'calculateFolderAddList start'); 342 let column: number = addFolderConfig?.column; 343 let margin: number = this.mLauncherLayoutStyleConfig.mFolderAddGridMargin; 344 let saveMargin: number = PresetStyleConstants.DEFAULT_SCREEN_GRID_GAP_AND_MARGIN; 345 let screenGap: number = PresetStyleConstants.DEFAULT_SCREEN_GRID_GAP_AND_MARGIN; 346 let gap: number = this.mLauncherLayoutStyleConfig.mFolderAddGridGap; 347 let maxHeight: number = this.mLauncherLayoutStyleConfig.mFolderAddMaxHeight * 348 (this.mScreenHeight - this.mSysUITopHeight); 349 let toggleSize: number = this.mLauncherLayoutStyleConfig.mFolderToggleSize; 350 let screenColumns: number = PresetStyleConstants.DEFAULT_PHONE_GRID_APP_COLUMNS; 351 let textSize: number = this.mLauncherLayoutStyleConfig.mFolderAddTextSize; 352 let textLines: number = this.mLauncherLayoutStyleConfig.mFolderAddTextLines; 353 let titleSize: number = this.mLauncherLayoutStyleConfig.mFolderAddTitleSize; 354 let linesHeight = textSize * textLines; 355 let buttonSize: number = this.mLauncherLayoutStyleConfig.mFolderAddButtonSize; 356 let ratio: number = this.mLauncherLayoutStyleConfig.mFolderAddIconRatio; 357 if (this.mIsPad) { 358 screenColumns = PresetStyleConstants.DEFAULT_PAD_GRID_APP_COLUMNS; 359 } 360 let columnsWidth = this.mScreenWidth - 2 * saveMargin - (screenColumns - 1) * screenGap; 361 let columnWidth = columnsWidth / screenColumns; 362 let layoutWidth = columnWidth * column + (column - 1) * screenGap; 363 let gridSize = layoutWidth - 2 * margin; 364 let itemSize = (gridSize - (column - 1) * gap) / column; 365 let layoutHeight = layoutWidth + StyleConstants.DEFAULT_APP_ADD_TITLE_SIZE + 366 StyleConstants.DEFAULT_BUTTON_HEIGHT_NUMBER + 367 StyleConstants.DEFAULT_DIALOG_BOTTOM_MARGIN_NUMBER; 368 let iconSize = (1 - 2 * ratio) * itemSize - linesHeight - this.mDesktopIconNameMargin; 369 370 let result = { 371 mAddFolderGridWidth: gridSize, 372 mAddFolderDialogWidth: layoutWidth, 373 mAddFolderDialogHeight: layoutHeight, 374 mAddFolderGridGap: gap, 375 mAddFolderGridMargin: margin, 376 mAddFolderMaxHeight: maxHeight, 377 mFolderToggleSize: toggleSize, 378 mAddFolderTextSize: textSize, 379 mAddFolderTextLines: textLines, 380 mAddFolderLinesHeight: linesHeight, 381 mAddFolderItemSize: itemSize, 382 mAddFolderIconPaddingTop: itemSize * ratio, 383 mAddFolderIconMarginHorizontal: (itemSize - iconSize) / 2, 384 mAddFolderIconSize: iconSize, 385 mAddFolderTitleSize: titleSize, 386 mAddFolderButtonSize: buttonSize 387 }; 388 return result; 389 } 390 391 /** 392 * calculate card form 393 */ 394 calculateForm(): any { 395 Log.showInfo(TAG, 'calculateForm start'); 396 let iconSize = this.mDesktopIconSize; 397 let folderSize = this.mDesktopFolderSize; 398 let itemSize = this.mDesktopItemSize; 399 let gap = this.mDesktopGap; 400 let iconMarginHorizontal = this.mDesktopIconMarginLeft; 401 let iconMarginVertical = this.mDesktopIconMarginTop; 402 let nameHeight = this.mDesktopNameHeight; 403 // 1x2 404 let widthDimension1: number = folderSize; 405 let heightDimension1: number = iconSize; 406 // 2x2 407 let widthDimension2 = folderSize; 408 let heightDimension2 = folderSize; 409 // 2x4 410 let widthDimension3 = (itemSize + gap) * 4 - gap - iconMarginHorizontal * 2; 411 let heightDimension3 = folderSize; 412 // 4x4 413 let widthDimension4 = widthDimension3; 414 let heightDimension4 = (itemSize + gap) * 4 - gap - 2 * iconMarginVertical - 415 nameHeight - this.mDesktopIconNameMargin; 416 // 2x1 417 let widthDimension5 = iconSize; 418 let heightDimension5 = folderSize; 419 // 1x1 420 let widthDimension6 = iconSize; 421 let heightDimension6 = iconSize; 422 // 6x4 423 let widthDimension7 = widthDimension3; 424 let heightDimension7 = (itemSize + gap) * 6 - gap - 2 * iconMarginVertical - 425 nameHeight - this.mDesktopIconNameMargin; 426 427 let result = { 428 widthDimension1: widthDimension1, 429 heightDimension1: heightDimension1, 430 widthDimension2: widthDimension2, 431 heightDimension2: heightDimension2, 432 widthDimension3: widthDimension3, 433 heightDimension3: heightDimension3, 434 widthDimension4: widthDimension4, 435 heightDimension4: heightDimension4, 436 widthDimension5: widthDimension5, 437 heightDimension5: heightDimension5, 438 widthDimension6: widthDimension6, 439 heightDimension6: heightDimension6, 440 widthDimension7: widthDimension7, 441 heightDimension7: heightDimension7, 442 mIconNameMargin: this.mDesktopIconNameMargin 443 }; 444 return result; 445 } 446 447 /** 448 * calculate app center 449 */ 450 calculateAppCenter(): any { 451 Log.showInfo(TAG, 'calculateAppCenter start'); 452 let appCenterMarginLeft: number = this.mLauncherLayoutStyleConfig.mAppCenterMarginLeft; 453 let saveMargin: number = this.mLauncherLayoutStyleConfig.mAppCenterMargin; 454 let gutter: number = this.mLauncherLayoutStyleConfig.mAppCenterGutter; 455 let appItemSize = this.mLauncherLayoutStyleConfig.mAppCenterSize; 456 let width = this.mScreenWidth - 2 * appCenterMarginLeft; 457 let height = this.mWorkSpaceHeight; 458 let column = ~~((width + gutter) / (appItemSize + gutter)); 459 let row = ~~((height + gutter) / (appItemSize + gutter)); 460 let padding = (height - row * (appItemSize + gutter) + gutter) / 2; 461 let ratio = this.mLauncherLayoutStyleConfig.mAppCenterRatio; 462 let lines = this.mLauncherLayoutStyleConfig.mAppCenterNameLines; 463 let appTextSize = this.mLauncherLayoutStyleConfig.mAppCenterNameSize; 464 let nameHeight = lines * appTextSize; 465 let iconMarginVertical = ratio * appItemSize; 466 let iconHeight = appItemSize - 2 * iconMarginVertical - nameHeight - this.mDesktopIconNameMargin; 467 let result = { 468 mColumnsGap: gutter, 469 mRowsGap: gutter, 470 mColumns: column, 471 mRows: row, 472 mGridWidth: width, 473 mGridHeight: height - 2 * padding, 474 mPadding: padding, 475 mNameSize: appTextSize, 476 mNameHeight: nameHeight, 477 mIconSize: iconHeight, 478 mNameLines: lines, 479 mIconMarginVertical: iconMarginVertical, 480 mAppItemSize: appItemSize, 481 mAppCenterMarginLeft:appCenterMarginLeft 482 }; 483 return result; 484 } 485 486 /** 487 * update gridConfig info 488 * 489 * @param {number} row row of grid 490 * @param {number} column column of grid 491 */ 492 private updateGrid(row: number, column: number): void { 493 Log.showInfo(TAG, `updateGrid row ${row} column ${column}`); 494 let settingsModel = SettingsModel.getInstance(); 495 let gridConfig = settingsModel.getGridConfig(); 496 gridConfig.row = row; 497 gridConfig.column = column; 498 const layoutDimension = `${row}X${column}`; 499 gridConfig.layout = layoutDimension; 500 gridConfig.name = layoutDimension; 501 } 502}