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 { AppMenu } from '@ohos/common'; 17import { AppIcon } from '@ohos/common'; 18import { DockItemInfo } from '@ohos/common'; 19import { ScrollerComponent } from '@ohos/common'; 20import { CommonConstants } from '@ohos/common'; 21import { StyleConstants } from '@ohos/common'; 22import { ResourceManager } from '@ohos/common'; 23import { Log } from '@ohos/common'; 24import { SmartDockStyleConfig } from '../config/SmartDockStyleConfig'; 25 26let mSmartDockStyleConfig: SmartDockStyleConfig = null; 27const TAG = 'RecentLayout'; 28 29@Component 30export default struct RecentLayout { 31 @StorageLink('sysUiRecentOnClickEvent') @Watch('sysUiRecentOnClick') sysUiRecentOnClickEvent: number = 0; 32 @StorageLink('dockPadding') dockPadding: {right: number, left: number, top: number, bottom: number} = {right: 0, left: 0, top: 0, bottom: 0}; 33 @State isHover: boolean = false; 34 @State showPopup: boolean = false; 35 @State onHoverItem: string = ''; 36 @Link @Watch('onDockListChange') appList: Array<DockItemInfo>; 37 mRecentMaxNum: number; 38 mSmartDockStyleConfig: SmartDockStyleConfig; 39 onItemClick: Function = null; 40 buildMenu: Function = null; 41 onHoverEvent: Function = null; 42 onDockListChangeFunc: Function = null; 43 isScrollHover: boolean = false; 44 popup: { 45 show: boolean, 46 showItem: string, 47 popup 48 } = { show: false, showItem: '', popup: null }; 49 onClickWithPopup: boolean = false; 50 autoCancel: boolean = false; 51 private updateData: Function = null; 52 53 aboutToAppear(): void { 54 55 mSmartDockStyleConfig = this.mSmartDockStyleConfig; 56 } 57 58 private sysUiRecentOnClick() { 59 this.showPopup = false; 60 this.popup = { show: false, showItem: '', popup: null }; 61 } 62 63 @Builder popupBuilder() { 64 Column() { 65 ScrollerComponent({ 66 popupHide: () => { 67 this.showPopup = false; 68 this.popup = { show: false, showItem: '', popup: null }; 69 }, 70 updateData: (show, bundleName, callback) => { 71 this.updateData = () => { 72 callback(); 73 setTimeout(() => { 74 this.onHoverEvent(true, bundleName); 75 }, 100) 76 } 77 if (show) { 78 this.updateData(); 79 this.getShowPopup(); 80 return; 81 } 82 this.showPopup = false; 83 this.popup = { show: false, showItem: '', popup: null }; 84 } 85 }) 86 }.onHover((isScrollHover: boolean) => { 87 this.autoCancel = false; 88 if (isScrollHover) { 89 this.isScrollHover = true; 90 } else { 91 this.isScrollHover = false; 92 } 93 this.getShowPopup(); 94 }) 95 .onClick(() => { 96 this.getShowPopup(); 97 }) 98 } 99 100 async getShowPopup() { 101 await this.delay(500); 102 if (this.popup.show || this.isScrollHover) { 103 this.showPopup = true; 104 } else { 105 this.showPopup = false; 106 } 107 return this.showPopup; 108 } 109 110 delay(ms: number) { 111 return new Promise(resolve => setTimeout(resolve, ms)); 112 } 113 114 build() { 115 List({ space: mSmartDockStyleConfig.mListItemGap }) { 116 ForEach(this.appList, (item) => { 117 ListItem() { 118 AppItem({ 119 appInfo: item, 120 buildMenu: this.buildMenu 121 }) 122 } 123 .bindPopup(this.showPopup && item.bundleName == this.onHoverItem && !AppStorage.Get('smartDockShowMenu') as boolean, { 124 builder: this.popupBuilder, 125 placement: Placement.Top, 126 enableArrow: true, 127 autoCancel: this.autoCancel, 128 maskColor: ('rgba(250,250,250,0)'), 129 popupColor: ('rgba(250,250,250,0.6)'), 130 onStateChange: (e) => { 131 if (!e.isVisible && this.autoCancel) { 132 this.popup = { show: false, showItem: '', popup: null }; 133 this.onHoverItem = ''; 134 this.onClickWithPopup = false; 135 this.autoCancel = false; 136 this.showPopup = false; 137 AppStorage.SetOrCreate('snapshotList', []); 138 AppStorage.SetOrCreate('recentShowPopup', false); 139 } 140 if (this.updateData) { 141 this.updateData(); 142 this.updateData = () => { 143 } 144 } 145 }, 146 }) 147 .onHover((isHover) => { 148 this.autoCancel = false; 149 if (this.onHoverEvent) { 150 this.onHoverEvent(isHover, item.bundleName); 151 this.onHoverItem = item.bundleName; 152 this.getShowPopup(); 153 } 154 }) 155 .onClick((event: ClickEvent) => { 156 this.onItemClick(event, item); 157 this.onClickWithPopup = AppStorage.Get('recentShowPopup'); 158 Log.showInfo(TAG, `onClick this.onClickWithPopup: ${this.onClickWithPopup}`); 159 if (this.onClickWithPopup) { 160 this.autoCancel = true; 161 this.showPopup = true 162 this.onHoverItem = item.bundleName; 163 } 164 AppStorage.SetOrCreate('recentShowPopup', false); 165 }) 166 }, (item) => JSON.stringify(item)) 167 } 168 .padding(this.dockPadding) 169 .width(this.getListWidth()) 170 .height(this.mSmartDockStyleConfig.mDockHeight) 171 .backgroundColor(this.mSmartDockStyleConfig.mBackgroundColor) 172 .borderRadius(this.mSmartDockStyleConfig.mDockRadius) 173 .backdropBlur(this.mSmartDockStyleConfig.mBackdropBlur) 174 .visibility(this.getListWidth() === 0 ? Visibility.None : Visibility.Visible) 175 .listDirection(this.mSmartDockStyleConfig.mListDirection) 176 } 177 178 getListWidth(): number { 179 let mRecentMaxNum = this.mSmartDockStyleConfig.mMaxRecentNum; 180 let width = 0; 181 if (AppStorage.Get("deviceType") == CommonConstants.DEFAULT_DEVICE_TYPE) { 182 return width; 183 } 184 if (typeof this.appList === 'undefined' || this.appList == null || this.appList.length === 0) { 185 return width; 186 } 187 let num = this.appList.length; 188 if (num > mRecentMaxNum) { 189 num = mRecentMaxNum; 190 } 191 width = this.mSmartDockStyleConfig.mDockPadding * 2 + num * (this.mSmartDockStyleConfig.mListItemWidth) + (num - 1) * (this.mSmartDockStyleConfig.mListItemGap); 192 return width; 193 } 194 195 private onDockListChange() { 196 this.onDockListChangeFunc(); 197 } 198} 199 200@Component 201struct AppItem { 202 @State isShow: boolean = false; 203 appInfo: DockItemInfo = null; 204 buildMenu: Function = null; 205 private menuInfo; 206 207 aboutToAppear(): void { 208 this.menuInfo = this.buildMenu(this.appInfo); 209 } 210 211 private getLongPress(): boolean { 212 return AppStorage.Get('isLongPress'); 213 } 214 215 @Builder MenuBuilder() { 216 Column() { 217 AppMenu({ 218 menuInfoList: this.menuInfo, 219 closeMenu: () => { 220 this.isShow = false; 221 } 222 }) 223 } 224 .alignItems(HorizontalAlign.Center) 225 .justifyContent(FlexAlign.Center) 226 .width(StyleConstants.CONTEXT_MENU_WIDTH) 227 .height(StyleConstants.DEFAULT_40 * this.menuInfo.length + StyleConstants.DEFAULT_8) 228 } 229 230 build() { 231 Column() { 232 Row() { 233 AppIcon({ 234 iconSize: mSmartDockStyleConfig.mIconSize, 235 iconId: this.appInfo.appIconId, 236 bundleName: this.appInfo.bundleName, 237 moduleName: this.appInfo.moduleName, 238 icon: ResourceManager.getInstance().getCachedAppIcon(this.appInfo.appIconId, 239 this.appInfo.bundleName, this.appInfo.moduleName), 240 badgeNumber: this.appInfo.badgeNumber 241 }) 242 } 243 .width(mSmartDockStyleConfig.mListItemWidth) 244 .height(mSmartDockStyleConfig.mListItemHeight) 245 .backgroundColor(mSmartDockStyleConfig.mItemBackgroundColor) 246 .borderRadius(mSmartDockStyleConfig.mItemBorderRadius) 247 } 248 .gesture( 249 LongPressGesture({ repeat: false }) 250 .onAction((event: GestureEvent) => { 251 this.isShow = true; 252 AppStorage.SetOrCreate('isLongPress', true); 253 }) 254 ) 255 .bindPopup(this.isShow, { 256 builder: this.MenuBuilder, 257 placement: Placement.Top, 258 popupColor: Color.White, 259 //@ts-ignore 260 arrowOffset: 3 * (mSmartDockStyleConfig.mIconSize / 2) + mSmartDockStyleConfig.mListItemGap, 261 onStateChange: (e) => { 262 if (!e.isVisible) { 263 this.isShow = false; 264 } 265 AppStorage.SetOrCreate('smartDockShowMenu', e.isVisible) 266 }, 267 autoCancel: true 268 }) 269 .onTouch((event: TouchEvent) => { 270 if (event.type == CommonConstants.TOUCH_TYPE_UP) { 271 AppStorage.SetOrCreate('isLongPress', false); 272 } 273 if (AppStorage.Get('isDrag')) { 274 this.isShow = false; 275 } 276 }) 277 .onMouse((event: MouseEvent) => { 278 Log.showInfo(TAG, `onMouse MouseType: ${event.button}`); 279 if (event.button == MouseButton.Right) { 280 event.stopPropagation(); 281 AppStorage.SetOrCreate('selectDesktopAppItem', ''); 282 this.isShow = true; 283 } 284 }) 285 } 286}