• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 '../utils/Log';
17import { SettingsModel } from '../model/SettingsModel';
18import { StyleConstants } from '../constants/StyleConstants';
19import { CommonConstants } from '../constants/CommonConstants';
20import { ResourceManager } from '../manager/ResourceManager';
21import { PresetStyleConstants } from '../constants/PresetStyleConstants';
22import { AppIcon } from './AppIcon';
23import { AppName } from './AppName';
24import { AppMenu } from './AppMenu';
25import { LauncherDragItemInfo } from '../bean/LauncherDragItemInfo';
26
27const TAG = 'FolderComponent';
28
29@Component
30export struct FolderComponent {
31  @StorageLink('openFolderStatus') @Watch('updateFolderAnimate') openFolderStatus: number = 1;
32  @State folderAnimateData: {
33    folderId: string,
34    isOpenFolder: boolean,
35  } = { folderId: '', isOpenFolder: false };
36  @State folderPositionX: number = 0;
37  @State folderPositionY: number = 0;
38  @State folderItemPositionX: number = 0;
39  @State folderItemPositionY: number = 0;
40  @State animateFolderPositionX: number = 0;
41  @State animateFolderPositionY: number = 0;
42  @State animateOpacity: number = 1.0;
43  @State animateScale: number = 1.0;
44  @State showFolderName: boolean = true;
45  @State folderNameHeight: number = 0;
46  @State folderNameSize: number = 0;
47  @State nameFontColor: string = '';
48  @State appIconSize: number = 0;
49  @State superposeIconVisible: boolean = false;
50  @State isHover: boolean = false;
51  mPaddingTop: number = StyleConstants.DEFAULT_10;
52  folderGridSize: number = StyleConstants.DEFAULT_FOLDER_GRID_SIZE;
53  gridMargin: number = StyleConstants.DEFAULT_FOLDER_GRID_MARGIN;
54  gridGap: number = StyleConstants.DEFAULT_FOLDER_GRID_GAP;
55  badgeNumber: number = 0;
56  private mSettingsModel: SettingsModel;
57  private isPad: boolean = false;
58  private mFolderItem: any;
59  private mShowAppList: any = [];
60  private mSuperposeAppList: any = [];
61  onAppIconClick?: Function = null;
62  onOpenFolderClick?: Function = null;
63  onFolderTouch?: Function = null;
64  onGetPosition?: Function = null;
65  buildMenu: Function = null;
66  folderNameLines: number = PresetStyleConstants.DEFAULT_APP_NAME_LINES;
67  iconNameMargin: number = PresetStyleConstants.DEFAULT_ICON_NAME_GAP;
68  isSelect?: boolean;
69  dragStart: Function;
70
71  aboutToAppear(): void  {
72    Log.showInfo(TAG, `aboutToAppear start`);
73    this.updateShowList();
74    this.mSettingsModel = SettingsModel.getInstance();
75    if (this.mSettingsModel.getDevice() != "phone") {
76      this.isPad = true;
77    }
78  }
79
80  aboutToDisappear(): void {
81    this.onAppIconClick = null;
82    this.onOpenFolderClick = null;
83    this.onFolderTouch = null;
84    this.onGetPosition = null;
85    this.buildMenu = null;
86    this.dragStart = null;
87  }
88
89  updateShowList(): void {
90    if (this.mFolderItem.layoutInfo[0].length > CommonConstants.FOLDER_STATIC_SHOW_LENGTH) {
91      this.mShowAppList = this.mFolderItem.layoutInfo[0].slice(0, CommonConstants.FOLDER_STATIC_SHOW_LENGTH);
92    } else {
93      this.mShowAppList = this.mFolderItem.layoutInfo[0];
94    }
95
96    let showLength = CommonConstants.FOLDER_STATIC_SHOW_LENGTH - CommonConstants.FOLDER_STATIC_SUPERPOSEAPP_LENGTH;
97    if (this.mShowAppList.length > showLength) {
98      this.mSuperposeAppList = this.mShowAppList.slice(showLength);
99      this.mShowAppList = this.mShowAppList.slice(0, showLength);
100      this.superposeIconVisible = true;
101    }
102
103    let length = this.mSuperposeAppList.length;
104    if (length > CommonConstants.FOLDER_STATIC_SUPERPOSEAPP_LENGTH) {
105      this.mSuperposeAppList = this.mSuperposeAppList.slice(0, CommonConstants.FOLDER_STATIC_SUPERPOSEAPP_LENGTH);
106    } else {
107      for (let i = 0; i < (CommonConstants.FOLDER_STATIC_SUPERPOSEAPP_LENGTH - length); i++) {
108        this.mSuperposeAppList.push({ 'isEmpty': true });
109      }
110    }
111    this.mSuperposeAppList = this.mSuperposeAppList.reverse();
112    this.mSuperposeAppList[0].alignContent = Alignment.TopStart;
113    this.mSuperposeAppList[1].alignContent = Alignment.Center;
114    this.mSuperposeAppList[2].alignContent = Alignment.BottomEnd;
115
116    Log.showInfo(TAG, `superposeIconVisible:${this.superposeIconVisible}`);
117    Log.showInfo(TAG, `FolderItem.layoutInfo[0].length:${this.mFolderItem.layoutInfo[0].length}`);
118    Log.showInfo(TAG, `SuperposeAppList length:${this.mSuperposeAppList.length}`);
119  }
120
121  @Builder MenuBuilder() {
122    Column() {
123      AppMenu({
124        menuInfoList: this.buildMenu(this.mFolderItem),
125      })
126    }
127    .alignItems(HorizontalAlign.Center)
128    .justifyContent(FlexAlign.Center)
129    .width(StyleConstants.CONTEXT_MENU_WIDTH)
130  }
131
132  private updateFolderAnimate() {
133    Log.showInfo(TAG, `updateFolderAnimate start`);
134    if (this.openFolderStatus == 0) {
135      this.folderAnimateData = AppStorage.get('folderAnimateData');
136      if (this.mFolderItem.folderId === this.folderAnimateData.folderId &&
137      this.folderAnimateData.isOpenFolder &&
138      this.folderAnimateData.folderId != '' &&
139      this.animateOpacity != 1.0 &&
140      this.animateScale != 1.0) {
141        this.folderAnimateData.isOpenFolder = false;
142        AppStorage.setOrCreate('folderAnimateData', this.folderAnimateData);
143        Log.showInfo(TAG, `updateFolderAnimate show`);
144        this.showAnimate(1.0, 1.0, false);
145      }
146    }
147  }
148
149  private showAnimate(animateScale: number, animateOpacity: number, isMoveFolder: boolean) {
150    let positionX = 0;
151    let positionY = 0;
152    if (this.onGetPosition) {
153      this.onGetPosition(this.getPosition.bind(this));
154      if (isMoveFolder) {
155        positionX = this.animateFolderPositionX;
156        positionY = this.animateFolderPositionY;
157      }
158    }
159    animateTo({
160      duration: 250,
161      tempo: 0.5,
162      curve: Curve.Friction,
163      delay: 0,
164      iterations: 1,
165      playMode: PlayMode.Normal,
166      onFinish: () => {
167        Log.showInfo(TAG, ` onFinish x: ${this.folderPositionX}, y: ${this.folderPositionY}`);
168      }
169    }, () => {
170      this.animateScale = animateScale;
171      this.animateOpacity = animateOpacity;
172      this.folderPositionX = positionX;
173      this.folderPositionY = positionY;
174    })
175  }
176
177  public getPosition(x: number, y: number): void  {
178    this.folderItemPositionX = x;
179    this.folderItemPositionY = y;
180    let screenWidth: number = AppStorage.get('screenWidth');
181    let screenHeight: number = AppStorage.get('screenHeight');
182    this.animateFolderPositionX = (screenWidth - this.folderGridSize * 1.5) / 2 - this.folderItemPositionX;
183    this.animateFolderPositionY = (screenHeight - this.folderGridSize * 1.5) / 2 - this.folderItemPositionY;
184    Log.showInfo(TAG, `getPosition animatePosition x: ${this.animateFolderPositionX}, y: ${this.animateFolderPositionY}`);
185  }
186
187  build() {
188    Column() {
189      Column() {
190        Badge({
191          count: this.badgeNumber,
192          maxCount: StyleConstants.MAX_BADGE_COUNT,
193          style: {
194            color: StyleConstants.DEFAULT_FONT_COLOR,
195            fontSize: StyleConstants.DEFAULT_BADGE_FONT_SIZE,
196            badgeSize: (this.badgeNumber > 0 ? StyleConstants.DEFAULT_BADGE_SIZE : 0),
197            badgeColor: Color.Red,
198          }
199        }) {
200          Stack() {
201            Column() {
202            }
203            .backgroundColor(Color.White)
204            .borderRadius(24)
205            .opacity(0.5)
206            .height(this.folderGridSize)
207            .width(this.folderGridSize)
208
209            Grid() {
210              ForEach(this.mShowAppList, (item) => {
211                GridItem() {
212                  AppIcon({
213                    iconSize: this.appIconSize,
214                    iconId: item.appIconId,
215                    icon: ResourceManager.getInstance().getCachedAppIcon(item.appIconId, item.bundleName, item.moduleName),
216                    bundleName: item.bundleName,
217                    moduleName: item.moduleName,
218                    badgeNumber: item.badgeNumber
219                  })
220                }
221                .height(StyleConstants.PERCENTAGE_100)
222                .width(StyleConstants.PERCENTAGE_100)
223                .onClick((event: ClickEvent) => {
224                  if (this.onAppIconClick) {
225                    this.onAppIconClick(event, item);
226                  }
227                })
228              }, (item) => JSON.stringify(item))
229
230              if (this.mSuperposeAppList.length > 0) {
231                GridItem() {
232                  Stack() {
233                    ForEach(this.mSuperposeAppList, (item) => {
234                      Stack({ alignContent: item.alignContent }) {
235                        if (item.isEmpty) {
236                          Column() {
237                            Column() {
238                            }
239                            .backgroundColor(Color.White)
240                            .borderRadius(10)
241                            .opacity(0.5)
242                            .width(StyleConstants.PERCENTAGE_100)
243                            .height(StyleConstants.PERCENTAGE_100)
244                          }
245                          .alignItems(HorizontalAlign.Start)
246                          .width(StyleConstants.PERCENTAGE_80)
247                          .height(StyleConstants.PERCENTAGE_80)
248                        } else {
249                          Column() {
250                            AppIcon({
251                              iconSize: this.appIconSize * StyleConstants.PERCENTAGE_80_number,
252                              iconId: item.appIconId,
253                              icon: ResourceManager.getInstance().getCachedAppIcon(item.appIconId, item.bundleName, item.moduleName),
254                              bundleName: item.bundleName,
255                              moduleName: item.moduleName,
256                              badgeNumber: item.badgeNumber
257                            })
258                          }
259                          .width(StyleConstants.PERCENTAGE_80)
260                          .height(StyleConstants.PERCENTAGE_80)
261                          .alignItems(HorizontalAlign.Start)
262                        }
263                      }
264                      .width(StyleConstants.PERCENTAGE_100)
265                      .height(StyleConstants.PERCENTAGE_100)
266                    }, (item) => JSON.stringify(item))
267                  }
268                  .width(this.isPad ?
269                    StyleConstants.DEFAULT_FOLDER_APP_ITEM_WIDTH_SMALL :
270                    StyleConstants.DEFAULT_FOLDER_APP_ITEM_WIDTH)
271                  .height(this.isPad ?
272                    StyleConstants.DEFAULT_FOLDER_APP_ITEM_WIDTH_SMALL :
273                    StyleConstants.DEFAULT_FOLDER_APP_ITEM_WIDTH)
274                }
275                .visibility(this.superposeIconVisible ? Visibility.Visible : Visibility.Hidden)
276                .width(StyleConstants.PERCENTAGE_100)
277                .height(StyleConstants.PERCENTAGE_100)
278                .onClick((event: ClickEvent) => {
279                  Log.showInfo(TAG, `last item onClick`);
280                  this.showAnimate(1.5, 0, true);
281                  if (this.onOpenFolderClick) {
282                    this.folderAnimateData.folderId = this.mFolderItem.folderId;
283                    this.folderAnimateData.isOpenFolder = true;
284                    AppStorage.setOrCreate('folderAnimateData', this.folderAnimateData);
285                    this.onOpenFolderClick(event, this.mFolderItem);
286                  }
287                })
288              }
289            }
290            .padding(this.gridMargin)
291            .columnsTemplate('1fr 1fr 1fr')
292            .rowsTemplate('1fr 1fr 1fr')
293            .columnsGap(this.gridGap)
294            .rowsGap(this.gridGap)
295            .onClick((event: ClickEvent) => {
296              Log.showInfo(TAG, `grid onClick`);
297              this.showAnimate(1.5, 0, true);
298              if (this.onOpenFolderClick) {
299                this.folderAnimateData.folderId = this.mFolderItem.folderId;
300                this.folderAnimateData.isOpenFolder = true;
301                AppStorage.setOrCreate('folderAnimateData', this.folderAnimateData);
302                this.onOpenFolderClick(event, this.mFolderItem);
303              }
304            })
305            .onTouch((event: TouchEvent) => {
306              Log.showInfo(TAG, "onTouch start");
307              if (this.onFolderTouch) {
308                this.onFolderTouch(event, this.mFolderItem);
309              }
310              Log.showInfo(TAG, "onTouch end");
311            })
312          }
313          .height(StyleConstants.PERCENTAGE_100)
314          .width(StyleConstants.PERCENTAGE_100)
315          .onHover((isHover: boolean) => {
316            Log.showInfo(TAG, `onHover isHover:${isHover}`);
317            this.isHover = isHover;
318          })
319          .bindContextMenu(this.MenuBuilder, ResponseType.LongPress)
320          .onDragStart((event: DragEvent) => {
321            return this.dragStart(event);
322          })
323          .onDragEnd((event: DragEvent, extraParams: string) => {
324            Log.showInfo(TAG, `onDragEnd event: [${event.getWindowX()}, ${event.getWindowY()}]` + event.getResult());
325            AppStorage.setOrCreate<LauncherDragItemInfo>('dragItemInfo', new LauncherDragItemInfo());
326          })
327        }
328        .height(this.folderGridSize)
329        .width(this.folderGridSize)
330
331        Column() {
332          AppName({
333            nameHeight: this.folderNameHeight,
334            nameSize: this.folderNameSize,
335            nameFontColor: this.nameFontColor,
336            appName: this.mFolderItem.folderName,
337            nameLines: this.folderNameLines,
338            marginTop: this.iconNameMargin
339          })
340        }
341        .visibility(this.showFolderName ? Visibility.Visible : Visibility.Hidden)
342      }
343      .bindContextMenu(this.MenuBuilder, ResponseType.RightClick)
344      .width(StyleConstants.PERCENTAGE_100)
345      .height(StyleConstants.PERCENTAGE_100)
346      .offset({ x: this.folderPositionX, y: this.folderPositionY })
347      .scale({ x: this.isHover ? 1.05 : this.animateScale, y: this.isHover ? 1.05 : this.animateScale })
348      .opacity(this.animateOpacity)
349    }
350    .width(this.isSelect ? this.folderGridSize + StyleConstants.DEFAULT_40 : StyleConstants.PERCENTAGE_100)
351    .height(this.isSelect ? this.folderGridSize + StyleConstants.DEFAULT_40 : StyleConstants.PERCENTAGE_100)
352    .backgroundColor(this.isSelect ? StyleConstants.DEFAULT_BROAD_COLOR : StyleConstants.DEFAULT_TRANSPARENT_COLOR)
353    .borderRadius(this.isSelect ? StyleConstants.DEFAULT_15 : StyleConstants.DEFAULT_0)
354    .padding(this.isSelect ? { left: StyleConstants.DEFAULT_20,
355                               right: StyleConstants.DEFAULT_20, top: this.mPaddingTop + StyleConstants.DEFAULT_10 } : { top: this.mPaddingTop })
356  }
357}