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