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