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