1/*
2 * Copyright (c) 2022-2023 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 router from '@ohos.router';
17import {
18  Action,
19  AlbumDefine,
20  BigDataConstants,
21  BroadCast,
22  BroadCastConstants,
23  BroadCastManager,
24  CommonObserverCallback,
25  Constants,
26  Log,
27  MediaItem,
28  MediaObserver,
29  PhotoDataImpl,
30  ReportToBigDataUtil,
31  ScreenManager,
32  SelectUtil,
33  ThirdSelectManager,
34  UiUtil,
35  UserFileManagerAccess,
36  ViewData,
37  BrowserDataFactory,
38  MediaDataSource
39} from '@ohos/common';
40import {
41  BrowserController,
42  GridScrollBar,
43  ImageGridItemComponent,
44  NoPhotoComponent,
45  NoPhotoIndexComponent
46} from '@ohos/common/CommonComponents';
47import { ThirdSelectedPageActionBar } from './ThirdSelectedPageActionBar';
48import { ThirdSelectedPanel } from './ThirdSelectedPanel';
49import { CameraGridItemComponent } from './CameraGridItemComponent';
50import {
51  FormConstants,
52  IS_HORIZONTAL,
53  IS_SPLIT_MODE,
54  LEFT_BLANK,
55  SelectParams,
56  THIRD_SELECT_IS_ORIGIN
57} from '../utils/ThirdSelectConstants';
58import ability from '@ohos.ability.ability';
59import common from '@ohos.app.ability.common';
60import SmartPickerRecommendInfo from '../common/SmartPickerRecommendInfo';
61import SmartPickerRecommendInfoObserver from '../common/SmartPickerRecommendInfoObserver';
62import { PickerMediaDataSource } from '../common/PickerMediaDataSource';
63import SmartPickerDataImpl from '../common/SmartPickerDataImpl';
64import SmartPickerRecommendTabInfo from '../common/SmartPickerRecommendTabInfo';
65import SmartPickerConstants from '../common/SmartPickerConstants';
66import { SmartPickerManager } from '../common/SmartPickerManager';
67import { ThirdSelectSmartRecommendTabBar } from './ThirdSelectSmartRecommendTabBar';
68import SmartPickerDataAdapter from '../common/SmartPickerDataAdapter';
69import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession';
70
71const TAG: string = 'thiSel_ThirdSelectPhotoGridBase';
72
73let localStorage = LocalStorage.getShared();
74
75// Third Select Album Page
76@Component
77export struct ThirdSelectPhotoGridBase {
78  @State selectedCount: number = 0;
79  @Provide isSelectedMode: boolean = true;
80  @Provide moreMenuList: Action[] = [];
81  @Provide rightClickMenuList: Action[] = [];
82  photoDataImpl: PhotoDataImpl | undefined =
83    BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_PHOTO) as PhotoDataImpl;
84  smartPickerDataImpl: SmartPickerDataImpl | undefined;
85  dataSource: PickerMediaDataSource = new PickerMediaDataSource(Constants.DEFAULT_SLIDING_WIN_SIZE, this.photoDataImpl);
86  @Provide broadCast: BroadCast = new BroadCast();
87  @Provide isShow: boolean = true;
88  selectManager: ThirdSelectManager | null = null;
89  isActive = false;
90  @State title: string = '';
91  @State isEmpty: boolean = false;
92  @StorageLink(IS_SPLIT_MODE) isSplitMode: boolean = ScreenManager.getInstance().isSplitMode();
93  @StorageLink(LEFT_BLANK) leftBlank: number[] =
94    [0, ScreenManager.getInstance().getStatusBarHeight(), 0, ScreenManager.getInstance().getNaviBarHeight()];
95  @StorageLink(IS_HORIZONTAL) isHorizontal: boolean = ScreenManager.getInstance().isHorizontal();
96  DEFAULT_TOAST_DURATION = 2000;
97  @State gridRowCount: number = 0;
98  @State isShowScrollBar: boolean = false;
99  @State currentUri: string = '';
100  @Provide isShowBar: boolean = true;
101  scroller: Scroller = new Scroller();
102  isFirstEnter: boolean = false;
103  @Prop @Watch('onPageChanged') pageStatus: boolean = false;
104  backFuncBinder: Function | null = null;
105  @State selectParams: SelectParams = SelectParams.defaultParam();
106  @State screenHeight: number = ScreenManager.getInstance().getWinHeight();
107  @StorageLink('placeholderIndex') @Watch('onPlaceholderChanged') placeholderIndex: number = -1;
108  @ObjectLink @Watch('onBrowserControllerChanged') browserController: BrowserController;
109  @State isShowSmartRecommendTabBar: boolean = false;
110  @State smartRecommendTabItems: Array<SmartPickerRecommendTabInfo> = [];
111  @State isAllMediaAlbum: boolean = true;
112  @State currentSmartRecommendTabIndex: number = 0;
113  private smartPickerRecommendInfoObserver: SmartPickerRecommendInfoObserver =
114    new SmartPickerRecommendInfoObserver(this);
115  private smartPickerManager: SmartPickerManager | undefined;
116  private appBroadCast: BroadCast = BroadCastManager.getInstance().getBroadCast();
117  private dataObserver: CommonObserverCallback = new CommonObserverCallback(this);
118  private selectFromCameraFunc: Function = (): void => {};
119  private itemId: string = '';
120  private isItemIdChange: boolean = false;
121  private onWindowSizeChangeCallBack: Function = () => this.initGridRowCount();
122  private selectFunc: Function = (position: number, key: string, value: boolean, callback: Function): void =>
123  this.onSelectCallback(position, key, value, callback);
124  private jumpThirdPhotoBrowserFunc: Function = (name: string, item: MediaItem, geometryTapIndex: number,
125                                                 geometryTransitionString: string, isSelectMode = false): void =>
126  this.jumpBrowserCallback(name, item, geometryTapIndex, geometryTransitionString, isSelectMode);
127  private onDataReloadedFunc: Function = (): void => this.onReloadFinishedCallback();
128  private onSwitchSmartRecommendTabFunc: Function = (index: number): void => this.onSwitchSmartRecommendTab(index);
129  private funcOnLoadingFinished: Function = (size: number): void => this.onLoadingFinished(size);
130  private pickerInitDataFirstQueryFinishFunc: Function = (): void => this.pickerInitDataFirstQueryFinish();
131
132  onPlaceholderChanged() {
133    Log.debug(TAG, 'onPlaceholderChanged placeholderIndex is ' + this.placeholderIndex);
134    if (this.placeholderIndex != -1) {
135      this.scroller.scrollToIndex(this.placeholderIndex);
136    }
137  }
138
139  private onSwitchSmartRecommendTab(index: number): void {
140    Log.debug(TAG, ' onSwitchSmartRecommendTab index:' + index)
141    AppStorage.setOrCreate<number>('placeholderIndex', Constants.INVALID);
142    this.currentSmartRecommendTabIndex = index;
143    Log.debug(TAG, ' onSwitchSmartRecommendTab this.isShowSmartRecommendTabBar:' + this.isShowSmartRecommendTabBar)
144    if (this.isShowSmartRecommendTabBar) {
145      this.selectParams.cameraAble = this.smartRecommendTabItems[this.currentSmartRecommendTabIndex].isCameraAble();
146    }
147    this.dataSource.changeDataImpl(this.currentSmartRecommendTabIndex === 0 ?
148    this.photoDataImpl : this.smartPickerDataImpl);
149    this.smartRecommendTabItems[this.currentSmartRecommendTabIndex].setUserClickTab(true);
150    this.dataSource.setAlbumUri(this.smartRecommendTabItems[this.currentSmartRecommendTabIndex].getAlbumUri());
151    this.dataSource.resetActiveWindow();
152    this.dataSource.initData();
153  }
154
155  onBrowserControllerChanged(): void {
156    if (!this.browserController.isBrowserShow) {
157      ScreenManager.getInstance().setSystemUi(true);
158    }
159  }
160
161  onMenuClicked(action: Action) {
162    Log.info(TAG, `onMenuClicked, action: ${action.actionID}`);
163    if (action.actionID === Action.BACK.actionID) {
164      this.goBackFormEditor();
165    } else if (action.actionID === Action.CANCEL.actionID) {
166      this.setPickResult();
167    } else if (action.actionID === Action.OK.actionID) {
168      let uriArray: string[] = [];
169      if (this.selectManager !== null) {
170        uriArray = SelectUtil.getUriArray(this.selectManager.clickedSet);
171      }
172      this.setPickResult(uriArray);
173    } else if (action.actionID === Action.NAVIGATION_ALBUMS.actionID) {
174      let params = this.selectParams;
175      params.isFirstEnter = false;
176      router.pushUrl({
177        url: 'pages/ThirdSelectAlbumSetPage',
178        params: this.selectParams
179      })
180      ReportToBigDataUtil.report(BigDataConstants.SELECT_PICKER_SWITCH_ALBUM, undefined);
181    }
182  }
183
184  aboutToAppear(): void {
185    let param: SelectParams;
186    if (localStorage?.has(Constants.PHOTO_PICKER_SESSION_KEY)) {
187      param = localStorage.get<SelectParams>(Constants.PHOTO_PICKER_PARAMS_KEY) as SelectParams;
188    } else {
189      param = router.getParams() as SelectParams;
190    }
191    this.initSelectParams(param);
192    if (param && param.preselectedUris) {
193      this.selectParams.preselectedUris = param.preselectedUris;
194    }
195    this.selectParams.cameraAble = param.cameraAble;
196
197    // 更新编辑许可
198    this.selectParams.editAble = param.editAble;
199    AppStorage.setOrCreate<boolean>(Constants.KEY_OF_IS_THIRD_EDITABLE, this.selectParams.editAble);
200    if (this.selectParams.isFromFa) {
201      this.selectParams.filterMediaType = AlbumDefine.FILTER_MEDIA_TYPE_IMAGE;
202      AppStorage.setOrCreate(FormConstants.FORM_ITEM_ALBUM_URI, param.uri);
203      AppStorage.setOrCreate(FormConstants.FORM_ITEM_DISPLAY_NAME, param.itemDisplayName);
204    }
205    this.dataSource.setFilterMediaType(this.selectParams.filterMediaType);
206    this.initSelectManager();
207    this.selectManager?.setIsMultiPick(this.selectParams.isMultiPick);
208
209    let self = this;
210    // 后续phone缩略图支持横竖屏后再放开
211    if (AppStorage.Get('deviceType') as string !== Constants.DEFAULT_DEVICE_TYPE) {
212      ScreenManager.getInstance().on(ScreenManager.ON_WIN_SIZE_CHANGED, this.onWindowSizeChangeCallBack);
213    }
214    this.initGridRowCount();
215    if (localStorage && localStorage.has(SmartPickerConstants.SMART_PICKER_MANAGER)) {
216      this.smartPickerManager = localStorage.get<SmartPickerManager>(SmartPickerConstants.SMART_PICKER_MANAGER);
217      if (this.smartPickerManager) {
218        this.smartPickerManager.addPickerRecommendInfoListener(this.smartPickerRecommendInfoObserver);
219      }
220    }
221    this.dataSource.setBroadCast(this.broadCast);
222    this.broadCast.on(BroadCastConstants.SELECT, this.selectFunc);
223    this.broadCast.on(BroadCastConstants.JUMP_THIRD_PHOTO_BROWSER, this.jumpThirdPhotoBrowserFunc);
224    this.broadCast.on(Constants.ON_LOADING_FINISHED, this.funcOnLoadingFinished);
225    this.broadCast.on(BroadCastConstants.ON_DATA_RELOADED, this.onDataReloadedFunc);
226    this.broadCast.on(SmartPickerConstants.PICKER_INIT_DATA_FIRST_QUERY_FINISH,
227      this.pickerInitDataFirstQueryFinishFunc);
228    this.selectManager?.registerCallback('updateCount',
229      (newState: number) => {
230        Log.info(TAG, `updateSelectedCount ${newState}`);
231        self.selectedCount = newState;
232        self.selectManager?.emitCallback('thirdSelectUpdateCount', [newState]);
233      });
234    this.dataSource.registerCallback('updateCount',
235      (newState: number) => {
236        Log.info(TAG, `updateTotalCount ${newState}`);
237        self.isShowScrollBar = (newState > Constants.PHOTOS_CNT_FOR_HIDE_SCROLL_BAR);
238        self.selectManager?.setTotalCount(newState);
239      });
240    this.broadCast.on(BroadCastConstants.THIRD_PICKER_SWITCH_SMART_RECOMMEND_TAB, this.onSwitchSmartRecommendTabFunc);
241    MediaObserver.getInstance().registerObserver(this.dataObserver);
242    this.isActive = true;
243
244    // save all photo dataSource
245    if (this.dataSource.albumUri === '' && AppStorage.get<MediaDataSource>(Constants.APP_KEY_ALL_PHOTO_DATASOURCE) === undefined) {
246      AppStorage.setOrCreate(Constants.APP_KEY_ALL_PHOTO_DATASOURCE, this.dataSource);
247    }
248    Log.error(TAG, 'meow data count = ' + this.dataSource.totalCount());
249  }
250
251  onBackPress() {
252    this.onMenuClicked(this.selectParams.isFromFa ? Action.BACK : Action.CANCEL);
253  }
254
255  onPageShow() {
256    Log.debug(TAG, 'onPageShow');
257    let param: SelectParams = router.getParams() as SelectParams;
258    this.isItemIdChange = (this.itemId && param && this.itemId !== param.itemId) as boolean;
259    if (this.isItemIdChange) {
260      this.initSelectParams(param);
261    }
262
263    MediaObserver.getInstance().registerObserver(this.dataObserver);
264    this.appBroadCast.emit(BroadCastConstants.THIRD_ROUTE_PAGE, []);
265    this.isShow = true;
266    if (!this.browserController.isBrowserShow) {
267      ScreenManager.getInstance().setSystemUi(true);
268    }
269    this.onActive();
270  }
271
272  onPageChanged() {
273    if (this.pageStatus) {
274      this.onPageShow();
275    } else {
276      this.onPageHide();
277    }
278  }
279
280  onPageHide() {
281    Log.debug(TAG, 'onPageHide');
282    this.isShow = false;
283    this.onInActive();
284  }
285
286  aboutToDisappear(): void {
287    ScreenManager.getInstance().off(ScreenManager.ON_WIN_SIZE_CHANGED, this.onWindowSizeChangeCallBack);
288    MediaObserver.getInstance().unregisterObserver(this.dataObserver);
289    if (this.smartPickerManager) {
290      this.smartPickerManager.removePickerRecommendInfoListener(this.smartPickerRecommendInfoObserver);
291    }
292    this.dataObserver.clearSource();
293    if (this.broadCast) {
294      this.broadCast.off(BroadCastConstants.SELECT, this.selectFunc);
295      this.broadCast.off(BroadCastConstants.JUMP_THIRD_PHOTO_BROWSER, this.jumpThirdPhotoBrowserFunc);
296      this.broadCast.off(BroadCastConstants.ON_DATA_RELOADED, this.onDataReloadedFunc);
297      this.broadCast.off(BroadCastConstants.THIRD_PICKER_SWITCH_SMART_RECOMMEND_TAB,
298        this.onSwitchSmartRecommendTabFunc);
299      this.broadCast.off(SmartPickerConstants.PICKER_INIT_DATA_FIRST_QUERY_FINISH,
300        this.pickerInitDataFirstQueryFinishFunc);
301      this.broadCast.off(Constants.ON_LOADING_FINISHED, this.funcOnLoadingFinished);
302    }
303    this.dataSource.releaseBroadCast();
304    this.selectManager?.releaseGetMediaItemFunc();
305    this.selectManager?.unregisterCallback('updateCount');
306    Log.info(TAG, `call aboutToDisappear`)
307  }
308
309  onSmartPickerRecommendInfoListReady(pickerRecommendInfoList: SmartPickerRecommendInfo[],
310                                      dataAdapter: SmartPickerDataAdapter): void {
311    let param: SelectParams = router.getParams() as SelectParams;
312    if (pickerRecommendInfoList === undefined || pickerRecommendInfoList === null ||
313      pickerRecommendInfoList.length === 0) {
314      return;
315    }
316    if (this.smartPickerDataImpl === undefined || this.smartPickerDataImpl === null) {
317      this.smartPickerDataImpl = new SmartPickerDataImpl();
318      this.smartPickerDataImpl.setDataAdapter(dataAdapter);
319    }
320    let tabInfo = new SmartPickerRecommendTabInfo();
321    tabInfo.setCameraAble(param ? param.cameraAble : this.selectParams.cameraAble);
322    tabInfo.setAlbumUri('');
323    tabInfo.setLabelId(SmartPickerConstants.LABEL_ALL_PHOTO);
324    this.smartRecommendTabItems.push(tabInfo);
325    pickerRecommendInfoList.forEach((item, index) => {
326      let tabInfo = new SmartPickerRecommendTabInfo();
327      tabInfo.setLabelId(item.getLabelId());
328      tabInfo.setRecommendType(item.getRecommendType());
329      tabInfo.setAlbumUri(item.getAlbumUri());
330      tabInfo.setTotalCount(item.getTotalCount());
331      tabInfo.setRecommendContent(item.getRecommendContent());
332      tabInfo.setCameraAble(false);
333      this.smartRecommendTabItems.push(tabInfo);
334    });
335    this.isShowSmartRecommendTabBar = true;
336    this.onSwitchSmartRecommendTab(this.currentSmartRecommendTabIndex);
337  }
338
339  onMediaLibDataChange(changeType: string): void {
340    Log.info(TAG, `onMediaLibDataChange type: ${changeType}`);
341    this.dataSource.onChange(changeType);
342  }
343
344  getGeometryTransitionId(item: ViewData, index: number): string {
345    let mediaItem = item.mediaItem as MediaItem;
346    if (mediaItem) {
347      return TAG + mediaItem.getHashCode() + (this.selectManager?.isItemSelected(mediaItem.uri as string) ?? false);
348    } else {
349      return TAG + item.viewIndex;
350    }
351  }
352
353  @Builder
354  buildGrid() {
355    Grid(this.scroller) {
356      if (!this.selectParams.isFromFa && this.selectParams.cameraAble) {
357        GridItem() {
358          CameraGridItemComponent({
359            selectParams: this.selectParams,
360            updateDataFunc: (uri: string) => {
361              Log.debug(TAG, `get camera callback, uri ${uri}`)
362              this.dataSource.initData();
363              this.selectFromCameraFunc = () => {
364                this.onSelectCallback(0, uri, true, () => {});
365              }
366            }
367          })
368        }
369        .aspectRatio(1)
370      }
371      LazyForEach(this.dataSource, (item: ViewData, index?: number) => {
372        if (item?.mediaItem) {
373          GridItem() {
374            ImageGridItemComponent({
375              dataSource: this.dataSource,
376              item: item?.mediaItem,
377              isSelected: this.selectManager?.isItemSelected((item.mediaItem as MediaItem).uri as string) ?? false,
378              pageName: Constants.PHOTO_TRANSITION_ALBUM,
379              isThird: true,
380              mPosition: item?.viewIndex,
381              isThirdMultiPick: this.selectParams.isMultiPick,
382              geometryTransitionString: this.getGeometryTransitionId(item, index as number),
383              selectedCount: $selectedCount
384            })
385          }
386          .aspectRatio(1)
387          .zIndex(index === this.placeholderIndex ? 1 : 0)
388        }
389      }, (item: ViewData, index?: number) => {
390        if (item == null || item == undefined) {
391          return JSON.stringify(item) + index;
392        }
393        return this.getGeometryTransitionId(item, index as number);
394      })
395    }
396    .edgeEffect(EdgeEffect.Spring)
397    .scrollBar(BarState.Off)
398    .gridStyle(this.gridRowCount)
399  }
400
401  build() {
402    Column() {
403      ThirdSelectedPageActionBar({
404        leftAction: this.selectParams.isFromFa ? Action.BACK : Action.CANCEL,
405        isSelectPhotoGrid: true,
406        title: $title,
407        selectParams: this.selectParams,
408        onMenuClicked: (action: Action): void => this.onMenuClicked(action),
409        isFirstEnter: this.isFirstEnter,
410        totalSelectedCount: $selectedCount
411      })
412
413      if (this.isEmpty) {
414        if (this.selectParams.isFromFa) {
415          NoPhotoIndexComponent({ index: Constants.TIMELINE_PAGE_INDEX, hasBarSpace: false })
416        } else {
417          if (!this.selectParams.cameraAble) {
418            NoPhotoComponent({ title: $r('app.string.no_distributed_photo_head_title_album') })
419          }
420        }
421      }
422      if (this.isShowSmartRecommendTabBar && this.isAllMediaAlbum) {
423        ThirdSelectSmartRecommendTabBar({
424          smartRecommendTabItems: this.smartRecommendTabItems,
425          currentTabIndex: this.currentSmartRecommendTabIndex
426        })
427      }
428      Stack() {
429        this.buildGrid()
430        if (this.isShowScrollBar) {
431          GridScrollBar({ scroller: this.scroller });
432        }
433      }
434      .layoutWeight(1)
435
436      if (this.selectParams.isMultiPick) {
437        ThirdSelectedPanel({
438          maxSelectCount: this.selectParams.maxSelectCount,
439          onMenuClicked: (action: Action): void => this.onMenuClicked(action),
440          mTransition: TAG,
441          currentUri: this.currentUri,
442          isShowBar: $isShowBar,
443          totalSelectedCount: $selectedCount,
444          dataSource: this.dataSource
445        })
446      }
447    }
448    .backgroundColor($r('sys.color.ohos_id_color_sub_background'))
449    .padding({
450      top: this.leftBlank[1],
451      bottom: this.leftBlank[3]
452    })
453  }
454
455  jumpToBrowserNormal(targetIndex: number, name: string, item: MediaItem, isSelectMode = false): void {
456    interface AniParams {
457      position: number;
458      bundleName: string;
459      transition: string;
460      title: string;
461      selectMode: boolean;
462      maxSelectCount: number;
463      isFromFa: boolean;
464    }
465    let params: AniParams = {
466      position: targetIndex,
467      bundleName: this.selectParams.bundleName,
468      transition: name,
469      title: this.title,
470      selectMode: isSelectMode,
471      maxSelectCount: this.selectParams.maxSelectCount,
472      isFromFa: this.selectParams.isFromFa,
473    };
474
475    router.pushUrl({
476      url: 'pages/ThirdSelectPhotoBrowser',
477      params: params
478    });
479  }
480
481  jumpToBrowserGeometryTransition(targetIndex: number, name: string, item: MediaItem, isSelectMode = false,
482                                  geometryTapIndex: number,
483                                  geometryTransitionString: string): void {
484    interface AniParams {
485      position: number;
486      bundleName: string;
487      transition: string;
488      title: string;
489      selectMode: boolean;
490      maxSelectCount: number;
491      isFromFa: boolean;
492    }
493
494    let params: AniParams = {
495      position: targetIndex,
496      bundleName: this.selectParams.bundleName,
497      transition: name,
498      title: this.title,
499      selectMode: isSelectMode,
500      maxSelectCount: this.selectParams.maxSelectCount,
501      isFromFa: this.selectParams.isFromFa,
502    };
503    this.browserController.showBrowser(geometryTapIndex, geometryTransitionString, TAG, params);
504  }
505
506  private initGridRowCount(): void {
507    let contentWidth = ScreenManager.getInstance().getWinWidth();
508    let margin = 0;
509    let maxThumbWidth = px2vp(Constants.GRID_IMAGE_SIZE) * Constants.GRID_MAX_SIZE_RATIO;
510    let calCount = Math.round(
511      ((contentWidth - Constants.NUMBER_2 * margin) + Constants.GRID_GUTTER) /
512        (maxThumbWidth + Constants.GRID_GUTTER));
513    let newCount = Math.max(Constants.GRID_MIN_COUNT, calCount);
514    if (newCount != this.gridRowCount) {
515      this.gridRowCount = newCount;
516    }
517    Log.info(TAG, `initGridRowCount contentWidth: ${contentWidth}, row count ${this.gridRowCount}`);
518  }
519
520  private initSelectParams(param?: SelectParams): void {
521    if (param) {
522      this.isItemIdChange =
523        (this.itemId !== undefined && this.itemId !== null && this.itemId !== param.itemId) as boolean;
524      this.itemId = param.itemId == undefined ? AlbumDefine.ALBUM_ID_ALL : param.itemId;
525      this.dataSource.setAlbumUri(this.itemId as string);
526
527      let albumUri = param.uri === undefined ?
528      UserFileManagerAccess.getInstance().getSystemAlbumUri(UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE) :
529      param.uri;
530      this.dataSource.setAlbumUri(this.isShowSmartRecommendTabBar ?
531      this.smartRecommendTabItems[this.currentSmartRecommendTabIndex].getAlbumUri() : albumUri);
532      this.updateTitle(param);
533      this.selectParams.bundleName = param.bundleName;
534      this.selectParams.isMultiPick = param.isMultiPick;
535      if (param.isFromFa != undefined || param.isFromFa != null) {
536        this.selectParams.isFromFa = param.isFromFa;
537      }
538      if (param.isFromFaPhoto != undefined || param.isFromFaPhoto != null) {
539        this.selectParams.isFromFaPhoto = param.isFromFaPhoto;
540      }
541      if (param.isFirstEnter != undefined || param.isFirstEnter != null) {
542        this.isFirstEnter = param.isFirstEnter;
543      }
544      if (!!param.filterMediaType) {
545        this.selectParams.filterMediaType = param.filterMediaType;
546      }
547      this.selectParams.isFromWallpaper = param.isFromWallpaper;
548      if (this.selectParams.isFromWallpaper) {
549        this.selectParams.maxSelectCount = param.remainingOfWallpapers;
550      } else if (!!param.maxSelectCount && param.maxSelectCount > 0) {
551        this.selectParams.maxSelectCount = param.maxSelectCount > Constants.LIMIT_MAX_THIRD_SELECT_COUNT
552          ? Constants.LIMIT_MAX_THIRD_SELECT_COUNT
553          : param.maxSelectCount;
554      }
555      if (this.backFuncBinder) {
556        this.backFuncBinder((): void => this.onBackPress());
557      }
558      Log.debug(TAG, `select param ${JSON.stringify(this.selectParams)}`);
559    }
560    this.isSelectedMode = this.selectParams.isMultiPick;
561    Log.debug(TAG, `select param ${JSON.stringify(this.selectParams)}, select mode ${this.isSelectedMode}`);
562  }
563
564  private updateTitle(param?: SelectParams): void {
565    let displayName = param?.itemDisplayName == undefined ? $r('app.string.album_all') : param.itemDisplayName;
566    if (typeof displayName === 'object') {
567      UiUtil.getResourceString(displayName as Resource).then((stringResource: string) => {
568        this.title = stringResource;
569      })
570    } else {
571      this.title = displayName as string;
572    }
573    Log.debug(TAG, `update title ${this.title}`);
574  }
575
576  private onSelectCallback(position: number, key: string, value: boolean, callback: Function): void{
577    Log.debug(TAG, `isHorizontal ${this.isHorizontal}, position ${position}, uri ${key}, select ${value}`)
578    let isMultiPick = this.selectParams.isMultiPick;
579    if (value && isMultiPick && this.selectedCount >= this.selectParams.maxSelectCount) {
580      if (!this.isHorizontal) {
581        UiUtil.showToast($r('app.string.up_to_limit_tips'));
582      }
583      return;
584    }
585    if (this.isShowSmartRecommendTabBar && this.isAllMediaAlbum && value) {
586      if (this.smartRecommendTabItems[this.currentSmartRecommendTabIndex].getUserPickUriList().indexOf(key) === -1) {
587        this.smartRecommendTabItems[this.currentSmartRecommendTabIndex].getUserPickUriList().push(key);
588      }
589    }
590    if (!isMultiPick) {
591      // update correct status from select manager
592      value = !this.selectManager?.isItemSelected(key);
593      this.selectManager?.deSelectAll();
594    }
595    if (this.selectManager?.toggle(key, value, position)) {
596      Log.info(TAG, 'enter event process');
597      this.dataSource.onDataChanged(this.dataSource.getDataIndexByUri(key));
598      callback && callback(value);
599    }
600  }
601
602  private jumpBrowserCallback(name: string, item: MediaItem, geometryTapIndex: number ,
603                              geometryTransitionString: string, isSelectMode = false) {
604    let selectItemIndex: number = this.selectManager?.getSelectItemIndex(item) ?? Constants.INVALID;
605    let targetIndex = isSelectMode ? selectItemIndex : this.dataSource.getDataIndex(item);
606    Log.info(TAG, `jump to photo browser at index: ${targetIndex}, transition: ${name}`);
607    AppStorage.setOrCreate(Constants.APP_KEY_PHOTO_BROWSER, this.dataSource);
608    if (geometryTapIndex != -1 && geometryTransitionString != '') {
609      this.jumpToBrowserGeometryTransition(
610        targetIndex, name, item, isSelectMode, geometryTapIndex, geometryTransitionString);
611    } else {
612      this.jumpToBrowserNormal(targetIndex, name, item, isSelectMode);
613    }
614    ReportToBigDataUtil.report(BigDataConstants.SELECT_PICKER_CLICK_PREVIEW, undefined);
615  }
616
617  private onReloadFinishedCallback(): void {
618    Log.info(TAG, 'ON_DATA_RELOADED');
619    this.dataSource.onDataReloaded();
620    this.selectFromCameraFunc && this.selectFromCameraFunc();
621    this.selectFromCameraFunc = () => {};
622  }
623
624  private pickerInitDataFirstQueryFinish(): void {
625    if (this.isShowSmartRecommendTabBar) {
626      this.selectParams.cameraAble =
627        this.smartRecommendTabItems[this.isAllMediaAlbum ? this.currentSmartRecommendTabIndex : 0].isCameraAble();
628    }
629  }
630
631  private onLoadingFinished(size: number): void {
632    this.onLoadFinishedCallback(size, (param: SelectParams): void => this.updateTitle(param));
633  }
634
635  private onLoadFinishedCallback(size: number, updateTitle: Function) {
636    Log.info(TAG, `ON_LOADING_FINISHED size: ${size}`);
637    this.isEmpty = size == 0;
638    if (this.isEmpty && updateTitle) {
639      updateTitle();
640    }
641    Log.info(TAG, `isEmpty: ${this.isEmpty}`)
642    this.dataSource.onDataReloaded();
643    this.modifyPhotoSelectStatus();
644  }
645
646  /**
647   * 图库预选择
648   */
649  private modifyPhotoSelectStatus(): void {
650    if (this.selectParams.preselectedUris.length > 0) {
651      if (this.selectParams.preselectedUris.length > this.selectParams.maxSelectCount) {
652        this.selectParams.preselectedUris =
653          this.selectParams.preselectedUris.slice(0, this.selectParams.maxSelectCount);
654      }
655      this.selectManager?.initPreSelectPhotos(this.selectParams.preselectedUris);
656      this.selectParams.preselectedUris = [];
657    }
658  }
659
660  private initSelectManager() {
661    let manager: ThirdSelectManager =
662      AppStorage.get<ThirdSelectManager>(Constants.THIRD_SELECT_MANAGER) as ThirdSelectManager;
663    if (manager && manager.getClassName() === 'ThirdSelectManager') {
664      Log.debug(TAG, `use cached select manager, current select count ${manager.getSelectedCount()}`);
665      this.selectManager = manager;
666    } else {
667      Log.debug(TAG, 'create new select manager');
668      this.selectManager = new ThirdSelectManager();
669      AppStorage.setOrCreate(Constants.THIRD_SELECT_MANAGER, this.selectManager);
670    }
671    if (this.isFirstEnter) {
672      Log.debug(TAG, 'clear select manager');
673      this.selectManager.deSelectAll();
674      AppStorage.setOrCreate(THIRD_SELECT_IS_ORIGIN, false);
675    }
676    this.selectManager.setGetMediaItemFunc((uri: string): MediaItem => {
677      return this.dataSource.getMediaItemByUri(uri);
678    });
679  }
680
681  private onActive() {
682    if (this.isItemIdChange) {
683      this.isActive = false;
684      this.dataSource && this.dataSource.initData();
685    }
686
687    if (!this.isActive) {
688      Log.info(TAG, 'onActive');
689      this.isActive = true;
690      this.dataSource && this.dataSource.onActive();
691      if (this.selectParams.isMultiPick) {
692        this.dataSource.forceUpdate();
693      }
694    }
695  }
696
697  private onInActive() {
698    if (this.isActive) {
699      Log.info(TAG, 'onInActive');
700      this.isActive = false;
701      this.dataSource && this.dataSource.onInActive();
702    }
703  }
704
705  private setPickResult(uriArray?: Array<string>): void {
706    let isOrigin: boolean = AppStorage.get<boolean>(THIRD_SELECT_IS_ORIGIN) as boolean;
707    if (isOrigin == undefined) {
708      isOrigin = false;
709    }
710    let abilityResult: ability.AbilityResult = {
711      resultCode: (uriArray === null || uriArray === undefined) ? -1 : 0,
712      want: {
713        parameters: {
714          'select-item-list': uriArray as Object,
715          isOriginal: isOrigin
716        }
717      }
718    };
719    let self = this;
720    let uriLength = 0;
721    if (uriArray == null && uriArray == undefined) {
722      if (localStorage?.has(Constants.PHOTO_PICKER_SESSION_KEY)) {
723        let session = localStorage?.get<UIExtensionContentSession>(Constants.PHOTO_PICKER_SESSION_KEY);
724        session?.terminateSelfWithResult(abilityResult as ability.AbilityResult).then((result: void) => {
725          Log.debug(TAG, `session terminateSelfWithResult result: ${result}, self result ${JSON.stringify(abilityResult)}`);
726        });
727      } else {
728        let context: common.UIAbilityContext = AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext;
729        context.terminateSelfWithResult(abilityResult as ability.AbilityResult).then((result: void) => {
730          Log.debug(TAG, `terminateSelfWithResult result: ${result}, self result ${JSON.stringify(abilityResult)}`);
731        });
732      }
733    } else {
734      uriLength = uriArray.length;
735      if (localStorage?.has(Constants.PHOTO_PICKER_SESSION_KEY)) {
736        let session = localStorage?.get<UIExtensionContentSession>(Constants.PHOTO_PICKER_SESSION_KEY);
737        let param = localStorage?.get<SelectParams>(Constants.PHOTO_PICKER_PARAMS_KEY);
738        if (param?.bundleName) {
739          SelectUtil.grantPermissionForUris(uriArray, param.bundleName).then(() => {
740            Log.info(TAG, `session grant permission success.`);
741            let context: common.UIAbilityContext = AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext;
742            session?.terminateSelfWithResult(abilityResult as ability.AbilityResult).then((result: void) => {
743              Log.debug(TAG, `session terminateSelfWithResult result: ${result}, self result ${JSON.stringify(abilityResult)}`);
744            });
745          }).catch((err: Error) => {
746            Log.error(TAG, `session grant permission error: ${JSON.stringify(err)}, self result ${JSON.stringify(abilityResult)}`);
747            session?.terminateSelfWithResult(abilityResult as ability.AbilityResult).then((result: void) => {
748              Log.debug(TAG, `session terminateSelfWithResult result: ${result}, self result ${JSON.stringify(abilityResult)}`);
749            });
750          });
751        }
752      } else {
753        SelectUtil.grantPermissionForUris(uriArray, self.selectParams.bundleName).then(() => {
754          Log.info(TAG, `grant permission success.`);
755          let context: common.UIAbilityContext = AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext;
756          context.terminateSelfWithResult(abilityResult as ability.AbilityResult).then((result: void) => {
757            Log.debug(TAG, `terminateSelfWithResult result: ${result}, self result ${JSON.stringify(abilityResult)}`);
758          });
759        }).catch((err: Error) => {
760          Log.error(TAG, `grant permission error: ${JSON.stringify(err)}, self result ${JSON.stringify(abilityResult)}`);
761        });
762      }
763    }
764    interface Msg {
765      isOriginalChecked: boolean;
766      selectItemSize: number;
767    }
768    let msg: Msg = {
769      isOriginalChecked: isOrigin,
770      selectItemSize: uriLength,
771    }
772    ReportToBigDataUtil.report(BigDataConstants.SELECT_PICKER_RESULT, msg);
773  }
774
775  private goBackFormEditor(): void {
776    let formEditorOption: router.RouterOptions = {
777      url: 'pages/FormEditorPage'
778    };
779    router.replaceUrl(formEditorOption);
780  }
781}
782
783@Extend(Grid) 
784function gridStyle(gridCount: number) {
785  .columnsTemplate('1fr '.repeat(gridCount))
786  .columnsGap(Constants.GRID_GUTTER)
787  .rowsGap(Constants.GRID_GUTTER)
788  .cachedCount(Constants.GRID_CACHE_ROW_COUNT)
789  .layoutWeight(1)
790}
791