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 { EventConstants } from '../constants/EventConstants';
17import { localEventManager } from '../manager/LocalEventManager';
18import { Log } from '../utils/Log';
19
20const TAG = 'PageDesktopModel';
21
22/**
23 * PageDesktop Model
24 */
25
26export class PageDesktopModel {
27  private isAddByDraggingFlag = false;
28
29  private constructor() {
30  }
31
32  /**
33  * Obtains the pageDesktop data model object.
34  *
35  * @return PageDesktopModel
36   */
37  static getInstance(): PageDesktopModel {
38    if (globalThis.PageDesktopModel == null) {
39      globalThis.PageDesktopModel = new PageDesktopModel();
40    }
41    return globalThis.PageDesktopModel;
42  }
43
44  /**
45  * Register for the PageDesktop application list add event.
46  *
47  * @param listener
48   */
49  registerPageDesktopItemAddEvent(listener): void {
50    localEventManager.registerEventListener(listener, [
51      EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_ADD,
52      EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_DELETE,
53      EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_UPDATE,
54      EventConstants.EVENT_REQUEST_PAGEDESK_FORM_ITEM_ADD,
55      EventConstants.EVENT_SMARTDOCK_INIT_FINISHED,
56      EventConstants.EVENT_REQUEST_PAGEDESK_REFRESH,
57      EventConstants.EVENT_REQUEST_FORM_ITEM_VISIBLE
58    ]);
59  }
60
61  /**
62  * register badge update event.
63  *
64  * @param listener
65   */
66  registerPageDesktopBadgeUpdateEvent(listener): void {
67    localEventManager.registerEventListener(listener, [
68      EventConstants.EVENT_BADGE_UPDATE
69    ]);
70  }
71
72  /**
73  * Unregister application list change listener.
74  *
75  * @param listener
76   */
77  unregisterEventListener(listener): void {
78    localEventManager.unregisterEventListener(listener);
79  }
80
81  sendDockItemChangeEvent(appInfo): void {
82    localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_DOCK_ITEM_ADD, appInfo);
83  }
84
85  /**
86   * delete blank page from layoutInfo
87   *
88   * @param layoutInfo
89   * @param page
90   */
91  deleteBlankPageFromLayoutInfo(layoutInfo, page): boolean {
92    for (let i = 0; i < layoutInfo.layoutInfo.length; i++) {
93      if (layoutInfo.layoutInfo[i].page == page) {
94        return false;
95      }
96    }
97    if (layoutInfo.layoutDescription.pageCount <= 1) {
98      return false;
99    }
100    layoutInfo.layoutDescription.pageCount--;
101    for (let m = 0; m < layoutInfo.layoutInfo.length; m++) {
102      if (layoutInfo.layoutInfo[m].page > page) {
103        layoutInfo.layoutInfo[m].page--;
104      }
105    }
106    return true;
107  }
108
109  /**
110   * get the addByDragging flag
111   */
112  isAddByDragging(): boolean {
113    return this.isAddByDraggingFlag;
114  }
115
116  /**
117   * set the addByDragging flag
118   * @param {boolean} isAddByDragging
119   */
120  setAddByDragging(isAddByDragging: boolean): void {
121    this.isAddByDraggingFlag = isAddByDragging;
122  }
123
124  updateAppItemLayoutInfo(info, item): void {
125    const pageCount = info.layoutDescription.pageCount;
126    const row = info.layoutDescription.row;
127    const column = info.layoutDescription.column;
128    const layoutInfo = info.layoutInfo;
129    // current page has space
130    let isNeedNewPage = true;
131    pageCycle: for (let i = 0; i < pageCount; i++) {
132      for (let y = 0; y < row; y++) {
133        for (let x = 0; x < column; x++) {
134          if (this.isPositionValid(info, item, i, x, y)) {
135            Log.showDebug(TAG, `updateAppItemLayoutInfo isPositionValid: x:${x} y:${y} page:${i}`);
136            isNeedNewPage = false;
137            layoutInfo.push({
138              bundleName: item.bundleName,
139              typeId: item.typeId,
140              abilityName: item.abilityName,
141              moduleName: item.moduleName,
142              keyName: item.keyName,
143              badgeNumber:item.badgeNumber,
144              area: item.area,
145              page: i,
146              column: x,
147              row: y
148            });
149            break pageCycle;
150          }
151        }
152      }
153    }
154    if (isNeedNewPage) {
155      layoutInfo.push({
156        bundleName: item.bundleName,
157        typeId: item.typeId,
158        abilityName: item.abilityName,
159        moduleName: item.moduleName,
160        keyName: item.keyName,
161        badgeNumber:item.badgeNumber,
162        area: item.area,
163        page: pageCount,
164        column: 0,
165        row: 0
166      });
167      ++info.layoutDescription.pageCount;
168    }
169  }
170
171  updatePageDesktopLayoutInfo(info, item): boolean {
172    const pageCount = info.layoutDescription.pageCount;
173    const row = info.layoutDescription.row;
174    const column = info.layoutDescription.column;
175    // current page has space
176    let isNeedNewPage = true;
177    const curPageIndex = this.getPageIndex();
178    const max = pageCount - 1 > curPageIndex ? curPageIndex + 1 : pageCount - 1;
179    pageCycle: for (let i = curPageIndex; i <= max; i++) {
180      for (let y = 0; y < row; y++) {
181        for (let x = 0; x < column; x++) {
182          if (this.isPositionValid(info, item, i, x, y)) {
183            Log.showDebug(TAG, `updatePageDesktopLayoutInfo isPositionValid: x:${x} y:${y} page:${i}`);
184            isNeedNewPage = false;
185            item.page = i;
186            item.column = x;
187            item.row = y;
188            break pageCycle;
189          }
190        }
191      }
192    }
193    if (isNeedNewPage) {
194      item.page = curPageIndex + 1;
195      item.column = 0;
196      item.row = 0;
197    }
198    return isNeedNewPage;
199  }
200
201  private isPositionValid(info, item, page, startColumn, startRow): boolean {
202    const row = info.layoutDescription.row;
203    const column = info.layoutDescription.column;
204    if ((startColumn + item.area[0]) > column || (startRow + item.area[1]) > row) {
205      return false;
206    }
207    let isValid = true;
208    for (let x = startColumn; x < startColumn + item.area[0]; x++) {
209      for (let y = startRow; y < startRow + item.area[1]; y++) {
210        if (this.isPositionOccupied(info, page, x, y)) {
211          isValid = false;
212          break;
213        }
214      }
215    }
216    return isValid;
217  }
218
219  private isPositionOccupied(info, page, column, row): boolean {
220    const pageCount = info.layoutDescription.pageCount;
221    const layoutInfo = info.layoutInfo;
222    // current page has space
223    for (const layout of layoutInfo) {
224      if (layout.page == page) {
225        const xMatch = (column >= layout.column) && (column < layout.column + layout.area[0]);
226        const yMatch = (row >= layout.row) && (row < layout.row + layout.area[1]);
227        if (xMatch && yMatch) {
228          return true;
229        }
230      }
231    }
232    return false;
233  }
234
235  /**
236   * Changing the Desktop Page Number.
237   *
238   * @param idx: Page number
239   */
240  setPageIndex(idx: number): void {
241    Log.showInfo(TAG, 'setPageIndex: ' + idx);
242    AppStorage.setOrCreate('pageIndex', idx);
243  }
244
245  /**
246   * Get the Desktop Page Number.
247   */
248  getPageIndex(): number {
249    return AppStorage.get('pageIndex');
250  }
251}