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 private 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 protected 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 private 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 }) 296 this.mSettingsModel.setAppListInfo(appInfoList); 297 } 298 startLayoutInfo = dragItemInfo; 299 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo); 300 } else { 301 startLayoutInfo = this.getStartLayoutInfo(layoutInfo, dragItemInfo); 302 } 303 layoutInfoList.push(startLayoutInfo); 304 this.mBigFolderViewModel.addNewFolder(layoutInfoList).then(()=> { 305 this.deleteBlankPageAfterDragging(startPosition, endPosition); 306 }); 307 return true; 308 } else if (endLayoutInfo.typeId === CommonConstants.TYPE_CARD) { 309 if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) { 310 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_ADD, dragItemInfo); 311 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo); 312 localEventManager.sendLocalEventSticky(EventConstants.EVENT_SMARTDOCK_INIT_FINISHED, null); 313 return true; 314 } 315 } 316 } 317 } 318 319 if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) { 320 let appInfoTemp = { 321 "bundleName": dragItemInfo.bundleName, 322 "typeId": dragItemInfo.typeId, 323 "abilityName": dragItemInfo.abilityName, 324 "moduleName": dragItemInfo.moduleName, 325 "keyName": dragItemInfo.keyName, 326 "area": dragItemInfo.area, 327 "page": dragItemInfo.page, 328 "column": this.getColumn(endIndex), 329 "row": this.getRow(endIndex) 330 }; 331 layoutInfo.push(appInfoTemp); 332 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo); 333 } else { 334 this.checkAndMove(this.mStartPosition, this.mEndPosition, layoutInfo, dragItemInfo); 335 } 336 337 info.layoutInfo = layoutInfo; 338 this.mSettingsModel.setLayoutInfo(info); 339 localEventManager.sendLocalEventSticky(EventConstants.EVENT_SMARTDOCK_INIT_FINISHED, null); 340 this.deleteBlankPageAfterDragging(startPosition, endPosition); 341 return true; 342 } 343 344 private updateEndPosition(dragItemInfo: LauncherDragItemInfo): void { 345 this.mGridConfig = this.mSettingsModel.getGridConfig(); 346 if (this.mEndPosition.row < 0) { 347 this.mEndPosition.row = 0; 348 } else if (this.mEndPosition.row + dragItemInfo.area[1] > this.mGridConfig.row) { 349 this.mEndPosition.row = this.mGridConfig.row - dragItemInfo.area[1]; 350 } 351 if (this.mEndPosition.column < 0) { 352 this.mEndPosition.column = 0; 353 } else if (this.mEndPosition.column + dragItemInfo.area[0] > this.mGridConfig.column ) { 354 this.mEndPosition.column = this.mGridConfig.column - dragItemInfo.area[0]; 355 } 356 } 357 358 deleteBlankPageOutsideEffect() { 359 // delete Blank Page because of drag outside effect area 360 Log.showInfo(TAG, "deleteBlankPageOutsideEffect" ); 361 const startPosition: DragItemPosition = this.copyPosition(this.mStartPosition); 362 this.deleteBlankPageAfterDragging(startPosition, startPosition); 363 } 364 365 /** 366 * copy a new position object by original position 367 * 368 * @param position - original position 369 */ 370 private copyPosition(position: DragItemPosition): DragItemPosition { 371 if (CheckEmptyUtils.isEmpty(position)) { 372 return null; 373 } 374 const directionPosition: DragItemPosition = { 375 page: position.page, 376 row: position.row, 377 column: position.column, 378 X: position.X, 379 Y: position.Y 380 }; 381 return directionPosition; 382 } 383 384 /** 385 * delete blank page after dragging 386 * 387 * @param startPosition - drag start position 388 * @param endPosition - drag end position 389 */ 390 deleteBlankPageAfterDragging(startPosition: DragItemPosition, endPosition: DragItemPosition): void { 391 const layoutInfo = this.mSettingsModel.getLayoutInfo(); 392 const pageCount = layoutInfo.layoutDescription.pageCount; 393 const isAddByDraggingFlag = this.mPageDesktopModel.isAddByDragging(); 394 let deleteLastFlag = false; 395 if (isAddByDraggingFlag && (CheckEmptyUtils.isEmpty(endPosition) || 396 !CheckEmptyUtils.isEmpty(endPosition) && endPosition.page != pageCount - 1 )) { 397 layoutInfo.layoutDescription.pageCount = pageCount - 1; 398 deleteLastFlag = true; 399 } 400 let deleteStartFlag = false; 401 if (!CheckEmptyUtils.isEmpty(startPosition)) { 402 deleteStartFlag = this.mPageDesktopModel.deleteBlankPageFromLayoutInfo(layoutInfo, startPosition.page); 403 } 404 if (CheckEmptyUtils.isEmpty(endPosition) || JSON.stringify(startPosition) === JSON.stringify(endPosition)) { 405 Log.showDebug(TAG, `pageIndex: ${JSON.stringify(startPosition) === JSON.stringify(endPosition)}`); 406 AppStorage.setOrCreate('pageIndex', startPosition.page); 407 } else if (deleteStartFlag) { 408 if (startPosition.page > endPosition.page) { 409 AppStorage.setOrCreate('pageIndex', endPosition.page); 410 } else if (endPosition.page > startPosition.page && 411 endPosition.page < layoutInfo.layoutDescription.pageCount) { 412 AppStorage.setOrCreate('pageIndex', endPosition.page - 1); 413 } 414 } 415 this.mPageDesktopModel.setAddByDragging(false); 416 if (deleteLastFlag || deleteStartFlag) { 417 this.mSettingsModel.setLayoutInfo(layoutInfo); 418 localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_REFRESH, null); 419 } 420 } 421 422 private isMoveToSamePosition(dragItemInfo: LauncherDragItemInfo): boolean { 423 if (this.mEndPosition.page == dragItemInfo.page && 424 this.mEndPosition.row == dragItemInfo.row && this.mEndPosition.column == dragItemInfo.column) { 425 return true; 426 } 427 return false; 428 } 429 430 private getEndLayoutInfo(layoutInfo) { 431 const endLayoutInfo = layoutInfo.find(item => { 432 if (item.typeId == CommonConstants.TYPE_FOLDER || item.typeId == CommonConstants.TYPE_CARD) { 433 return item.page === this.mEndPosition.page && this.isItemInRowColumn(this.mEndPosition.row, this.mEndPosition.column, item); 434 } else if (item.typeId == CommonConstants.TYPE_APP) { 435 return item.page === this.mEndPosition.page && item.row === this.mEndPosition.row && item.column === this.mEndPosition.column; 436 } 437 }); 438 return endLayoutInfo; 439 } 440 441 private getStartLayoutInfo(layoutInfo, dragItemInfo: LauncherDragItemInfo): LauncherDragItemInfo { 442 const startLayoutInfo = layoutInfo.find(item => { 443 return item.page === dragItemInfo.page && item.row === dragItemInfo.row && item.column === dragItemInfo.column; 444 }); 445 return startLayoutInfo; 446 } 447 448 /** 449 * folder squeeze handle 450 * @param source 451 * @param destination 452 * @param layoutInfo 453 * @param dragItemInfo 454 */ 455 private checkAndMove(source, destination, layoutInfo, dragItemInfo: LauncherDragItemInfo): boolean { 456 Log.showDebug(TAG, 'checkAndMove start'); 457 458 const allPositions = this.getAllPositions(destination, layoutInfo); 459 const objectPositionCount = this.getObjectPositionCount(destination, layoutInfo); 460 const pressedPositions = this.getPressedObjects(destination, allPositions, dragItemInfo); 461 462 // source and destination is in the same page 463 if (source.page == destination.page && !this.checkCanMoveInSamePage(pressedPositions, objectPositionCount, dragItemInfo)) { 464 return false; 465 } 466 // source and destination is in diff page 467 if (source.page != destination.page && !this.checkCanMoveInDiffPage(allPositions, dragItemInfo)) { 468 return false; 469 } 470 471 if (source.page == destination.page) { 472 this.setSourcePositionToNull(dragItemInfo, allPositions); 473 } 474 this.setDestinationPosition(destination, allPositions, dragItemInfo); 475 476 Log.showDebug(TAG, `checkAndMove pressedPositions.foldersAndForms: ${pressedPositions.foldersAndForms.length}`); 477 if (pressedPositions.foldersAndForms.length != 0) { 478 if (!this.moveFoldersAndForms(pressedPositions.foldersAndForms, destination, allPositions, dragItemInfo)) { 479 return false; 480 } 481 } 482 Log.showDebug(TAG, `checkAndMove pressedPositions.apps.length: ${pressedPositions.apps.length}`); 483 if (pressedPositions.apps.length != 0) { 484 this.moveApps(pressedPositions.apps, allPositions); 485 } 486 Log.showDebug(TAG, 'checkAndMove update destination '); 487 this.updateDestinationByDragItem(dragItemInfo, destination, allPositions); 488 Log.showDebug(TAG, 'checkAndMove update layoutInfo '); 489 for (let index = 0; index < layoutInfo.length; index++) { 490 for (let row = allPositions.length - 1; row >= 0 ; row--) { 491 for (let column = allPositions[row].length - 1; column >= 0 ; column--) { 492 if (layoutInfo[index].typeId == CommonConstants.TYPE_APP && layoutInfo[index].keyName == allPositions[row][column].keyName || 493 layoutInfo[index].typeId == CommonConstants.TYPE_FOLDER && layoutInfo[index].folderId == allPositions[row][column].keyName || 494 layoutInfo[index].typeId == CommonConstants.TYPE_CARD && layoutInfo[index].cardId == allPositions[row][column].keyName) { 495 layoutInfo[index].row = row; 496 layoutInfo[index].column = column; 497 layoutInfo[index].page = destination.page; 498 } 499 } 500 } 501 } 502 Log.showDebug(TAG, 'checkAndMove end'); 503 return true; 504 } 505 506 /** 507 * get desktop's position info 508 * @param destination 509 * @param layoutInfo 510 */ 511 private getAllPositions(destination, layoutInfo): any[] { 512 Log.showDebug(TAG, 'getAllPositions start'); 513 const allPositions = []; 514 this.setAllpositionsToNull(allPositions); 515 516 // set position in layoutInfo to all positions 517 for (let i = 0; i < layoutInfo.length; i++) { 518 if (layoutInfo[i].page == destination.page) { 519 if (layoutInfo[i].typeId == CommonConstants.TYPE_FOLDER || layoutInfo[i].typeId == CommonConstants.TYPE_CARD) { 520 let keyName = ''; 521 if (layoutInfo[i].typeId == CommonConstants.TYPE_FOLDER) { 522 keyName = layoutInfo[i].folderId; 523 } else if (layoutInfo[i].typeId == CommonConstants.TYPE_CARD) { 524 keyName = layoutInfo[i].cardId; 525 } 526 527 const positionInLayoutInfo = { 528 typeId: layoutInfo[i].typeId, 529 keyName: keyName, 530 area: layoutInfo[i].area 531 }; 532 for (let k = 0; k < layoutInfo[i].area[1]; k++) { 533 for (let j = 0; j < layoutInfo[i].area[0]; j++) { 534 allPositions[layoutInfo[i].row + k][layoutInfo[i].column + j] = positionInLayoutInfo; 535 } 536 } 537 } else if (layoutInfo[i].typeId == CommonConstants.TYPE_APP) { 538 const positionInLayoutInfo = { 539 typeId: layoutInfo[i].typeId, 540 keyName: layoutInfo[i].keyName, 541 area: layoutInfo[i].area 542 }; 543 allPositions[layoutInfo[i].row][layoutInfo[i].column] = positionInLayoutInfo; 544 } 545 } 546 } 547 return allPositions; 548 } 549 550 private setAllpositionsToNull(allPositions): void { 551 const mGridConfig = this.mSettingsModel.getGridConfig(); 552 const pageRow = mGridConfig.row; 553 const pageColumn = mGridConfig.column; 554 555 // set null to all positions in current page 556 for (let row = 0; row < pageRow; row++) { 557 const rowPositions = []; 558 for (let column = 0; column < pageColumn; column++) { 559 const position = { 560 typeId: -1, 561 keyName: 'null', 562 area: [] 563 }; 564 rowPositions.push(position); 565 } 566 allPositions.push(rowPositions); 567 } 568 } 569 570 /** 571 * get desktop's position count by Object 572 * @param destination 573 * @param layoutInfo 574 */ 575 private getObjectPositionCount(destination, layoutInfo): Map<string, number> { 576 Log.showDebug(TAG, 'getObjectPositionCount start'); 577 578 const objectPositionCount = new Map<string, number>(); 579 // set position in layoutInfo to all positions 580 for (let i = 0; i < layoutInfo.length; i++) { 581 if (layoutInfo[i].page == destination.page) { 582 const count = layoutInfo[i].area[0] * layoutInfo[i].area[1]; 583 let keyName = ''; 584 if (layoutInfo[i].typeId == CommonConstants.TYPE_FOLDER) { 585 keyName = layoutInfo[i].folderId; 586 } else if (layoutInfo[i].typeId == CommonConstants.TYPE_CARD) { 587 keyName = layoutInfo[i].cardId; 588 } else if (layoutInfo[i].typeId == CommonConstants.TYPE_APP) { 589 keyName = layoutInfo[i].keyName; 590 } 591 objectPositionCount.set(keyName, count); 592 } 593 } 594 return objectPositionCount; 595 } 596 597 /** 598 * get Object under pressed big folder or form 599 * @param destination 600 * @param allPositions 601 * @param dragItemInfo 602 */ 603 private getPressedObjects(destination, allPositions, dragItemInfo: LauncherDragItemInfo): { 604 apps: Array<LauncherDragItemInfo>, 605 foldersAndForms: Array<LauncherDragItemInfo> 606 } { 607 Log.showDebug(TAG, 'getPressedObjects start'); 608 const row = destination.row; 609 const column = destination.column; 610 const apps = []; 611 const foldersAndForms = []; 612 613 Log.showDebug(TAG, `getPressedObjects destination.row: ${row},destination.column:${column}`); 614 615 for (let j = 0; j < dragItemInfo.area[1]; j++) { 616 for (let i = 0; i < dragItemInfo.area[0]; i++) { 617 if (allPositions[row + j][column + i].typeId == CommonConstants.TYPE_APP) { 618 apps.push(allPositions[row + j][column + i]); 619 } else if (allPositions[row + j][column + i].typeId == CommonConstants.TYPE_FOLDER && 620 allPositions[row + j][column + i].keyName != dragItemInfo.folderId) { 621 foldersAndForms.push(allPositions[row + j][column + i]); 622 } else if (allPositions[row + j][column + i].typeId == CommonConstants.TYPE_CARD && 623 allPositions[row + j][column + i].keyName != dragItemInfo.cardId) { 624 foldersAndForms.push(allPositions[row + j][column + i]); 625 } 626 } 627 } 628 629 Log.showDebug(TAG, `getPressedObjects foldersAndForms.length: ${foldersAndForms.length}`); 630 Log.showDebug(TAG, `getPressedObjects apps.length: ${apps.length}`); 631 const pressedObjects = { 632 apps, 633 foldersAndForms 634 }; 635 return pressedObjects; 636 } 637 638 /** 639 * check of canMove in same page 640 * @param pressedPositions 641 * @param objectPositionCount 642 * @param dragItemInfo 643 */ 644 private checkCanMoveInSamePage(pressedPositions, objectPositionCount, dragItemInfo: LauncherDragItemInfo): boolean { 645 Log.showDebug(TAG, 'checkCanMoveInSamePage start'); 646 const foldersAndForms = pressedPositions.foldersAndForms; 647 if (foldersAndForms.length == 0) { 648 return true; 649 } 650 651 if (foldersAndForms.length == 1) { 652 if (dragItemInfo.typeId == CommonConstants.TYPE_APP && foldersAndForms[0].typeId == CommonConstants.TYPE_CARD) { 653 return true; 654 } 655 } 656 657 const coverPositionCount = new Map<string, number>(); 658 Log.showDebug(TAG, `checkCanMoveInSamePage foldersAndForms.length: ${foldersAndForms.length}`); 659 for (let i = 0; i < foldersAndForms.length; i++) { 660 const keyName = foldersAndForms[i].keyName; 661 if (coverPositionCount.has(keyName)) { 662 coverPositionCount.set(keyName, coverPositionCount.get(keyName) + 1); 663 } else { 664 coverPositionCount.set(keyName, 1); 665 } 666 } 667 668 for (const keyName of coverPositionCount.keys()) { 669 if (coverPositionCount.get(keyName) < objectPositionCount.get(keyName) / 2) { 670 Log.showDebug(TAG, 'checkCanMoveInSamePage end false'); 671 return false; 672 } 673 } 674 return true; 675 } 676 677 /** 678 * check of canMove in diff page 679 * @param allPositions 680 */ 681 private checkCanMoveInDiffPage(allPositions, dragItemInfo): boolean { 682 Log.showDebug(TAG, 'checkCanMoveInDiffPage start'); 683 let count = 0; 684 for (let i = 0; i < allPositions.length; i++) { 685 for (let j = 0; j < allPositions[i].length; j++) { 686 if (allPositions[i][j].typeId == -1) { 687 count++; 688 } 689 } 690 } 691 const minCount = dragItemInfo.area[0] * dragItemInfo.area[1]; 692 // target page empty position min is dragItemInfo's need position 693 if (count < minCount) { 694 Log.showDebug(TAG, 'checkCanMoveInDiffPage end false'); 695 return false; 696 } 697 return true; 698 } 699 700 /** 701 * set source‘s position to null 702 * @param source 703 * @param allPositions 704 */ 705 private setSourcePositionToNull(dragItemInfo, allPositions): void { 706 Log.showDebug(TAG, 'setSourcePositionToNull start'); 707 for (let j = 0; j < dragItemInfo.area[1]; j++) { 708 for (let i = 0; i < dragItemInfo.area[0]; i++) { 709 const nullPosition = { 710 typeId: -1, 711 keyName: 'null', 712 area: [] 713 }; 714 allPositions[dragItemInfo.row + j][dragItemInfo.column + i] = nullPosition; 715 } 716 } 717 } 718 719 /** 720 * set direction‘s position to null 721 * @param destination 722 * @param allPositions 723 * @param dragItemInfo 724 */ 725 private setDestinationPosition(destination, allPositions, dragItemInfo): void { 726 Log.showDebug(TAG, 'setDestinationPosition start'); 727 let keyName = ''; 728 if (dragItemInfo.typeId == CommonConstants.TYPE_FOLDER) { 729 keyName = dragItemInfo.folderId; 730 } else if (dragItemInfo.typeId == CommonConstants.TYPE_CARD) { 731 keyName = dragItemInfo.cardId; 732 } else if (dragItemInfo.typeId == CommonConstants.TYPE_APP) { 733 keyName = dragItemInfo.keyName; 734 } 735 736 for (let j = 0; j < dragItemInfo.area[1]; j++) { 737 for (let i = 0; i < dragItemInfo.area[0]; i++) { 738 if (allPositions[destination.row + j][destination.column+ i].typeId == -1) { 739 const destinationPosition = { 740 typeId: dragItemInfo.typeId, 741 keyName: keyName, 742 area: dragItemInfo.area 743 }; 744 allPositions[destination.row + j][destination.column+ i] = destinationPosition; 745 } 746 } 747 } 748 } 749 750 /** 751 * move folders and forms to target position 752 * @param foldersAndForms 753 * @param destination 754 * @param allPositions 755 * @param dragItemInfo 756 */ 757 private moveFoldersAndForms(foldersAndForms, destination, allPositions, dragItemInfo: LauncherDragItemInfo): boolean { 758 Log.showDebug(TAG, 'moveFoldersAndForms start'); 759 const movedFoldersAndForms = []; 760 for (let i = 0; i < foldersAndForms.length; i++) { 761 const moveFolderOrForm = foldersAndForms[i]; 762 if (movedFoldersAndForms.indexOf(moveFolderOrForm.keyName) != -1) { 763 continue; 764 } 765 766 for (let row = 0; row < allPositions.length; row++) { 767 for (let column = 0; column < allPositions[row].length; column++) { 768 if (moveFolderOrForm.keyName == allPositions[row][column].keyName) { 769 this.updateDestinationToNull(dragItemInfo, destination, allPositions, row, column); 770 } 771 } 772 } 773 774 let isUsablePosition = false; 775 for (let row = 0; row < allPositions.length; row++) { 776 if (isUsablePosition) { 777 break; 778 } 779 for (let column = 0; column < allPositions[row].length; column++) { 780 const usablePositionCount =this.getUsablePositionCount(moveFolderOrForm, allPositions, row , column); 781 if (usablePositionCount == moveFolderOrForm.area[1] * moveFolderOrForm.area[0]) { 782 isUsablePosition = true; 783 this.updatePositionByMoveItem(moveFolderOrForm, allPositions, row, column); 784 movedFoldersAndForms.push(moveFolderOrForm.keyName); 785 break; 786 } 787 } 788 } 789 if (!isUsablePosition) { 790 Log.showDebug(TAG, 'moveFoldersAndForms return false'); 791 return false; 792 } 793 } 794 this.updateDestinationByDragItem(dragItemInfo, destination, allPositions); 795 return true; 796 } 797 798 /** 799 * get the count of usable position 800 * @param moveFolderOrForm 801 * @param allPositions 802 * @param row 803 * @param column 804 */ 805 private getUsablePositionCount(moveFolderOrForm, allPositions, row , column): number { 806 let getUsablePositionCount = 0; 807 for (let j = 0; j < moveFolderOrForm.area[1]; j++) { 808 for (let i = 0; i < moveFolderOrForm.area[0]; i++) { 809 if (row + j < allPositions.length && column + i < allPositions[row].length && allPositions[row + j][column + i].typeId == -1) { 810 getUsablePositionCount++; 811 } 812 } 813 } 814 return getUsablePositionCount; 815 } 816 817 /** 818 * update destination to nullPosition 819 * 820 * @param dragItemInfo 821 * @param destination 822 * @param allPositions 823 * @param row 824 * @param column 825 */ 826 private updateDestinationToNull(dragItemInfo: LauncherDragItemInfo, destination, allPositions, row, column): void { 827 let destinationFlag = false; 828 for (let j = 0; j < dragItemInfo.area[1]; j++) { 829 if (destinationFlag) { 830 break; 831 } 832 for (let i = 0; i < dragItemInfo.area[0]; i++) { 833 if (destination.row + j == row && destination.column + i == column) { 834 destinationFlag = true; 835 break; 836 } 837 } 838 } 839 if (!destinationFlag) { 840 const nullPosition = { 841 typeId: -1, 842 keyName: 'null', 843 area: [] 844 }; 845 allPositions[row][column] = nullPosition; 846 } 847 } 848 849 /** 850 * update destination position by dragItemInfo 851 * 852 * @param dragItemInfo 853 * @param destination 854 * @param allPositions 855 */ 856 private updateDestinationByDragItem(dragItemInfo: LauncherDragItemInfo, destination, allPositions): void { 857 let keyName = ''; 858 if (dragItemInfo.typeId == CommonConstants.TYPE_FOLDER) { 859 keyName = dragItemInfo.folderId; 860 } else if (dragItemInfo.typeId == CommonConstants.TYPE_CARD) { 861 keyName = dragItemInfo.cardId >= 0 ? String(dragItemInfo.cardId) : ''; 862 } else if (dragItemInfo.typeId == CommonConstants.TYPE_APP) { 863 keyName = dragItemInfo.keyName; 864 } 865 866 for (let j = 0; j < dragItemInfo.area[1]; j++) { 867 for (let i = 0; i < dragItemInfo.area[0]; i++) { 868 const dragItemPosition = { 869 typeId: dragItemInfo.typeId, 870 keyName: keyName, 871 area: dragItemInfo.area 872 }; 873 allPositions[destination.row + j][destination.column + i] = dragItemPosition; 874 } 875 } 876 } 877 878 /** 879 * update positions by moveItemInfo 880 * 881 * @param moveFolderOrForm 882 * @param allPositions 883 * @param row 884 * @param column 885 */ 886 private updatePositionByMoveItem(moveFolderOrForm, allPositions, row, column): void { 887 for (let j = 0; j < moveFolderOrForm.area[1]; j++) { 888 for (let i = 0; i < moveFolderOrForm.area[0]; i++) { 889 const movePosition = { 890 typeId: moveFolderOrForm.typeId, 891 keyName: moveFolderOrForm.keyName, 892 area: moveFolderOrForm.area 893 }; 894 allPositions[row + j][column + i] = movePosition; 895 } 896 } 897 } 898 899 /** 900 * move apps to target position 901 * @param apps 902 * @param allPositions 903 */ 904 private moveApps(apps, allPositions): void { 905 Log.showDebug(TAG, 'moveApps start'); 906 for (let i = 0; i < apps.length; i++) { 907 const app = apps[i]; 908 let isUsable = false; 909 for (let row = 0; row < allPositions.length; row++) { 910 if (isUsable) { 911 break; 912 } 913 for (let column = 0; column < allPositions[row].length; column++) { 914 if (allPositions[row][column].typeId == -1) { 915 const appPosition = { 916 typeId: app.typeId, 917 keyName: app.keyName, 918 area: app.area 919 }; 920 allPositions[row][column] = appPosition; 921 isUsable = true; 922 break; 923 } 924 } 925 } 926 } 927 } 928} 929