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 { 17 Log, 18 BaseDragHandler, 19 CommonConstants, 20 CheckEmptyUtils, 21 SettingsModel, 22 EventConstants, 23 localEventManager, 24 layoutConfigManager, 25 PageDesktopModel 26} from '@ohos/common'; 27import type { 28 LauncherDragItemInfo, 29 DragArea, 30 DragItemPosition 31} from '@ohos/common'; 32import { FormViewModel } from '@ohos/form'; 33import { BigFolderViewModel } from '@ohos/bigfolder'; 34import { PageDesktopGridStyleConfig } from './PageDesktopGridStyleConfig'; 35import PageDesktopConstants from './constants/PageDesktopConstants' 36 37const TAG = 'PageDesktopDragHandler'; 38 39/** 40 * Desktop workspace drag and drop processing class 41 */ 42export class PageDesktopDragHandler extends BaseDragHandler { 43 private readonly mPageDesktopStyleConfig: PageDesktopGridStyleConfig; 44 private readonly mBigFolderViewModel: BigFolderViewModel; 45 private readonly mFormViewModel: FormViewModel; 46 private readonly mSettingsModel: SettingsModel; 47 private readonly mPageDesktopModel: PageDesktopModel; 48 private mGridConfig; 49 private mPageCoordinateData = { 50 gridXAxis: [], 51 gridYAxis: [] 52 }; 53 mStartPosition: DragItemPosition; 54 private mEndPosition: DragItemPosition; 55 private readonly styleConfig; 56 private mGridItemHeight: number; 57 private mGridItemWidth: number; 58 59 private constructor() { 60 super(); 61 this.mBigFolderViewModel = BigFolderViewModel.getInstance(); 62 this.mSettingsModel = SettingsModel.getInstance(); 63 this.mFormViewModel = FormViewModel.getInstance(); 64 this.mPageDesktopModel = PageDesktopModel.getInstance(); 65 this.mPageDesktopStyleConfig = layoutConfigManager.getStyleConfig(PageDesktopGridStyleConfig.APP_GRID_STYLE_CONFIG, 66 PageDesktopConstants.FEATURE_NAME); 67 } 68 69 static getInstance(): PageDesktopDragHandler { 70 if (globalThis.PageDesktopDragHandler == null) { 71 globalThis.PageDesktopDragHandler = new PageDesktopDragHandler(); 72 } 73 return globalThis.PageDesktopDragHandler; 74 } 75 76 setDragEffectArea(effectArea): void { 77 Log.showDebug(TAG, `setDragEffectArea:${JSON.stringify(effectArea)}`) 78 AppStorage.setOrCreate('pageDesktopDragEffectArea', effectArea); 79 super.setDragEffectArea(effectArea); 80 this.updateGridParam(effectArea); 81 } 82 83 isDragEffectArea(x: number, y: number): boolean { 84 const isInEffectArea = super.isDragEffectArea(x, y); 85 Log.showDebug(TAG, `isDragEffectArea x: ${x}, y: ${y}, isInEffectArea: ${isInEffectArea}`); 86 const deviceType: string = AppStorage.get('deviceType'); 87 const smartDockDragEffectArea: DragArea = AppStorage.get('smartDockDragEffectArea'); 88 Log.showDebug(TAG, `isDragEffectArea smartDockDragEffectArea: ${JSON.stringify(smartDockDragEffectArea)}`); 89 if (smartDockDragEffectArea) { 90 if (deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) { 91 if (isInEffectArea || (y <= smartDockDragEffectArea.bottom && y >= smartDockDragEffectArea.top) 92 && x <= smartDockDragEffectArea.right && x >= smartDockDragEffectArea.left) { 93 return true; 94 } 95 return false; 96 } 97 return isInEffectArea; 98 } 99 return false; 100 } 101 102 getRow(index: number): number { 103 return ~~(index / this.mSettingsModel.getGridConfig().column); 104 } 105 106 getColumn(index: number): number { 107 return index % this.mSettingsModel.getGridConfig().column; 108 } 109 110 private updateGridParam(effectArea: DragArea): void { 111 const gridWidth = this.mPageDesktopStyleConfig.mGridWidth; 112 const gridHeight = this.mPageDesktopStyleConfig.mGridHeight; 113 Log.showDebug(TAG, `updateGridParam gridWidth: ${gridWidth}, gridHeight: ${gridHeight}`); 114 this.mGridConfig = this.mSettingsModel.getGridConfig(); 115 const column = this.mGridConfig.column; 116 const row = this.mGridConfig.row; 117 const columnsGap = this.mPageDesktopStyleConfig.mColumnsGap; 118 const rowGap = this.mPageDesktopStyleConfig.mRowsGap; 119 this.mGridItemHeight = row > 0 ? (gridHeight + columnsGap) / row : 0; 120 this.mGridItemWidth = column > 0 ? (gridWidth + rowGap) / column : 0; 121 Log.showDebug(TAG, `updateGridParam column: ${column}, row: ${row}`); 122 this.mPageCoordinateData.gridYAxis = []; 123 for (let i = 1; i <= row; i++) { 124 const touchPositioningY = (gridHeight / row) * i + effectArea.top; 125 this.mPageCoordinateData.gridYAxis.push(touchPositioningY); 126 } 127 128 this.mPageCoordinateData.gridXAxis = []; 129 for (let i = 1; i <= column; i++) { 130 const touchPositioningX = (gridWidth / column) * i + effectArea.left; 131 this.mPageCoordinateData.gridXAxis.push(touchPositioningX); 132 } 133 } 134 135 protected getDragRelativeData(): any { 136 const desktopDataInfo: { 137 appGridInfo: [[]] 138 } = AppStorage.get('appListInfo'); 139 return desktopDataInfo.appGridInfo; 140 } 141 142 getItemIndex(x: number, y: number): number { 143 Log.showInfo(TAG, `getItemIndex x: ${x}, y: ${y}`); 144 let rowVal = CommonConstants.INVALID_VALUE; 145 for (let index = 0; index < this.mPageCoordinateData.gridYAxis.length; index++) { 146 if (this.mPageCoordinateData.gridYAxis[index] > y) { 147 rowVal = index; 148 break; 149 } 150 } 151 let columnVal = CommonConstants.INVALID_VALUE; 152 for (let index = 0; index < this.mPageCoordinateData.gridXAxis.length; index++) { 153 if (this.mPageCoordinateData.gridXAxis[index] > x) { 154 columnVal = index; 155 break; 156 } 157 } 158 const column = this.mGridConfig.column; 159 if (rowVal != CommonConstants.INVALID_VALUE && columnVal != CommonConstants.INVALID_VALUE) { 160 return rowVal * column + columnVal; 161 } 162 return CommonConstants.INVALID_VALUE; 163 } 164 165 protected getItemByIndex(index: number): any { 166 const column = index % this.mGridConfig.column; 167 const row = Math.floor(index / this.mGridConfig.column); 168 const pageIndex: number = AppStorage.get('pageIndex'); 169 const appGridInfo = this.getDragRelativeData(); 170 Log.showInfo(TAG, `getItemByIndex pageIndex: ${pageIndex}, appGridInfo length: ${appGridInfo.length}, 171 column: ${column}, row: ${row}`); 172 const itemInfo = appGridInfo[pageIndex].find(item => { 173 if (item.typeId == CommonConstants.TYPE_APP) { 174 return item.column == column && item.row == row; 175 } else if (item.typeId == CommonConstants.TYPE_FOLDER || item.typeId == CommonConstants.TYPE_CARD) { 176 return this.isItemInRowColumn(row, column, item); 177 } 178 }); 179 return itemInfo; 180 } 181 182 /** 183 * judge the item is at target row and column 184 * @param row 185 * @param column 186 * @param item 187 */ 188 private isItemInRowColumn(row: number, column: number, item: any): boolean { 189 return item.column <= column && column < item.column + item.area[0] && item.row <= row && row < item.row + item.area[1]; 190 } 191 192 getTouchPosition(x: number, y: number): DragItemPosition { 193 const pageIndex: number = AppStorage.get('pageIndex'); 194 Log.showDebug(TAG, `getTouchPosition pageIndex: ${pageIndex}`); 195 const position: DragItemPosition = { 196 page: pageIndex, 197 row: 0, 198 column: 0, 199 X: x, 200 Y: y, 201 }; 202 for (let i = 0; i < this.mPageCoordinateData.gridXAxis.length; i++) { 203 if (x < this.mPageCoordinateData.gridXAxis[i]) { 204 position.column = i; 205 break; 206 } else { 207 position.column = this.mPageCoordinateData.gridXAxis.length - 1; 208 } 209 } 210 for (let i = 0; i < this.mPageCoordinateData.gridYAxis.length; i++) { 211 if (y < this.mPageCoordinateData.gridYAxis[i]) { 212 position.row = i; 213 break; 214 } else { 215 position.row = this.mPageCoordinateData.gridYAxis.length - 1; 216 } 217 } 218 return position; 219 } 220 221 onDragStart(x: number, y: number): void { 222 this.mStartPosition = null; 223 Log.showInfo(TAG, 'onDragStart start'); 224 const selectAppIndex = this.getItemIndex(x, y); 225 AppStorage.setOrCreate('selectAppIndex', selectAppIndex); 226 this.mStartPosition = this.getTouchPosition(x, y); 227 } 228 229 onDragDrop(x: number, y: number): boolean { 230 const dragItemInfo: LauncherDragItemInfo = AppStorage.get<LauncherDragItemInfo>('dragItemInfo'); 231 if (!dragItemInfo.isDragging) { 232 return false; 233 } 234 const dragItemType: number = AppStorage.get('dragItemType'); 235 const deviceType: string = AppStorage.get('deviceType') 236 // dock appInfo has no location information. 237 if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) { 238 dragItemInfo.typeId = CommonConstants.TYPE_APP; 239 dragItemInfo.area = [1, 1]; 240 dragItemInfo.page = AppStorage.get('pageIndex'); 241 } 242 Log.showDebug(TAG, `onDragEnd dragItemInfo: ${JSON.stringify(dragItemInfo)}`); 243 const endIndex = this.getItemIndex(x, y); 244 const startPosition: DragItemPosition = this.copyPosition(this.mStartPosition); 245 let endPosition: DragItemPosition = null; 246 this.mEndPosition = this.getTouchPosition(x, y); 247 Log.showDebug(TAG, `onDragEnd mEndPosition: ${JSON.stringify(this.mEndPosition)}`); 248 endPosition = this.copyPosition(this.mEndPosition); 249 const info = this.mSettingsModel.getLayoutInfo(); 250 const layoutInfo = info.layoutInfo; 251 if (dragItemInfo.typeId == CommonConstants.TYPE_FOLDER || dragItemInfo.typeId == CommonConstants.TYPE_CARD) { 252 this.updateEndPosition(dragItemInfo); 253 } else { 254 if (this.isMoveToSamePosition(dragItemInfo)) { 255 this.deleteBlankPageAfterDragging(startPosition, endPosition); 256 return false; 257 } 258 const endLayoutInfo = this.getEndLayoutInfo(layoutInfo); 259 if (endLayoutInfo != undefined) { 260 // add app to folder 261 if (endLayoutInfo.typeId === CommonConstants.TYPE_FOLDER) { 262 this.mBigFolderViewModel.addOneAppToFolder(dragItemInfo, endLayoutInfo.folderId); 263 if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) { 264 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo); 265 } 266 this.deleteBlankPageAfterDragging(startPosition, endPosition); 267 return true; 268 } else if (endLayoutInfo.typeId === CommonConstants.TYPE_APP) { 269 // create a new folder 270 const layoutInfoList = [endLayoutInfo]; 271 let startLayoutInfo = null; 272 if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) { 273 let appInfoList = this.mSettingsModel.getAppListInfo(); 274 const appIndex = appInfoList.findIndex(item => { 275 return item.keyName === dragItemInfo.keyName; 276 }) 277 if (appIndex == CommonConstants.INVALID_VALUE) { 278 appInfoList.push({ 279 "appName": dragItemInfo.appName, 280 "isSystemApp": dragItemInfo.isSystemApp, 281 "isUninstallAble": dragItemInfo.isUninstallAble, 282 "appIconId": dragItemInfo.appIconId, 283 "appLabelId": dragItemInfo.appLabelId, 284 "bundleName": dragItemInfo.bundleName, 285 "abilityName": dragItemInfo.abilityName, 286 "moduleName": dragItemInfo.moduleName, 287 "keyName": dragItemInfo.keyName, 288 "typeId": dragItemInfo.typeId, 289 "area": dragItemInfo.area, 290 "page": dragItemInfo.page, 291 "column": this.getColumn(endIndex), 292 "row": this.getRow(endIndex), 293 "x": 0, 294 "installTime": dragItemInfo.installTime, 295 "badgeNumber": dragItemInfo.badgeNumber 296 }) 297 this.mSettingsModel.setAppListInfo(appInfoList); 298 } 299 startLayoutInfo = dragItemInfo; 300 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo); 301 } else { 302 startLayoutInfo = this.getStartLayoutInfo(layoutInfo, dragItemInfo); 303 } 304 layoutInfoList.push(startLayoutInfo); 305 this.mBigFolderViewModel.addNewFolder(layoutInfoList).then(()=> { 306 this.deleteBlankPageAfterDragging(startPosition, endPosition); 307 }); 308 return true; 309 } else if (endLayoutInfo.typeId === CommonConstants.TYPE_CARD) { 310 if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) { 311 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_ADD, dragItemInfo); 312 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo); 313 localEventManager.sendLocalEventSticky(EventConstants.EVENT_SMARTDOCK_INIT_FINISHED, null); 314 return true; 315 } 316 } 317 } 318 } 319 320 if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) { 321 let appInfoTemp = { 322 "bundleName": dragItemInfo.bundleName, 323 "typeId": dragItemInfo.typeId, 324 "abilityName": dragItemInfo.abilityName, 325 "moduleName": dragItemInfo.moduleName, 326 "keyName": dragItemInfo.keyName, 327 "area": dragItemInfo.area, 328 "page": dragItemInfo.page, 329 "column": this.getColumn(endIndex), 330 "row": this.getRow(endIndex), 331 "badgeNumber": dragItemInfo.badgeNumber 332 }; 333 layoutInfo.push(appInfoTemp as LauncherDragItemInfo); 334 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo); 335 } else { 336 this.checkAndMove(this.mStartPosition, this.mEndPosition, layoutInfo, dragItemInfo); 337 } 338 339 info.layoutInfo = layoutInfo; 340 this.mSettingsModel.setLayoutInfo(info); 341 localEventManager.sendLocalEventSticky(EventConstants.EVENT_SMARTDOCK_INIT_FINISHED, null); 342 this.deleteBlankPageAfterDragging(startPosition, endPosition); 343 return true; 344 } 345 346 private updateEndPosition(dragItemInfo: LauncherDragItemInfo): void { 347 this.mGridConfig = this.mSettingsModel.getGridConfig(); 348 if (this.mEndPosition.row < 0) { 349 this.mEndPosition.row = 0; 350 } else if (this.mEndPosition.row + dragItemInfo.area[1] > this.mGridConfig.row) { 351 this.mEndPosition.row = this.mGridConfig.row - dragItemInfo.area[1]; 352 } 353 if (this.mEndPosition.column < 0) { 354 this.mEndPosition.column = 0; 355 } else if (this.mEndPosition.column + dragItemInfo.area[0] > this.mGridConfig.column ) { 356 this.mEndPosition.column = this.mGridConfig.column - dragItemInfo.area[0]; 357 } 358 } 359 360 deleteBlankPageOutsideEffect() { 361 // delete Blank Page because of drag outside effect area 362 Log.showInfo(TAG, 'deleteBlankPageOutsideEffect' ); 363 const startPosition: DragItemPosition = this.copyPosition(this.mStartPosition); 364 this.deleteBlankPageAfterDragging(startPosition, startPosition); 365 } 366 367 /** 368 * copy a new position object by original position 369 * 370 * @param position - original position 371 */ 372 private copyPosition(position: DragItemPosition): DragItemPosition { 373 if (CheckEmptyUtils.isEmpty(position)) { 374 return null; 375 } 376 const directionPosition: DragItemPosition = { 377 page: position.page, 378 row: position.row, 379 column: position.column, 380 X: position.X, 381 Y: position.Y 382 }; 383 return directionPosition; 384 } 385 386 /** 387 * delete blank page after dragging 388 * 389 * @param startPosition - drag start position 390 * @param endPosition - drag end position 391 */ 392 deleteBlankPageAfterDragging(startPosition: DragItemPosition, endPosition: DragItemPosition): void { 393 const layoutInfo = this.mSettingsModel.getLayoutInfo(); 394 const pageCount = layoutInfo.layoutDescription.pageCount; 395 const isAddByDraggingFlag = this.mPageDesktopModel.isAddByDragging(); 396 let deleteLastFlag = false; 397 if (isAddByDraggingFlag && (CheckEmptyUtils.isEmpty(endPosition) || 398 !CheckEmptyUtils.isEmpty(endPosition) && endPosition.page != pageCount - 1 )) { 399 layoutInfo.layoutDescription.pageCount = pageCount - 1; 400 deleteLastFlag = true; 401 } 402 let deleteStartFlag = false; 403 if (!CheckEmptyUtils.isEmpty(startPosition)) { 404 deleteStartFlag = this.mPageDesktopModel.deleteBlankPageFromLayoutInfo(layoutInfo, startPosition.page); 405 } 406 if (CheckEmptyUtils.isEmpty(endPosition) || JSON.stringify(startPosition) === JSON.stringify(endPosition)) { 407 Log.showDebug(TAG, `pageIndex: ${JSON.stringify(startPosition) === JSON.stringify(endPosition)}`); 408 AppStorage.setOrCreate('pageIndex', startPosition.page); 409 } else if (deleteStartFlag) { 410 if (startPosition.page > endPosition.page) { 411 AppStorage.setOrCreate('pageIndex', endPosition.page); 412 } else if (endPosition.page > startPosition.page && 413 endPosition.page < layoutInfo.layoutDescription.pageCount) { 414 AppStorage.setOrCreate('pageIndex', endPosition.page - 1); 415 } 416 } 417 this.mPageDesktopModel.setAddByDragging(false); 418 if (deleteLastFlag || deleteStartFlag) { 419 this.mSettingsModel.setLayoutInfo(layoutInfo); 420 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_REFRESH, null); 421 } 422 } 423 424 private isMoveToSamePosition(dragItemInfo: LauncherDragItemInfo): boolean { 425 if (this.mEndPosition.page == dragItemInfo.page && 426 this.mEndPosition.row == dragItemInfo.row && this.mEndPosition.column == dragItemInfo.column) { 427 return true; 428 } 429 return false; 430 } 431 432 private getEndLayoutInfo(layoutInfo) { 433 const endLayoutInfo = layoutInfo.find(item => { 434 if (item.typeId == CommonConstants.TYPE_FOLDER || item.typeId == CommonConstants.TYPE_CARD) { 435 return item.page === this.mEndPosition.page && this.isItemInRowColumn(this.mEndPosition.row, this.mEndPosition.column, item); 436 } else if (item.typeId == CommonConstants.TYPE_APP) { 437 return item.page === this.mEndPosition.page && item.row === this.mEndPosition.row && item.column === this.mEndPosition.column; 438 } 439 }); 440 return endLayoutInfo; 441 } 442 443 private getStartLayoutInfo(layoutInfo, dragItemInfo: LauncherDragItemInfo): LauncherDragItemInfo { 444 const startLayoutInfo = layoutInfo.find(item => { 445 return item.page === dragItemInfo.page && item.row === dragItemInfo.row && item.column === dragItemInfo.column; 446 }); 447 return startLayoutInfo; 448 } 449 450 /** 451 * folder squeeze handle 452 * @param source 453 * @param destination 454 * @param layoutInfo 455 * @param dragItemInfo 456 */ 457 private checkAndMove(source, destination, layoutInfo, dragItemInfo: LauncherDragItemInfo): boolean { 458 Log.showDebug(TAG, 'checkAndMove start'); 459 460 const allPositions = this.getAllPositions(destination, layoutInfo); 461 const objectPositionCount = this.getObjectPositionCount(destination, layoutInfo); 462 const pressedPositions = this.getPressedObjects(destination, allPositions, dragItemInfo); 463 464 // source and destination is in the same page 465 if (source.page == destination.page && !this.checkCanMoveInSamePage(pressedPositions, objectPositionCount, dragItemInfo)) { 466 return false; 467 } 468 // source and destination is in diff page 469 if (source.page != destination.page && !this.checkCanMoveInDiffPage(allPositions, dragItemInfo)) { 470 return false; 471 } 472 473 if (source.page == destination.page) { 474 this.setSourcePositionToNull(dragItemInfo, allPositions); 475 } 476 this.setDestinationPosition(destination, allPositions, dragItemInfo); 477 478 Log.showDebug(TAG, `checkAndMove pressedPositions.foldersAndForms: ${pressedPositions.foldersAndForms.length}`); 479 if (pressedPositions.foldersAndForms.length != 0) { 480 if (!this.moveFoldersAndForms(pressedPositions.foldersAndForms, destination, allPositions, dragItemInfo)) { 481 return false; 482 } 483 } 484 Log.showDebug(TAG, `checkAndMove pressedPositions.apps.length: ${pressedPositions.apps.length}`); 485 if (pressedPositions.apps.length != 0) { 486 this.moveApps(pressedPositions.apps, allPositions); 487 } 488 Log.showDebug(TAG, 'checkAndMove update destination '); 489 this.updateDestinationByDragItem(dragItemInfo, destination, allPositions); 490 Log.showDebug(TAG, 'checkAndMove update layoutInfo '); 491 for (let index = 0; index < layoutInfo.length; index++) { 492 for (let row = allPositions.length - 1; row >= 0 ; row--) { 493 for (let column = allPositions[row].length - 1; column >= 0 ; column--) { 494 if (layoutInfo[index].typeId == CommonConstants.TYPE_APP && layoutInfo[index].keyName == allPositions[row][column].keyName || 495 layoutInfo[index].typeId == CommonConstants.TYPE_FOLDER && layoutInfo[index].folderId == allPositions[row][column].keyName || 496 layoutInfo[index].typeId == CommonConstants.TYPE_CARD && layoutInfo[index].cardId == allPositions[row][column].keyName) { 497 layoutInfo[index].row = row; 498 layoutInfo[index].column = column; 499 layoutInfo[index].page = destination.page; 500 } 501 } 502 } 503 } 504 Log.showDebug(TAG, 'checkAndMove end'); 505 return true; 506 } 507 508 /** 509 * get desktop's position info 510 * @param destination 511 * @param layoutInfo 512 */ 513 private getAllPositions(destination, layoutInfo): any[] { 514 Log.showDebug(TAG, 'getAllPositions start'); 515 const allPositions = []; 516 this.setAllpositionsToNull(allPositions); 517 518 // set position in layoutInfo to all positions 519 for (let i = 0; i < layoutInfo.length; i++) { 520 if (layoutInfo[i].page == destination.page) { 521 if (layoutInfo[i].typeId == CommonConstants.TYPE_FOLDER || layoutInfo[i].typeId == CommonConstants.TYPE_CARD) { 522 let keyName = ''; 523 if (layoutInfo[i].typeId == CommonConstants.TYPE_FOLDER) { 524 keyName = layoutInfo[i].folderId; 525 } else if (layoutInfo[i].typeId == CommonConstants.TYPE_CARD) { 526 keyName = layoutInfo[i].cardId; 527 } 528 529 const positionInLayoutInfo = { 530 typeId: layoutInfo[i].typeId, 531 keyName: keyName, 532 area: layoutInfo[i].area 533 }; 534 for (let k = 0; k < layoutInfo[i].area[1]; k++) { 535 for (let j = 0; j < layoutInfo[i].area[0]; j++) { 536 allPositions[layoutInfo[i].row + k][layoutInfo[i].column + j] = positionInLayoutInfo; 537 } 538 } 539 } else if (layoutInfo[i].typeId == CommonConstants.TYPE_APP) { 540 const positionInLayoutInfo = { 541 typeId: layoutInfo[i].typeId, 542 keyName: layoutInfo[i].keyName, 543 area: layoutInfo[i].area 544 }; 545 allPositions[layoutInfo[i].row][layoutInfo[i].column] = positionInLayoutInfo; 546 } 547 } 548 } 549 return allPositions; 550 } 551 552 private setAllpositionsToNull(allPositions): void { 553 const mGridConfig = this.mSettingsModel.getGridConfig(); 554 const pageRow = mGridConfig.row; 555 const pageColumn = mGridConfig.column; 556 557 // set null to all positions in current page 558 for (let row = 0; row < pageRow; row++) { 559 const rowPositions = []; 560 for (let column = 0; column < pageColumn; column++) { 561 const position = { 562 typeId: -1, 563 keyName: 'null', 564 area: [] 565 }; 566 rowPositions.push(position); 567 } 568 allPositions.push(rowPositions); 569 } 570 } 571 572 /** 573 * get desktop's position count by Object 574 * @param destination 575 * @param layoutInfo 576 */ 577 private getObjectPositionCount(destination, layoutInfo): Map<string, number> { 578 Log.showDebug(TAG, 'getObjectPositionCount start'); 579 580 const objectPositionCount = new Map<string, number>(); 581 // set position in layoutInfo to all positions 582 for (let i = 0; i < layoutInfo.length; i++) { 583 if (layoutInfo[i].page == destination.page) { 584 const count = layoutInfo[i].area[0] * layoutInfo[i].area[1]; 585 let keyName = ''; 586 if (layoutInfo[i].typeId == CommonConstants.TYPE_FOLDER) { 587 keyName = layoutInfo[i].folderId; 588 } else if (layoutInfo[i].typeId == CommonConstants.TYPE_CARD) { 589 keyName = layoutInfo[i].cardId; 590 } else if (layoutInfo[i].typeId == CommonConstants.TYPE_APP) { 591 keyName = layoutInfo[i].keyName; 592 } 593 objectPositionCount.set(keyName, count); 594 } 595 } 596 return objectPositionCount; 597 } 598 599 /** 600 * get Object under pressed big folder or form 601 * @param destination 602 * @param allPositions 603 * @param dragItemInfo 604 */ 605 private getPressedObjects(destination, allPositions, dragItemInfo: LauncherDragItemInfo): { 606 apps: Array<LauncherDragItemInfo>, 607 foldersAndForms: Array<LauncherDragItemInfo> 608 } { 609 Log.showDebug(TAG, 'getPressedObjects start'); 610 const row = destination.row; 611 const column = destination.column; 612 const apps = []; 613 const foldersAndForms = []; 614 615 Log.showDebug(TAG, `getPressedObjects destination.row: ${row},destination.column:${column}`); 616 617 for (let j = 0; j < dragItemInfo.area[1]; j++) { 618 for (let i = 0; i < dragItemInfo.area[0]; i++) { 619 if (allPositions[row + j][column + i].typeId == CommonConstants.TYPE_APP) { 620 apps.push(allPositions[row + j][column + i]); 621 } else if (allPositions[row + j][column + i].typeId == CommonConstants.TYPE_FOLDER && 622 allPositions[row + j][column + i].keyName != dragItemInfo.folderId) { 623 foldersAndForms.push(allPositions[row + j][column + i]); 624 } else if (allPositions[row + j][column + i].typeId == CommonConstants.TYPE_CARD && 625 allPositions[row + j][column + i].keyName != dragItemInfo.cardId) { 626 foldersAndForms.push(allPositions[row + j][column + i]); 627 } 628 } 629 } 630 631 Log.showDebug(TAG, `getPressedObjects foldersAndForms.length: ${foldersAndForms.length}`); 632 Log.showDebug(TAG, `getPressedObjects apps.length: ${apps.length}`); 633 const pressedObjects = { 634 apps, 635 foldersAndForms 636 }; 637 return pressedObjects; 638 } 639 640 /** 641 * check of canMove in same page 642 * @param pressedPositions 643 * @param objectPositionCount 644 * @param dragItemInfo 645 */ 646 private checkCanMoveInSamePage(pressedPositions, objectPositionCount, dragItemInfo: LauncherDragItemInfo): boolean { 647 Log.showDebug(TAG, 'checkCanMoveInSamePage start'); 648 const foldersAndForms = pressedPositions.foldersAndForms; 649 if (foldersAndForms.length == 0) { 650 return true; 651 } 652 653 if (foldersAndForms.length == 1) { 654 if (dragItemInfo.typeId == CommonConstants.TYPE_APP && foldersAndForms[0].typeId == CommonConstants.TYPE_CARD) { 655 return true; 656 } 657 } 658 659 const coverPositionCount = new Map<string, number>(); 660 Log.showDebug(TAG, `checkCanMoveInSamePage foldersAndForms.length: ${foldersAndForms.length}`); 661 for (let i = 0; i < foldersAndForms.length; i++) { 662 const keyName = foldersAndForms[i].keyName; 663 if (coverPositionCount.has(keyName)) { 664 coverPositionCount.set(keyName, coverPositionCount.get(keyName) + 1); 665 } else { 666 coverPositionCount.set(keyName, 1); 667 } 668 } 669 670 for (const keyName of coverPositionCount.keys()) { 671 if (coverPositionCount.get(keyName) < objectPositionCount.get(keyName) / 2) { 672 Log.showDebug(TAG, 'checkCanMoveInSamePage end false'); 673 return false; 674 } 675 } 676 return true; 677 } 678 679 /** 680 * check of canMove in diff page 681 * @param allPositions 682 */ 683 private checkCanMoveInDiffPage(allPositions, dragItemInfo): boolean { 684 Log.showDebug(TAG, 'checkCanMoveInDiffPage start'); 685 let count = 0; 686 for (let i = 0; i < allPositions.length; i++) { 687 for (let j = 0; j < allPositions[i].length; j++) { 688 if (allPositions[i][j].typeId == -1) { 689 count++; 690 } 691 } 692 } 693 const minCount = dragItemInfo.area[0] * dragItemInfo.area[1]; 694 // target page empty position min is dragItemInfo's need position 695 if (count < minCount) { 696 Log.showDebug(TAG, 'checkCanMoveInDiffPage end false'); 697 return false; 698 } 699 return true; 700 } 701 702 /** 703 * set source‘s position to null 704 * @param source 705 * @param allPositions 706 */ 707 private setSourcePositionToNull(dragItemInfo, allPositions): void { 708 Log.showDebug(TAG, 'setSourcePositionToNull start'); 709 for (let j = 0; j < dragItemInfo.area[1]; j++) { 710 for (let i = 0; i < dragItemInfo.area[0]; i++) { 711 const nullPosition = { 712 typeId: -1, 713 keyName: 'null', 714 area: [] 715 }; 716 allPositions[dragItemInfo.row + j][dragItemInfo.column + i] = nullPosition; 717 } 718 } 719 } 720 721 /** 722 * set direction‘s position to null 723 * @param destination 724 * @param allPositions 725 * @param dragItemInfo 726 */ 727 private setDestinationPosition(destination, allPositions, dragItemInfo): void { 728 Log.showDebug(TAG, 'setDestinationPosition start'); 729 let keyName = ''; 730 if (dragItemInfo.typeId == CommonConstants.TYPE_FOLDER) { 731 keyName = dragItemInfo.folderId; 732 } else if (dragItemInfo.typeId == CommonConstants.TYPE_CARD) { 733 keyName = dragItemInfo.cardId; 734 } else if (dragItemInfo.typeId == CommonConstants.TYPE_APP) { 735 keyName = dragItemInfo.keyName; 736 } 737 738 for (let j = 0; j < dragItemInfo.area[1]; j++) { 739 for (let i = 0; i < dragItemInfo.area[0]; i++) { 740 if (allPositions[destination.row + j][destination.column+ i].typeId == -1) { 741 const destinationPosition = { 742 typeId: dragItemInfo.typeId, 743 keyName: keyName, 744 area: dragItemInfo.area 745 }; 746 allPositions[destination.row + j][destination.column+ i] = destinationPosition; 747 } 748 } 749 } 750 } 751 752 /** 753 * move folders and forms to target position 754 * @param foldersAndForms 755 * @param destination 756 * @param allPositions 757 * @param dragItemInfo 758 */ 759 private moveFoldersAndForms(foldersAndForms, destination, allPositions, dragItemInfo: LauncherDragItemInfo): boolean { 760 Log.showDebug(TAG, 'moveFoldersAndForms start'); 761 const movedFoldersAndForms = []; 762 for (let i = 0; i < foldersAndForms.length; i++) { 763 const moveFolderOrForm = foldersAndForms[i]; 764 if (movedFoldersAndForms.indexOf(moveFolderOrForm.keyName) != -1) { 765 continue; 766 } 767 768 for (let row = 0; row < allPositions.length; row++) { 769 for (let column = 0; column < allPositions[row].length; column++) { 770 if (moveFolderOrForm.keyName == allPositions[row][column].keyName) { 771 this.updateDestinationToNull(dragItemInfo, destination, allPositions, row, column); 772 } 773 } 774 } 775 776 let isUsablePosition = false; 777 for (let row = 0; row < allPositions.length; row++) { 778 if (isUsablePosition) { 779 break; 780 } 781 for (let column = 0; column < allPositions[row].length; column++) { 782 const usablePositionCount =this.getUsablePositionCount(moveFolderOrForm, allPositions, row , column); 783 if (usablePositionCount == moveFolderOrForm.area[1] * moveFolderOrForm.area[0]) { 784 isUsablePosition = true; 785 this.updatePositionByMoveItem(moveFolderOrForm, allPositions, row, column); 786 movedFoldersAndForms.push(moveFolderOrForm.keyName); 787 break; 788 } 789 } 790 } 791 if (!isUsablePosition) { 792 Log.showDebug(TAG, 'moveFoldersAndForms return false'); 793 return false; 794 } 795 } 796 this.updateDestinationByDragItem(dragItemInfo, destination, allPositions); 797 return true; 798 } 799 800 /** 801 * get the count of usable position 802 * @param moveFolderOrForm 803 * @param allPositions 804 * @param row 805 * @param column 806 */ 807 private getUsablePositionCount(moveFolderOrForm, allPositions, row , column): number { 808 let getUsablePositionCount = 0; 809 for (let j = 0; j < moveFolderOrForm.area[1]; j++) { 810 for (let i = 0; i < moveFolderOrForm.area[0]; i++) { 811 if (row + j < allPositions.length && column + i < allPositions[row].length && allPositions[row + j][column + i].typeId == -1) { 812 getUsablePositionCount++; 813 } 814 } 815 } 816 return getUsablePositionCount; 817 } 818 819 /** 820 * update destination to nullPosition 821 * 822 * @param dragItemInfo 823 * @param destination 824 * @param allPositions 825 * @param row 826 * @param column 827 */ 828 private updateDestinationToNull(dragItemInfo: LauncherDragItemInfo, destination, allPositions, row, column): void { 829 let destinationFlag = false; 830 for (let j = 0; j < dragItemInfo.area[1]; j++) { 831 if (destinationFlag) { 832 break; 833 } 834 for (let i = 0; i < dragItemInfo.area[0]; i++) { 835 if (destination.row + j == row && destination.column + i == column) { 836 destinationFlag = true; 837 break; 838 } 839 } 840 } 841 if (!destinationFlag) { 842 const nullPosition = { 843 typeId: -1, 844 keyName: 'null', 845 area: [] 846 }; 847 allPositions[row][column] = nullPosition; 848 } 849 } 850 851 /** 852 * update destination position by dragItemInfo 853 * 854 * @param dragItemInfo 855 * @param destination 856 * @param allPositions 857 */ 858 private updateDestinationByDragItem(dragItemInfo: LauncherDragItemInfo, destination, allPositions): void { 859 let keyName = ''; 860 if (dragItemInfo.typeId == CommonConstants.TYPE_FOLDER) { 861 keyName = dragItemInfo.folderId; 862 } else if (dragItemInfo.typeId == CommonConstants.TYPE_CARD) { 863 keyName = dragItemInfo.cardId >= 0 ? String(dragItemInfo.cardId) : ''; 864 } else if (dragItemInfo.typeId == CommonConstants.TYPE_APP) { 865 keyName = dragItemInfo.keyName; 866 } 867 868 for (let j = 0; j < dragItemInfo.area[1]; j++) { 869 for (let i = 0; i < dragItemInfo.area[0]; i++) { 870 const dragItemPosition = { 871 typeId: dragItemInfo.typeId, 872 keyName: keyName, 873 area: dragItemInfo.area 874 }; 875 allPositions[destination.row + j][destination.column + i] = dragItemPosition; 876 } 877 } 878 } 879 880 /** 881 * update positions by moveItemInfo 882 * 883 * @param moveFolderOrForm 884 * @param allPositions 885 * @param row 886 * @param column 887 */ 888 private updatePositionByMoveItem(moveFolderOrForm, allPositions, row, column): void { 889 for (let j = 0; j < moveFolderOrForm.area[1]; j++) { 890 for (let i = 0; i < moveFolderOrForm.area[0]; i++) { 891 const movePosition = { 892 typeId: moveFolderOrForm.typeId, 893 keyName: moveFolderOrForm.keyName, 894 area: moveFolderOrForm.area 895 }; 896 allPositions[row + j][column + i] = movePosition; 897 } 898 } 899 } 900 901 /** 902 * move apps to target position 903 * @param apps 904 * @param allPositions 905 */ 906 private moveApps(apps, allPositions): void { 907 Log.showDebug(TAG, 'moveApps start'); 908 for (let i = 0; i < apps.length; i++) { 909 const app = apps[i]; 910 let isUsable = false; 911 for (let row = 0; row < allPositions.length; row++) { 912 if (isUsable) { 913 break; 914 } 915 for (let column = 0; column < allPositions[row].length; column++) { 916 if (allPositions[row][column].typeId == -1) { 917 const appPosition = { 918 typeId: app.typeId, 919 keyName: app.keyName, 920 area: app.area 921 }; 922 allPositions[row][column] = appPosition; 923 isUsable = true; 924 break; 925 } 926 } 927 } 928 } 929 } 930} 931