• 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 {
17  AppMenu,
18  AppIcon,
19} from '@ohos/common/component'
20import {
21  DockItemInfo,
22  LauncherDragItemInfo,
23  CommonConstants,
24  StyleConstants,
25  ResourceManager,
26  Log,
27  MenuInfo,
28  BadgeManager
29} from '@ohos/common';
30import { SmartDockStyleConfig } from '../config/SmartDockStyleConfig';
31import SmartDockDragHandler from '../common/SmartDockDragHandler';
32
33let mSmartDockStyleConfig: SmartDockStyleConfig | null = null;
34const TAG = 'ResidentLayout';
35
36interface DockPadding {
37  right: number;
38  left: number;
39  top: number;
40  bottom: number;
41}
42
43@Component
44export default struct ResidentLayout {
45  @StorageLink('dockPadding') dockPadding: DockPadding = { right: 0, left: 0, top: 0, bottom: 0 };
46  @StorageLink('residentList') @Watch('onDockListChange') appList: Array<DockItemInfo> = [];
47  @Link mSmartDockStyleConfig: SmartDockStyleConfig;
48  onItemClick: (event: ClickEvent, item: DockItemInfo) => void = (event: ClickEvent, item: DockItemInfo) => {};
49  buildMenu: (item: DockItemInfo) => MenuInfo[] = (item: DockItemInfo): MenuInfo[] => [];
50  onDockListChangeFunc: () => void = () => {};
51
52  aboutToAppear(): void {
53    mSmartDockStyleConfig = this.mSmartDockStyleConfig;
54    this.onDockListChange();
55  }
56
57  aboutToDisappear(): void {
58  }
59
60  getListWidth(): number {
61    let residentMaxNum = this.mSmartDockStyleConfig.mMaxDockNum;
62    let width = 0.0;
63    if (AppStorage.get('deviceType') == CommonConstants.DEFAULT_DEVICE_TYPE) {
64      Log.showDebug(TAG, `getListWidth mDockPadding: ${this.mSmartDockStyleConfig.mDockPadding}, mMaxNum: ${residentMaxNum}`);
65      width = this.mSmartDockStyleConfig.mDockPadding * 2 + residentMaxNum *
66        (this.mSmartDockStyleConfig.mListItemWidth) + (residentMaxNum - 1) * (this.mSmartDockStyleConfig.mListItemGap);
67      Log.showDebug(TAG, `getListWidth width: ${width}`);
68    } else {
69      if (this.appList == null || this.appList.length === 0) {
70      } else {
71        let num = this.appList.length;
72        if (num > residentMaxNum) {
73          num = residentMaxNum;
74        }
75        width = this.mSmartDockStyleConfig.mDockPadding * 2 + num *
76          (this.mSmartDockStyleConfig.mListItemWidth) + (num - 1) * (this.mSmartDockStyleConfig.mListItemGap);
77      }
78    }
79    return width;
80  }
81
82  private onDockListChange() {
83    this.onDockListChangeFunc();
84  }
85
86  build() {
87    if (this.getListWidth && this.getListWidth() !== 0) {
88      Row() {
89        List({ space: this.appList.length == 0 ? 0 : this.mSmartDockStyleConfig.mListItemGap }) {
90          ForEach(this.appList, (item: DockItemInfo) => {
91            ListItem() {
92              AppItem({
93                appInfo: item,
94                buildMenu: this.buildMenu,
95                onItemClick: this.onItemClick
96              })
97            }
98          }, (item: DockItemInfo) => JSON.stringify(item))
99        }
100        .enableScrollInteraction(false)
101        .scrollBar(BarState.Off)
102        .height('100%')
103        .animation({
104          curve: Curve.Friction
105        })
106        .listDirection(Axis[this.mSmartDockStyleConfig.mListDirection])
107      }
108      .backgroundColor(this.mSmartDockStyleConfig.mBackgroundColor)
109      .borderRadius(this.mSmartDockStyleConfig.mDockRadius)
110      .backdropBlur(this.mSmartDockStyleConfig.mBackdropBlur)
111      .padding(this.appList.length == 0 ? this.mSmartDockStyleConfig.mDockPadding : this.dockPadding)
112      .width(this.getListWidth())
113      .height(this.mSmartDockStyleConfig.mDockHeight)
114      .justifyContent(FlexAlign.Center)
115      .onDragEnter((event: DragEvent, extraParams: string) => {
116        Log.showDebug(TAG, `onDragEnter extraParams: ${extraParams}, event: [${event.getWindowX()}, ${event.getWindowY()}]`);
117      })
118      .onDragMove((event: DragEvent, extraParams: string) => {
119        Log.showDebug(TAG, `onDragMove event: [${event.getWindowX()}, ${event.getWindowY()}]`);
120      })
121      .onDragLeave((event: DragEvent, extraParams: string) => {
122        Log.showDebug(TAG, `onDragLeave event: [${event.getWindowX()}, ${event.getWindowY()}]`);
123      })
124      .onDrop((event: DragEvent, extraParams: string) => {
125        Log.showInfo(TAG, `onDrop event: [${event.getWindowX()}, ${event.getWindowY()}]`);
126        const dragResult = SmartDockDragHandler.getInstance().onDragDrop(event.getWindowX(), event.getWindowY());
127        AppStorage.setOrCreate('selectAppIndex', null);
128        const dragItemInfo: LauncherDragItemInfo = AppStorage.get('dragItemInfo') as LauncherDragItemInfo;
129        if (dragItemInfo.bundleName) {
130          BadgeManager.getInstance().updateBadgeNumber(dragItemInfo.bundleName, dragItemInfo.badgeNumber);
131        }
132        if (!dragResult) {
133          AppStorage.setOrCreate<LauncherDragItemInfo>('dragItemInfo', new LauncherDragItemInfo());
134        } else {
135          // Wait for the UI rendering to end.
136          setTimeout(() => {
137            AppStorage.setOrCreate<LauncherDragItemInfo>('dragItemInfo', new LauncherDragItemInfo());
138          }, 50);
139        }
140      })
141    }
142  }
143}
144
145@Component
146struct AppItem {
147  @StorageLink('dragItemInfo') smartDragItemInfo: LauncherDragItemInfo = new LauncherDragItemInfo();
148  @StorageLink('dragItemType') dragItemType: number = CommonConstants.DRAG_FROM_DOCK;
149  @State isShow: boolean = false;
150  onItemClick: (event: ClickEvent, item: DockItemInfo) => void = (event: ClickEvent, item: DockItemInfo) => {};
151  appInfo: DockItemInfo = new DockItemInfo();
152  buildMenu: (item: DockItemInfo) => MenuInfo[] = (item: DockItemInfo): MenuInfo[] => [];
153  private menuInfo: MenuInfo[] = [];
154
155  aboutToAppear(): void {
156    this.menuInfo = this.buildMenu(this.appInfo);
157  }
158
159  aboutToDisappear(): void {
160    this.isShow = false;
161    this.menuInfo = [];
162  }
163
164  private getLongPress(): boolean {
165    return AppStorage.get('isLongPress') as boolean;
166  }
167
168  @Builder MenuBuilder() {
169    Column() {
170      AppMenu({
171        menuInfoList: this.menuInfo,
172        closeMenu: () => {
173          this.isShow = false;
174        }
175      })
176    }
177    .alignItems(HorizontalAlign.Center)
178    .justifyContent(FlexAlign.Center)
179    .width(StyleConstants.CONTEXT_MENU_WIDTH)
180    .height(StyleConstants.DEFAULT_40 * this.menuInfo.length + StyleConstants.DEFAULT_8)
181  }
182
183  build() {
184    Column() {
185      AppIcon({
186        iconSize: mSmartDockStyleConfig?.mIconSize as number,
187        iconId: this.appInfo.appIconId,
188        bundleName: this.appInfo.bundleName,
189        moduleName: this.appInfo.moduleName,
190        icon: ResourceManager.getInstance().getCachedAppIcon(this.appInfo.appIconId,
191        this.appInfo.bundleName, this.appInfo.moduleName),
192        badgeNumber: this.appInfo.badgeNumber
193      })
194    }
195    .visibility(this.dragItemType === CommonConstants.DRAG_FROM_DOCK &&
196      this.smartDragItemInfo.keyName === this.appInfo.keyName ?
197    Visibility.Hidden : Visibility.Visible)
198    .width(mSmartDockStyleConfig?.mListItemWidth as number)
199    .height(mSmartDockStyleConfig?.mListItemHeight as number)
200    .backgroundColor(mSmartDockStyleConfig?.mItemBackgroundColor as string)
201    .borderRadius(mSmartDockStyleConfig?.mItemBorderRadius as number)
202    .parallelGesture(
203    LongPressGesture({ repeat: false })
204      .onAction((event: GestureEvent) => {
205        Log.showInfo(TAG, 'onAction start');
206        this.isShow = true;
207        AppStorage.setOrCreate('isLongPress', true);
208      })
209    )
210    .bindPopup(this.isShow, {
211      builder: this.MenuBuilder,
212      placement: Placement.Top,
213      popupColor: Color.White,
214      arrowOffset: AppStorage.get('deviceType') == CommonConstants.DEFAULT_DEVICE_TYPE
215        ? null : 3 * ((mSmartDockStyleConfig?.mIconSize as number) / 2) +
216          (mSmartDockStyleConfig?.mListItemGap as number), // Avoid the popup offset problem in phone form
217      onStateChange: (e) => {
218        if (!e.isVisible) {
219          this.isShow = false;
220        }
221        AppStorage.setOrCreate('smartDockShowMenu', e.isVisible)
222      },
223      autoCancel: true
224    })
225    .onTouch((event: TouchEvent) => {
226      Log.showInfo(TAG, `onTouch event type: ${event.type}`);
227      if (event.type === CommonConstants.TOUCH_TYPE_UP && this.smartDragItemInfo.isDragging) {
228        let mIsDragEffectArea =
229        SmartDockDragHandler.getInstance().isDragEffectArea(event.touches[0].windowX, event.touches[0].windowY);
230        if (!mIsDragEffectArea) {
231          AppStorage.setOrCreate<LauncherDragItemInfo>('dragItemInfo', new LauncherDragItemInfo());
232          AppStorage.setOrCreate('selectAppIndex', null);
233        }
234        AppStorage.setOrCreate('isLongPress', false);
235      }
236      if (this.smartDragItemInfo.isDragging) {
237        this.isShow = false;
238      }
239    })
240    .onClick((event) => {
241      this.onItemClick(event, this.appInfo);
242    })
243    .onMouse((event: MouseEvent) => {
244      Log.showInfo(TAG, `onMouse MouseType: ${event.button}`);
245      if (event.button == MouseButton.Right) {
246        event.stopPropagation();
247        AppStorage.setOrCreate('selectDesktopAppItem', '');
248        this.isShow = true;
249      }
250    })
251    .onDragStart((event: DragEvent, extraParams: string) => {
252      Log.showInfo(TAG, 'DragStart');
253      this.dragItemType = CommonConstants.DRAG_FROM_DOCK;
254      this.appInfo.isDragging = true;
255      this.smartDragItemInfo = this.appInfo as LauncherDragItemInfo;
256      Log.showInfo(TAG, `smartDragItemInfo: ${JSON.stringify(this.smartDragItemInfo)}`);
257      const selectAppIndex =
258      SmartDockDragHandler.getInstance().getDragItemIndexByCoordinates(event.getWindowX(), event.getWindowY());
259      AppStorage.setOrCreate('selectAppIndex', selectAppIndex);
260    })
261    .onDragEnd((event: DragEvent, extraParams: string) => {
262      Log.showInfo(TAG, `onDragEnd event: [${event.getWindowX()}, ${event.getWindowY()}]` + event.getResult());
263      AppStorage.setOrCreate<LauncherDragItemInfo>('dragItemInfo', new LauncherDragItemInfo());
264    })
265  }
266}