• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 prompt from '@system.prompt';
18import Curves from '@ohos.curves';
19import { MenuOperation } from '@ohos/common';
20import {
21  Action,
22  AddMenuOperation,
23  AlbumDefine,
24  AlbumInfo,
25  BatchDeleteMenuOperation,
26  BatchRemoveMenuOperation,
27  BroadCast,
28  BroadCastConstants,
29  BroadCastManager,
30  BrowserConstants,
31  CommonObserverCallback,
32  Constants,
33  DeleteMenuOperation,
34  ImageUtil,
35  JumpSourceToMain,
36  Log,
37  MediaDataSource,
38  MediaItem,
39  MediaObserver,
40  MediaOperationType,
41  MenuContext,
42  MenuOperationFactory,
43  MoveMenuOperation,
44  RemoveMenuOperation,
45  ScreenManager,
46  SelectManager,
47  ShareMenuOperation,
48  TraceControllerUtils,
49  UiUtil,
50  UserFileManagerAccess,
51  ViewData
52} from '@ohos/common';
53import {
54  BrowserController,
55  CustomDialogView,
56  GridScrollBar,
57  ImageGridItemComponent,
58  NoPhotoComponent
59} from '@ohos/common/CommonComponents';
60import { RecoverMenuOperation } from '@ohos/browser';
61import {
62  BatchRecoverMenuOperation,
63  ClearRecycleMenuOperation,
64  PhotoGridPageActionBar,
65  PhotoGridPageToolBar
66} from '@ohos/browser/BrowserComponents';
67
68
69const TAG: string = 'PhotoGridView';
70AppStorage.SetOrCreate('PhotoGridPageIndex', Constants.INVALID);
71
72// Album View
73@Component
74export struct PhotoGridView {
75  @State isShowScrollBar: boolean = false;
76  @Provide isEmpty: boolean = false;
77  @State gridRowCount: number = 0;
78  @Consume @Watch('updateRightClickMenuList') isSelectedMode: boolean;
79  @Provide isAllSelected: boolean = false;
80  @State totalSelectedCount: number = 0;
81  @StorageLink('isHorizontal') isHorizontal: boolean = ScreenManager.getInstance().isHorizontal();
82  @Provide broadCast: BroadCast = new BroadCast();
83  @Consume isShow: boolean;
84  @Provide isShowBar: boolean = true;
85  @Provide moreMenuList: Array<Action> = new Array<Action>();
86  @Provide rightClickMenuList: Array<Action> = new Array<Action>();
87  @StorageLink('PhotoGridPageIndex') @Watch('onIndexChange') PhotoGridPageIndex: number = Constants.INVALID;
88  @StorageLink('isSplitMode') isSplitMode: boolean = ScreenManager.getInstance().isSplitMode();
89  @StorageLink('leftBlank') leftBlank: number[]
90    = [0, ScreenManager.getInstance().getStatusBarHeight(), 0, ScreenManager.getInstance().getNaviBarHeight()];
91  @Prop @Watch('onPageChanged') pageStatus: boolean = false;
92  @State gridItemWidth: number = 0;
93  @StorageLink('photoGridActionBarOpacity') photoGridActionBarOpacity: number = 0;
94  @StorageLink('photoGridViewOpacity') photoGridViewOpacity: number = 0;
95  albumInfo: AlbumInfo = new AlbumInfo();
96  title: string = '';
97  deviceName: string = '';
98  dataSource: MediaDataSource = new MediaDataSource(Constants.DEFAULT_SLIDING_WIN_SIZE);
99  scroller: Scroller = new Scroller();
100  isDataFreeze = false;
101  mSelectManager = new SelectManager();
102  isActive = false;
103  isDistributedAlbum = false;
104  deleteMode: boolean = false;
105  routerStart = false;
106  isFromFACard = false;
107  @StorageLink('placeholderIndex') @Watch('onPlaceholderChanged') placeholderIndex: number = -1;
108  @Provide hidePopup: boolean = false;
109  @ObjectLink browserController: BrowserController;
110  private dataObserver: CommonObserverCallback = new CommonObserverCallback(this);
111  private appBroadCast: BroadCast = BroadCastManager.getInstance().getBroadCast();
112  // 选择模式下,鼠标对着未勾选项按右键弹框时,移动和复制菜单点击事件的标识位
113  private isMvOrCpSeparatesItem: boolean = false;
114  private mvOrCpSeparatesItem: MediaItem = new MediaItem();
115  private photoTotalCount: number = 0;
116  private params: Params | null = null;
117  private scrollIndex: number = 0;
118  private onWindowSizeChangeCallBack: Function = () => {
119    // 后续phone缩略图支持横竖屏后再放开
120    // this.initGridRowCount;
121  }
122  private selectFunc: Function = (position: number, key: string, value: boolean, callback: Function): void => this.select(position, key, value, callback);
123  private jumpPhotoBrowserFunc: Function = (name: string, item: MediaItem, geometryTapIndex: number, geometryTransitionString: string): void =>
124  this.jumpPhotoBrowser(name, item, geometryTapIndex, geometryTransitionString);
125  private jumpThirdPhotoBrowserFunc: Function = (name: string, item: MediaItem, geometryTapIndex: number, geometryTransitionString: string): void =>
126  this.jumpThirdPhotoBrowser(name, item, geometryTapIndex, geometryTransitionString);
127  private onLoadingFinishedFunc: Function = (size: number): void => this.onLoadingFinished(size);
128  private onDataReloadedFunc: Function = (): void => this.onDataReloaded();
129  private onUpdateFavorStateFunc: Function = (item: MediaItem): void => this.onUpdateFavorState(item);
130
131  onPlaceholderChanged() {
132    Log.debug(TAG, 'onPlaceholderChanged placeholderIndex is ' + this.placeholderIndex);
133    if (this.placeholderIndex != -1) {
134      this.scroller.scrollToIndex(this.placeholderIndex);
135    }
136  }
137
138  initParams(): void {
139    this.isSelectedMode = false;
140    this.isShow = true;
141  }
142
143  onIndexChange(): void {
144    Log.info(TAG, `onIndexChange ${this.PhotoGridPageIndex}`)
145    if (this.PhotoGridPageIndex != Constants.INVALID) {
146      this.scroller.scrollToIndex(this.PhotoGridPageIndex);
147    }
148  }
149
150  doAnimation(): void {
151    animateTo({
152      duration: BrowserConstants.PHONE_LINK_ALBUM_ACTIONBAR_DURATION,
153      delay: BrowserConstants.PHONE_LINK_ALBUM_ACTIONBAR_DELAY,
154      curve: Curve.Sharp
155    }, () => {
156      AppStorage.SetOrCreate<number>(Constants.KEY_OF_ALBUM_ACTIONBAR_OPACITY, 1);
157    })
158    animateTo({
159      duration: BrowserConstants.PHONE_LINK_OUT_PHOTO_GRID_ACTIONBAR_DURATION,
160      curve: Curve.Sharp
161    }, () => {
162      AppStorage.SetOrCreate<number>(Constants.KEY_OF_PHOTO_GRID_ACTIONBAR_OPACITY, 0);
163      AppStorage.SetOrCreate<number>(Constants.KEY_OF_PHOTO_GRID_VIEW_OPACITY, 0);
164      AppStorage.SetOrCreate<number>(Constants.KEY_OF_ALBUM_OPACITY, 1);
165    })
166    animateTo({
167      duration: BrowserConstants.PHONE_LINK_PHOTO_GRID_TO_ALBUM_DURATION,
168      curve: Curve.Friction
169    }, () => {
170      AppStorage.SetOrCreate<number>(Constants.KEY_OF_SELECTED_ALBUM_INDEX, -1);
171      AppStorage.SetOrCreate<boolean>(Constants.KEY_OF_IS_SHOW_PHOTO_GRID_VIEW, false);
172      AppStorage.SetOrCreate<string>(Constants.KEY_OF_SELECTED_ALBUM_URI, '');
173    })
174    animateTo({
175      duration: BrowserConstants.PHONE_LINK_PHOTO_GRID_TO_ALBUM_SCALE_DURATION,
176      curve: Curve.Friction
177    }, () => {
178      AppStorage.SetOrCreate<number>(Constants.KEY_OF_ALBUM_OTHER_SCALE, 1);
179    })
180  }
181
182  onMenuClicked(action: Action): void {
183    Log.info(TAG, `onMenuClicked, action: ${action.actionID}`);
184    let menuContext: MenuContext;
185    let menuOperation: MenuOperation;
186    if (action.actionID === Action.BACK.actionID) {
187      if (this.isFromFACard) {
188        router.replaceUrl({
189          url: 'pages/index',
190          params: {
191            jumpSource: JumpSourceToMain.ALBUM,
192          }
193        });
194      } else {
195        if (router.getState().name === Constants.USER_FILE_MANAGER_PHOTO_TRANSITION_ALBUM) {
196          router.back();
197        } else {
198          this.doAnimation();
199        }
200      }
201    } else if (action.actionID === Action.CANCEL.actionID) {
202      this.onModeChange();
203    } else if (action.actionID === Action.MULTISELECT.actionID) {
204      this.isSelectedMode = true;
205    } else if (action.actionID === Action.SELECT_ALL.actionID) {
206      this.mSelectManager.selectAll(true);
207    } else if (action.actionID === Action.DESELECT_ALL.actionID) {
208      this.mSelectManager.deSelectAll();
209    } else if (action.actionID === Action.DELETE.actionID) {
210      menuContext = new MenuContext();
211      menuContext
212        .withSelectManager(this.mSelectManager)
213        .withOperationStartCallback((): void => this.onDeleteStart())
214        .withOperationEndCallback((): void => this.onDeleteEnd())
215        .withBroadCast(this.broadCast)
216        .withAlbumUri(this.albumInfo.uri)
217        .withFromSelectMode(this.isSelectedMode)
218        .withAlbumInfo(this.albumInfo)
219      menuOperation = MenuOperationFactory.getInstance()
220        .createMenuOperation(BatchDeleteMenuOperation, menuContext);
221      menuOperation.doAction();
222    } else if (action.actionID === Action.SHARE.actionID) {
223      menuContext = new MenuContext();
224      menuContext.withFromSelectMode(true).withSelectManager(this.mSelectManager);
225      menuOperation = MenuOperationFactory.getInstance()
226        .createMenuOperation(ShareMenuOperation, menuContext);
227      menuOperation.doAction();
228    } else if (action.actionID === Action.INFO.actionID) {
229      this.hidePopup = true;
230      this.openDetailsDialog();
231    } else if (action.actionID === Action.CLEAR_RECYCLE.actionID) {
232      menuContext = new MenuContext();
233      menuContext
234        .withSelectManager(this.mSelectManager)
235        .withOperationStartCallback((): void => this.onDeleteStart())
236        .withOperationEndCallback((): void => this.onDeleteEnd())
237        .withBroadCast(this.broadCast)
238        .withAlbumUri(UserFileManagerAccess.getInstance()
239          .getSystemAlbumUri(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE))
240        .withAlbumInfo(this.albumInfo)
241      menuOperation = MenuOperationFactory.getInstance()
242        .createMenuOperation(ClearRecycleMenuOperation, menuContext);
243      menuOperation.doAction();
244    } else if (action.actionID === Action.RECOVER.actionID) {
245      menuContext = new MenuContext();
246      menuContext
247        .withAlbumUri(UserFileManagerAccess.getInstance()
248          .getSystemAlbumUri(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE))
249        .withSelectManager(this.mSelectManager)
250        .withOperationStartCallback((): void => this.onDeleteStart())
251        .withOperationEndCallback((): void => this.onDeleteEnd())
252        .withBroadCast(this.broadCast)
253        .withAlbumInfo(this.albumInfo)
254      menuOperation = MenuOperationFactory.getInstance()
255        .createMenuOperation(BatchRecoverMenuOperation, menuContext);
256      menuOperation.doAction();
257    } else if (action.actionID === Action.MOVE.actionID) {
258      this.mSelectManager.getSelectedItems((selectedItems: Array<MediaItem>) => {
259        Log.info(TAG, `Get selected items success, size: ${selectedItems.length}, start route to select album page`);
260        this.routeToSelectAlbumPage(MediaOperationType.Move, selectedItems);
261      })
262    } else if (action.actionID === Action.ADD.actionID) {
263      this.mSelectManager.getSelectedItems((selectedItems: Array<MediaItem>) => {
264        Log.info(TAG, `Get selected items success, size: ${selectedItems.length}, start route to select album page`);
265        this.routeToSelectAlbumPage(MediaOperationType.Add, selectedItems);
266      })
267    } else if (action.actionID === Action.REMOVE_FROM.actionID) {
268      menuContext = new MenuContext();
269      menuContext
270        .withSelectManager(this.mSelectManager)
271        .withOperationStartCallback((): void => this.onRemoveStart())
272        .withOperationEndCallback((): void => this.onRemoveEnd())
273        .withBroadCast(this.broadCast)
274        .withAlbumUri(this.albumInfo.uri)
275        .withFromSelectMode(this.isSelectedMode)
276      menuOperation = MenuOperationFactory.getInstance()
277        .createMenuOperation(BatchRemoveMenuOperation, menuContext);
278      menuOperation.doAction();
279    } else if (action.actionID === Action.NEW.actionID) {
280      this.routeToAddMediaPage();
281    } else if (action.actionID === Action.DOWNLOAD.actionID) {
282      menuContext = new MenuContext();
283      menuContext
284        .withSelectManager(this.mSelectManager)
285        .withOperationStartCallback((): void => this.onDownloadStart())
286        .withOperationEndCallback(async (err: Error, count: number, total: number): Promise<void> => this.onDownloadEnd(err as Object, count, total))
287        .withBroadCast(this.broadCast)
288      menuOperation = MenuOperationFactory.getInstance().createMenuOperation(AddMenuOperation, menuContext);
289      menuOperation.doAction();
290    }
291  }
292
293  async openDetailsDialog(): Promise<void> {
294    if (this.totalSelectedCount == 0) {
295      Log.error(TAG, 'no select error');
296      return;
297    } else if (this.totalSelectedCount == 1) {
298      Log.info(TAG, 'totalSelectedCount is 1');
299      await this.mSelectManager.getSelectedItems((selectItems: MediaItem[]) => {
300        if (selectItems.length != 1) {
301          Log.error(TAG, 'get selectItems is error');
302          return;
303        }
304        this.broadCast.emit(BroadCastConstants.SHOW_DETAIL_DIALOG, [selectItems[0], this.isDistributedAlbum]);
305      });
306    } else {
307      await this.mSelectManager.getSelectedItems((selectItems: MediaItem[]) => {
308        if (selectItems.length <= 1) {
309          Log.error(TAG, 'get selectItems is error');
310          return;
311        }
312        let size = 0;
313        selectItems.forEach((item) => {
314          size = size + item.size;
315        })
316
317        Log.info(TAG, `openDetailsDialog size: ${size}`);
318        this.broadCast.emit(BroadCastConstants.SHOW_MULTI_SELECT_DIALOG, [this.totalSelectedCount, size]);
319      });
320      return;
321    }
322  }
323
324  routeToSelectAlbumPage(pageType: string, selectedItems: Array<MediaItem>): void {
325    this.routerStart = true;
326    router.pushUrl({
327      url: 'pages/MediaOperationPage',
328      params: {
329        pageFrom: Constants.MEDIA_OPERATION_FROM_PHOTO_GRID,
330        pageType: pageType,
331        albumInfo: this.albumInfo,
332        selectedItems: selectedItems
333      }
334    });
335  }
336
337  routeToAddMediaPage(): void {
338    router.pushUrl({
339      url: 'pages/AlbumSelect',
340      params: {
341        albumName: this.albumInfo.albumName,
342        albumUri: this.albumInfo.uri
343      }
344    });
345  }
346
347  onCopyStart(): void {
348    Log.info(TAG, `onCopyStart`);
349    this.isDataFreeze = true;
350    MediaObserver.getInstance().unregisterObserver(this.dataObserver);
351    this.dataSource.freeze();
352  }
353
354  onCopyEnd(err: Object, count: number, total: number): void {
355    Log.info(TAG, `onCopyEnd count: ${count}, total: ${total}`);
356    this.isDataFreeze = false;
357    this.onModeChange();
358    MediaObserver.getInstance().registerObserver(this.dataObserver);
359    this.dataSource.onChange('image');
360    this.dataSource.unfreeze();
361    if (err) {
362      UiUtil.showToast($r('app.string.copy_failed_single'));
363    }
364  }
365
366  onDownloadStart(): void {
367    Log.info(TAG, `onDownloadStart`);
368    this.isDataFreeze = true;
369    MediaObserver.getInstance().unregisterObserver(this.dataObserver);
370    this.dataSource.freeze();
371  }
372
373  async onDownloadEnd(err: Object, count: number, total: number): Promise<void> {
374    Log.info(TAG, `onDownloadEnd count: ${count}, total: ${total}`);
375    this.isDataFreeze = false;
376    this.onModeChange();
377    MediaObserver.getInstance().registerObserver(this.dataObserver);
378    this.dataSource.onChange('image');
379    this.dataSource.unfreeze();
380    if (err) {
381      if (total > 1) {
382        Log.error(TAG, `get selectItems is error ${count}`);
383        let str = await UiUtil.getResourceString($r('app.string.download_failed_multi'));
384        let message = str.replace('%d', count.toString());
385        prompt.showToast({
386          message: message,
387          duration: UiUtil.TOAST_DURATION,
388          bottom: '200vp'
389        });
390      } else {
391        UiUtil.showToast($r('app.string.download_failed_single'))
392      }
393    } else {
394      UiUtil.showToast($r('app.string.download_progress_done'));
395    }
396  }
397
398  onMoveStart(): void {
399    Log.info(TAG, `onMoveStart`);
400    this.isDataFreeze = true;
401    MediaObserver.getInstance().unregisterObserver(this.dataObserver);
402    this.dataSource.freeze();
403  }
404
405  onMoveEnd(err: Object, count: number, total: number): void {
406    Log.info(TAG, `onMoveEnd count: ${count}, total: ${total}`);
407    this.isDataFreeze = false;
408    this.onModeChange();
409    MediaObserver.getInstance().registerObserver(this.dataObserver);
410    this.dataSource.switchRefreshOn();
411    this.dataSource.onChange('image');
412    this.dataSource.unfreeze();
413    if (err) {
414      UiUtil.showToast($r('app.string.move_failed_single'));
415    }
416  }
417
418  onDeleteStart(): void {
419    Log.info(TAG, `onDeleteStart`);
420    this.deleteMode = true;
421    this.isDataFreeze = true;
422    this.onModeChange();
423    MediaObserver.getInstance().unregisterObserver(this.dataObserver);
424    this.dataSource.freeze();
425    MediaObserver.getInstance().freezeNotify();
426  }
427
428  onDeleteEnd(): void {
429    Log.info(TAG, `onDeleteEnd`);
430    this.isDataFreeze = false;
431    MediaObserver.getInstance().unfreezeNotify();
432    MediaObserver.getInstance().forceNotify();
433    MediaObserver.getInstance().registerObserver(this.dataObserver);
434    this.dataSource.onChange('image');
435    this.dataSource.unfreeze();
436  }
437
438  onRemoveStart(): void {
439    Log.info(TAG, `onRemoveStart`);
440    this.deleteMode = true;
441    this.isDataFreeze = true;
442    MediaObserver.getInstance().unregisterObserver(this.dataObserver);
443    this.dataSource.freeze();
444  }
445
446  onRemoveEnd(): void {
447    Log.info(TAG, `onRemoveEnd`);
448    this.isDataFreeze = false;
449    this.onModeChange();
450    MediaObserver.getInstance().registerObserver(this.dataObserver);
451    this.dataSource.onChange('image');
452    this.dataSource.unfreeze();
453  }
454
455  onModeChange(): void {
456    Log.info(TAG, 'onModeChange');
457    this.isSelectedMode = false;
458    this.isAllSelected = false;
459    this.mSelectManager.onModeChange(false);
460    AppStorage.delete(Constants.PHOTO_GRID_SELECT_MANAGER);
461  }
462
463  onPageChanged(): void {
464    this.params = router.getParams() as Params;
465    if (this.pageStatus) {
466      this.onPageShow();
467    } else {
468      this.onPageHide();
469    }
470  }
471
472  onPageShow(): void {
473    this.appBroadCast.emit(BroadCastConstants.THIRD_ROUTE_PAGE, []);
474    this.isShow = true;
475    if (this.routerStart && this.params != null && this.params.pageType != null) {
476      Log.info(TAG, 'MediaOperation back');
477      if (this.params.pageType === MediaOperationType.Move) {
478        this.moveOperation(this.params.albumName, this.params.albumUri);
479      } else if (this.params.pageType === MediaOperationType.Add) {
480        this.addOperation(this.params.albumName, this.params.albumUri);
481      }
482    }
483    MediaObserver.getInstance().registerObserver(this.dataObserver);
484    this.isMvOrCpSeparatesItem = false;
485    this.mvOrCpSeparatesItem = new MediaItem();
486    this.routerStart = false;
487    this.onActive();
488  }
489
490  onPageHide(): void {
491    this.isShow = false;
492    this.onInActive();
493  }
494
495  onActive(): void {
496    if (!this.isActive) {
497      Log.info(TAG, 'onActive');
498      this.isActive = true;
499      this.dataSource && this.dataSource.onActive();
500      if (this.isSelectedMode) {
501        this.totalSelectedCount = this.mSelectManager.getSelectedCount();
502        this.dataSource.forceUpdate();
503      }
504    }
505  }
506
507  onInActive(): void {
508    if (this.isActive) {
509      Log.info(TAG, 'onInActive');
510      this.isActive = false;
511    }
512  }
513
514  updateRightClickMenuList(): void {
515    if (!this.isSelectedMode) {
516      this.onModeChange();
517    }
518    this.rightClickMenuList = new Array<Action>();
519    if (this.albumInfo) {
520      let isRecycleAlbum: boolean = this.albumInfo.isTrashAlbum;
521      if (isRecycleAlbum) {
522        this.rightClickMenuList = [Action.RECOVER, Action.DELETE,
523          this.isSelectedMode ? Action.MULTISELECT_INVALID : Action.MULTISELECT];
524      } else {
525        if (!this.isSelectedMode) {
526          this.rightClickMenuList.push(Action.MULTISELECT)
527        }
528        this.rightClickMenuList.push(Action.DELETE);
529        if (!this.albumInfo.isSystemAlbum) {
530          this.rightClickMenuList.push(Action.MOVE);
531          this.rightClickMenuList.push(Action.REMOVE_FROM);
532        }
533        this.rightClickMenuList.push(Action.ADD, Action.INFO);
534      }
535    }
536  }
537
538  aboutToAppear(): void {
539    Log.debug(TAG, `aboutToAppear`);
540    TraceControllerUtils.startTrace('PhotoGridPageAboutToAppear');
541    this.initParams();
542    if (router.getState().name === Constants.USER_FILE_MANAGER_PHOTO_TRANSITION_ALBUM) {
543      this.photoGridActionBarOpacity = 1;
544      this.photoGridViewOpacity = 1;
545    }
546    let param: ParamAlbumInfo;
547    param = router.getParams() as ParamAlbumInfo;
548    if (!param || (param && !param.item)) {
549      param = AppStorage.get<ParamAlbumInfo>(Constants.KEY_OF_PHOTO_GRID_VIEW_ALBUM_ITEM) as ParamAlbumInfo;
550    }
551    if (param != null) {
552      if (param.isFromFACard) {
553        this.isFromFACard = param.isFromFACard;
554      }
555      this.albumInfo = JSON.parse(param.item);
556      this.title = this.albumInfo.albumName;
557      this.dataSource.setAlbumUri(this.albumInfo.uri);
558      if (this.albumInfo.mediaItem) {
559        let mediaItem = this.albumInfo.mediaItem;
560        this.dataSource.items = [mediaItem];
561        this.dataSource.size = 1;
562        this.dataSource.dataIndexes = [0];
563        this.photoTotalCount = this.albumInfo.count;
564      }
565    }
566
567    let self = this;
568    this.dataSource.setBroadCast(this.broadCast)
569    this.mSelectManager.setPhotoDataImpl();
570    this.mSelectManager.setAlbumUri(this.albumInfo.uri);
571    MediaObserver.getInstance().registerObserver(this.dataObserver);
572
573    this.broadCast.on(BroadCastConstants.SELECT, this.selectFunc);
574    this.broadCast.on(BroadCastConstants.JUMP_PHOTO_BROWSER, this.jumpPhotoBrowserFunc);
575    this.broadCast.on(BroadCastConstants.JUMP_THIRD_PHOTO_BROWSER, this.jumpThirdPhotoBrowserFunc);
576    this.broadCast.on(Constants.ON_LOADING_FINISHED, this.onLoadingFinishedFunc);
577    this.appBroadCast.on(BroadCastConstants.UPDATE_DATA_SOURCE, this.onUpdateFavorStateFunc);
578    this.appBroadCast.on(BroadCastConstants.DO_ANIMATION, (): void => {
579      this.doAnimation();
580      this.appBroadCast.off(BroadCastConstants.DO_ANIMATION, null);
581    });
582
583    AppStorage.SetOrCreate(Constants.PHOTO_GRID_SELECT_MANAGER, this.mSelectManager);
584    this.mSelectManager.registerCallback('allSelect', (newState: boolean) => {
585      Log.info(TAG, `allSelect ${newState}`);
586      if (this.isDataFreeze) {
587        return;
588      }
589      this.isAllSelected = newState;
590      this.dataSource.forceUpdate();
591    });
592    this.mSelectManager.registerCallback('updateCount', (newState: number) => {
593      Log.info(TAG, `updateSelectedCount ${newState}`);
594      if (this.isDataFreeze) {
595        return;
596      }
597      this.moreMenuList = Boolean(newState) ? (this.albumInfo.isSystemAlbum ? [Action.ADD, Action.INFO] : [Action.MOVE, Action.ADD, Action.REMOVE_FROM, Action.INFO])
598        : (this.albumInfo.isSystemAlbum ? [Action.ADD_INVALID, Action.INFO_INVALID] : [Action.MOVE_INVALID, Action.ADD_INVALID, Action.REMOVE_FROM_INVALID, Action.INFO_INVALID]);
599      this.totalSelectedCount = newState;
600    });
601    this.mSelectManager.registerCallback('select', (newState: number) => {
602      Log.info(TAG, `select ${newState}`);
603      if (this.isDataFreeze) {
604        return;
605      }
606      this.dataSource.onDataChanged(newState);
607    });
608    this.dataSource.registerCallback('updateCount', (newState: number) => {
609      Log.info(TAG, `updateTotalCount ${newState}`);
610      self.isShowScrollBar = (newState > Constants.PHOTOS_CNT_FOR_HIDE_SCROLL_BAR);
611      self.isEmpty = !Boolean(newState)
612      self.mSelectManager.setTotalCount(newState);
613    });
614
615    this.broadCast.on(BroadCastConstants.ON_DATA_RELOADED, this.onDataReloadedFunc);
616
617    ScreenManager.getInstance().on(ScreenManager.ON_WIN_SIZE_CHANGED, this.onWindowSizeChangeCallBack);
618
619    this.initGridRowCount();
620    this.moreMenuList = this.albumInfo.isSystemAlbum ? [Action.ADD, Action.INFO] : [Action.MOVE, Action.ADD, Action.REMOVE_FROM, Action.INFO];
621    this.updateRightClickMenuList();
622    TraceControllerUtils.finishTrace('PhotoGridPageAboutToAppear');
623  }
624
625  private select(position: number, key: string, value: boolean, callback: Function): void {
626    if (this.mSelectManager.toggle(key, value, position)) {
627      Log.info(TAG, 'enter event process')
628      if (!this.isSelectedMode) {
629        this.isSelectedMode = true;
630      }
631      callback();
632    }
633  }
634
635  private jumpPhotoBrowser(name: string, item: MediaItem, geometryTapIndex: number, geometryTransitionString: string): void {
636    let targetIndex = this.dataSource.getDataIndex(item);
637    if (targetIndex == Constants.NOT_FOUND) {
638      Log.error(TAG, 'targetIndex is not found');
639      return;
640    }
641    Log.info(TAG, `jump to photo browser at index: ${targetIndex}`);
642    let pageEntryFrom = Constants.ENTRY_FROM.NORMAL;
643    if (this.albumInfo.isTrashAlbum) {
644      pageEntryFrom = Constants.ENTRY_FROM.RECYCLE;
645    } else if (this.isDistributedAlbum) {
646      pageEntryFrom = Constants.ENTRY_FROM.DISTRIBUTED;
647    }
648
649    AppStorage.SetOrCreate(Constants.APP_KEY_PHOTO_BROWSER, this.dataSource);
650    if (geometryTapIndex !== undefined && geometryTransitionString !== undefined) {
651      this.jumpToPhotoBrowserGeometryTransition(
652        targetIndex, name, pageEntryFrom, geometryTapIndex, geometryTransitionString);
653    } else {
654      this.jumpToPhotoBrowserNormal(targetIndex, name, pageEntryFrom);
655    }
656  }
657
658  private jumpThirdPhotoBrowser(name: string, item: MediaItem, geometryTapIndex: number, geometryTransitionString: string): void {
659    Log.info(TAG, 'JUMP_THIRD_PHOTO_BROWSER');
660    let targetIndex = this.dataSource.getDataIndex(item);
661    if (targetIndex == Constants.NOT_FOUND) {
662      Log.error(TAG, 'targetIndex is not found');
663      return;
664    }
665    Log.info(TAG, `jump to photo browser at index: ${targetIndex} ${name}`);
666    let pageEntryFrom = Constants.ENTRY_FROM.NORMAL;
667    if (this.albumInfo.isTrashAlbum) {
668      pageEntryFrom = Constants.ENTRY_FROM.RECYCLE;
669    } else if (this.isDistributedAlbum) {
670      pageEntryFrom = Constants.ENTRY_FROM.DISTRIBUTED;
671    }
672    AppStorage.SetOrCreate(Constants.PHOTO_GRID_SELECT_MANAGER, this.mSelectManager);
673    AppStorage.SetOrCreate(Constants.APP_KEY_PHOTO_BROWSER, this.dataSource);
674    if (geometryTapIndex !== undefined && geometryTransitionString !== undefined) {
675      this.jumpToSelectPhotoBrowserGeometryTransition(
676        targetIndex, name, pageEntryFrom, geometryTapIndex, geometryTransitionString);
677    } else {
678      this.jumpToSelectPhotoBrowserNormal(targetIndex, name, pageEntryFrom);
679    }
680  }
681
682  private onLoadingFinished(size: number): void {
683    Log.info(TAG, `ON_LOADING_FINISHED size: ${size}`);
684  }
685
686  private onDataReloaded(): void {
687    Log.info(TAG, 'ON_DATA_RELOADED');
688    if (this.deleteMode) {
689      animateTo({ duration: 300 }, () => {
690        this.dataSource.onDataReloaded();
691      })
692      this.deleteMode = false;
693    } else {
694      this.dataSource.onDataReloaded();
695    }
696  }
697
698
699  updateFirstPhotoItemInfo(item: MediaItem, isFirstPhotoItem: boolean): void {
700    if (item) {
701      AppStorage.SetOrCreate<boolean>(Constants.KEY_OF_IS_FIRST_PHOTO_ITEM, isFirstPhotoItem);
702      let albumUri = AppStorage.Get<string>(Constants.KEY_OF_ALBUM_URI);
703      let transitionId = `${item.hashCode}_${albumUri}`;
704      Log.info(TAG, `updateFirstPhotoItemInfo transitionId: ${transitionId}`);
705      AppStorage.Set<string>(Constants.KEY_OF_GEOMETRY_TRANSITION_ID_HEIGHT, transitionId);
706    }
707  }
708
709  jumpToPhotoBrowserNormal(targetIndex: number, name: string, pageEntryFrom: number) {
710    Log.debug(TAG, 'start jump to photo browser in normal');
711    router.pushUrl({
712      url: 'pages/PhotoBrowser',
713      params: {
714        position: targetIndex,
715        transition: name,
716        leftBlank: this.leftBlank,
717        pageFrom: pageEntryFrom,
718        deviceName: this.deviceName,
719        albumInfo: this.albumInfo
720      }
721    });
722  }
723
724  jumpToPhotoBrowserGeometryTransition(targetIndex: number, name: string, pageEntryFrom: number,
725                                       geometryTapIndex: number, geometryTransitionString: string) {
726    Log.debug(TAG, 'start jump to photo browser in geometry transition');
727
728    interface Params {
729      position: number;
730      transition: string;
731      leftBlank: number[];
732      pageFrom: number;
733      deviceName: string;
734      albumInfo: AlbumInfo;
735    }
736
737    let params: Params = {
738      position: targetIndex,
739      transition: name,
740      leftBlank: this.leftBlank,
741      pageFrom: pageEntryFrom,
742      deviceName: this.deviceName,
743      albumInfo: this.albumInfo
744    }
745    this.browserController.showBrowser(geometryTapIndex, geometryTransitionString, TAG, params);
746  }
747
748  jumpToSelectPhotoBrowserNormal(targetIndex: number, name: string, pageEntryFrom: number) {
749    Log.debug(TAG, 'start jump to select photo browser in normal');
750    router.pushUrl({
751      url: 'pages/SelectPhotoBrowser',
752      params: {
753        position: targetIndex,
754        transition: name,
755        pageFrom: pageEntryFrom,
756      }
757    });
758  }
759
760  jumpToSelectPhotoBrowserGeometryTransition(targetIndex: number, name: string, pageEntryFrom: number,
761                                             geometryTapIndex: number, geometryTransitionString: string) {
762    Log.debug(TAG, 'start jump to select photo browser in geometry transition');
763    interface Params {
764      position: number;
765      transition: string;
766      pageFrom: number;
767    }
768
769    const params: Params = {
770      position: targetIndex,
771      transition: name,
772      pageFrom: pageEntryFrom,
773    };
774    this.browserController.showSelectBrowser(geometryTapIndex, geometryTransitionString, TAG, params);
775  }
776
777  onMediaLibDataChange(changeType: string): void {
778    Log.info(TAG, `onMediaLibDataChange type: ${changeType}`);
779    this.dataSource.switchRefreshOn();
780    this.dataSource.onChange(changeType);
781  }
782
783  aboutToDisappear(): void {
784    Log.info(TAG, `aboutToDisappear`);
785    ScreenManager.getInstance().off(ScreenManager.ON_WIN_SIZE_CHANGED, this.onWindowSizeChangeCallBack);
786    this.broadCast.off(BroadCastConstants.SELECT, this.selectFunc);
787    this.broadCast.off(BroadCastConstants.JUMP_PHOTO_BROWSER, this.jumpPhotoBrowserFunc);
788    this.broadCast.off(BroadCastConstants.JUMP_THIRD_PHOTO_BROWSER, this.jumpThirdPhotoBrowserFunc);
789    this.broadCast.off(Constants.ON_LOADING_FINISHED, this.onLoadingFinishedFunc);
790    this.broadCast.off(BroadCastConstants.ON_DATA_RELOADED, this.onDataReloadedFunc);
791    this.appBroadCast.off(BroadCastConstants.UPDATE_DATA_SOURCE, this.onUpdateFavorStateFunc);
792    this.dataSource.releaseBroadCast();
793    MediaObserver.getInstance().unregisterObserver(this.dataObserver);
794    this.dataObserver.clearSource();
795  }
796
797  isSameTransitionId(item: MediaItem): boolean {
798    return AppStorage.get<string>(Constants.KEY_OF_GEOMETRY_TRANSITION_ID_HEIGHT) as string ===
799      `${item.hashCode}_${this.dataSource.albumUri}`;
800  }
801
802  getGeometryTransitionId(item: ViewData): string {
803    return TAG + (item.mediaItem as MediaItem).hashCode + this.mSelectManager.isItemSelected((item.mediaItem as MediaItem).uri);
804  }
805
806  build() {
807    Column() {
808      PhotoGridPageActionBar({
809        title: this.title,
810        albumInfo: this.albumInfo,
811        isSystemAlbum: this.albumInfo.isSystemAlbum,
812        onMenuClicked: (action: Action): void => this.onMenuClicked(action),
813        isRecycle: this.albumInfo.isTrashAlbum,
814        isDistributedAlbum: this.isDistributedAlbum,
815        totalSelectedCount: $totalSelectedCount
816      })
817        .opacity(this.photoGridActionBarOpacity)
818
819      if (this.isEmpty) {
820        NoPhotoComponent({ title: $r('app.string.no_distributed_photo_head_title_album') })
821      } else {
822        if (this.albumInfo.isTrashAlbum) {
823          Text($r('app.string.recycle_prompt_message', Constants.RECYCLE_DAYS_MAX))
824            .fontColor($r('sys.color.ohos_id_color_text_secondary'))
825            .fontSize($r('sys.float.ohos_id_text_size_body2'))
826            .fontWeight(FontWeight.Regular)
827            .width(Constants.PERCENT_100)
828            .padding(this.isHorizontal ? {
829              left: $r('sys.float.ohos_id_max_padding_start'),
830              top: $r('app.float.recycle_prompt_message_margin_tb'),
831              bottom: $r('app.float.recycle_prompt_message_margin_tb')
832            } : {
833              left: $r('sys.float.ohos_id_max_padding_start'),
834              right: $r('sys.float.ohos_id_max_padding_end'),
835              top: $r('app.float.recycle_prompt_message_margin_tb'),
836              bottom: $r('app.float.recycle_prompt_message_margin_tb')
837            }
838            )
839        }
840        Stack() {
841          Grid(this.scroller) {
842            LazyForEach(this.dataSource, (item: ViewData, index?: number) => {
843              if (!!item) {
844                GridItem() {
845                  ImageGridItemComponent({
846                    dataSource: this.dataSource,
847                    item: item.mediaItem,
848                    isSelected: this.isSelectedMode ?
849                    this.mSelectManager.isItemSelected((item.mediaItem as MediaItem).uri) : false,
850                    isRecycle: this.albumInfo.isTrashAlbum,
851                    pageName: Constants.PHOTO_TRANSITION_ALBUM,
852                    onMenuClicked: (action: Action): void => this.onMenuClicked(action),
853                    onMenuClickedForSingleItem: (action: Action, currentPhoto: MediaItem): void => {
854                      this.onMenuClickedForSingleItem(action, currentPhoto);
855                    },
856                    geometryTransitionString: this.getGeometryTransitionId(item),
857                    mPosition: index,
858                    selectedCount: $totalSelectedCount
859                  })
860                }
861                .zIndex(this.isSameTransitionId(item.mediaItem as MediaItem) || index === this.placeholderIndex ? 1 : 0)
862                .width(this.gridItemWidth)
863                .aspectRatio(1)
864                .key('AlbumGridImage' + index)
865              }
866            }, (item: ViewData, index?: number) => {
867              if (item == null || item == undefined) {
868                return JSON.stringify(item);
869              }
870              // Update animation object
871              if (index === 0) {
872                if (this.scrollIndex === 0) {
873                  this.updateFirstPhotoItemInfo(item.mediaItem as MediaItem, true);
874                } else {
875                  this.updateFirstPhotoItemInfo((this.dataSource.getData(this.scrollIndex) as ViewData)?.mediaItem as MediaItem, false);
876                }
877              }
878              return this.getGeometryTransitionId(item)
879            })
880          }
881          .zIndex(-1)
882          .clip(false)
883          .onScrollIndex((index: number) => {
884            this.scrollIndex = index;
885            this.updateFirstPhotoItemInfo((this.dataSource.getData(index) as ViewData)?.mediaItem as MediaItem, false);
886          })
887          .edgeEffect(EdgeEffect.Spring)
888          .scrollBar(BarState.Off)
889          .columnsTemplate('1fr '.repeat(this.gridRowCount))
890          .columnsGap(Constants.GRID_GUTTER)
891          .rowsGap(Constants.GRID_GUTTER)
892          .cachedCount(Constants.GRID_CACHE_ROW_COUNT)
893          .transition(TransitionEffect.scale({
894            x: BrowserConstants.PHOTO_GRID_Scale,
895            y: BrowserConstants.PHOTO_GRID_Scale,
896            z: BrowserConstants.PHOTO_GRID_Scale
897          }))
898
899          if (this.isShowScrollBar) {
900            GridScrollBar({ scroller: this.scroller });
901          }
902
903          if (this.albumInfo.isTrashAlbum) {
904            Column() {
905              Row() {
906                Button({ type: ButtonType.Capsule, stateEffect: true }) {
907                  Text($r('app.string.action_clear_recycle'))
908                    .fontWeight(FontWeight.Medium)
909                    .fontSize($r('sys.float.ohos_id_text_size_button1'))
910                    .fontColor($r('sys.color.ohos_id_color_text_primary_activated'))
911                    .margin({
912                      left: $r('app.float.dialog_double_buttons_margin'),
913                      right: $r('app.float.dialog_double_buttons_margin')
914                    })
915                }
916                .key('ClearRecycleButton')
917                .height($r('app.float.details_dialog_button_height'))
918                .borderRadius($r('sys.float.ohos_id_corner_radius_button'))
919                .backgroundColor($r('sys.color.ohos_id_color_button_normal'))
920                .onClick(() => {
921                  this.onMenuClicked && this.onMenuClicked(Action.CLEAR_RECYCLE);
922                })
923              }
924              .borderRadius($r('sys.float.ohos_id_corner_radius_button'))
925              .backgroundColor($r('sys.color.ohos_id_color_sub_background'))
926            }
927            .hitTestBehavior(HitTestMode.Transparent)
928            .width(`100%`)
929            .height('100%')
930            .alignItems(HorizontalAlign.Center)
931            .justifyContent(FlexAlign.End)
932            .padding({ bottom: $r('sys.float.ohos_id_default_padding_bottom_fixed') })
933            .visibility(this.isSelectedMode ? Visibility.Hidden : Visibility.Visible)
934          }
935        }
936        .clip(true)
937        .zIndex(-1)
938        .layoutWeight(1)
939        .padding({
940          bottom: ((this.isSelectedMode) && !this.isHorizontal) ? Constants.ActionBarHeight : 0
941        })
942      }
943      CustomDialogView({ broadCast: $broadCast });
944
945      if (this.isSelectedMode) {
946        PhotoGridPageToolBar({
947          onMenuClicked: (action: Action): void => this.onMenuClicked(action),
948          isRecycleAlbum: (this.albumInfo.isTrashAlbum),
949          isDistributedAlbum: this.isDistributedAlbum,
950          totalSelectedCount: $totalSelectedCount
951        });
952      }
953    }
954    .clip(true)
955    .opacity(this.photoGridViewOpacity)
956    .backgroundColor($r('app.color.default_background_color'))
957    .padding({
958      top: this.leftBlank[1]
959    })
960  }
961
962  private onUpdateFavorState(item: MediaItem): void {
963    Log.debug(TAG, 'onUpdateFavorState');
964    let index = this.dataSource.getIndexByMediaItem(item);
965    if (index != -1) {
966      this.dataSource.onDataChanged(index);
967    }
968  }
969
970  private moveOperation(albumName: string, albumUri: string): void {
971    let menuContext = new MenuContext();
972    if (this.isMvOrCpSeparatesItem) {
973      menuContext.withMediaItem(this.mvOrCpSeparatesItem);
974      this.onMoveStart && this.onMoveStart();
975    } else {
976      menuContext.withSelectManager(this.mSelectManager).withOperationStartCallback((): void => this.onMoveStart());
977    }
978    menuContext.withOperationEndCallback((err: Error, count: number, total: number): void => this.onMoveEnd(err as Object, count, total))
979      .withBroadCast(this.broadCast)
980      .withTargetAlbumName(albumName)
981      .withAlbumUri(albumUri);
982    let menuOperation = MenuOperationFactory.getInstance().createMenuOperation(MoveMenuOperation, menuContext);
983    AppStorage.SetOrCreate(Constants.APP_KEY_NEW_ALBUM_SOURCE, this.albumInfo.uri);
984    menuOperation.doAction();
985  }
986
987  private addOperation(albumName: string, albumUri: string): void {
988    let menuContext = new MenuContext();
989    if (this.isMvOrCpSeparatesItem) {
990      menuContext.withMediaItem(this.mvOrCpSeparatesItem);
991      this.onCopyStart && this.onCopyStart();
992    } else {
993      menuContext.withSelectManager(this.mSelectManager).withOperationStartCallback((): void => this.onCopyStart());
994    }
995    menuContext.withOperationEndCallback((err: Error, count: number, total: number): void => this.onCopyEnd(err as Object, count, total))
996      .withBroadCast(this.broadCast)
997      .withTargetAlbumName(albumName)
998      .withAlbumUri(albumUri);
999    let menuOperation = MenuOperationFactory.getInstance().createMenuOperation(AddMenuOperation, menuContext);
1000    menuOperation.doAction();
1001  }
1002
1003  private onMenuClickedForSingleItem(action: Action, currentPhoto: MediaItem) {
1004    Log.info(TAG, `single menu click, action: ${action?.actionID}, currentUri: ${currentPhoto?.uri}`);
1005    if (currentPhoto == undefined) {
1006      return;
1007    }
1008    let menuOperation: MenuOperation;
1009    let menuContext: MenuContext;
1010    if (action.actionID === Action.RECOVER.actionID) {
1011      menuContext = new MenuContext();
1012      menuContext.withMediaItem(currentPhoto).withBroadCast(this.broadCast);
1013      menuOperation = MenuOperationFactory.getInstance()
1014        .createMenuOperation(RecoverMenuOperation, menuContext);
1015      menuOperation.doAction();
1016    } else if (action.actionID === Action.DELETE.actionID) {
1017      menuContext = new MenuContext();
1018      if (this.dataSource.albumUri == UserFileManagerAccess.getInstance()
1019        .getSystemAlbumUri(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE)) {
1020        menuContext.withAlbumUri(UserFileManagerAccess.getInstance()
1021          .getSystemAlbumUri(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE));
1022      }
1023      menuContext.withMediaItem(currentPhoto).withBroadCast(this.broadCast);
1024      menuOperation = MenuOperationFactory.getInstance()
1025        .createMenuOperation(DeleteMenuOperation, menuContext);
1026      menuOperation.doAction();
1027    } else if (action.actionID === Action.MOVE.actionID) {
1028      this.isMvOrCpSeparatesItem = true;
1029      this.mvOrCpSeparatesItem = currentPhoto;
1030      this.routeToSelectAlbumPage(MediaOperationType.Move, [currentPhoto]);
1031    } else if (action.actionID === Action.ADD.actionID) {
1032      this.isMvOrCpSeparatesItem = true;
1033      this.mvOrCpSeparatesItem = currentPhoto;
1034      this.routeToSelectAlbumPage(MediaOperationType.Add, [currentPhoto]);
1035    } else if (action.actionID === Action.REMOVE_FROM.actionID) {
1036      menuContext = new MenuContext();
1037      menuContext.withMediaItem(currentPhoto).withBroadCast(this.broadCast);
1038      menuOperation = MenuOperationFactory.getInstance()
1039        .createMenuOperation(RemoveMenuOperation, menuContext);
1040      menuOperation.doAction();
1041    } else if (action.actionID === Action.INFO.actionID) {
1042      this.broadCast.emit(BroadCastConstants.SHOW_DETAIL_DIALOG, [currentPhoto, false]);
1043    }
1044  }
1045
1046  private initGridRowCount(): void {
1047    let contentWidth = ScreenManager.getInstance().getWinWidth();
1048    let margin = 0;
1049    let maxThumbWidth = px2vp(Constants.GRID_IMAGE_SIZE) * Constants.GRID_MAX_SIZE_RATIO;
1050    // 原型机竖屏为4不变,横屏需计算: currentBreakpoint == 'lg' 表示横屏
1051    const currentBreakpoint: string = AppStorage.get<string>('currentBreakpoint') as string;
1052    this.gridRowCount = currentBreakpoint == Constants.BREAKPOINT_LG ?
1053    Math.max(Constants.GRID_MIN_COUNT, Math.ceil(((contentWidth - Constants.NUMBER_2 * margin)
1054      + Constants.GRID_GUTTER) / (maxThumbWidth + Constants.GRID_GUTTER))) : Constants.GRID_MIN_COUNT;
1055    this.gridItemWidth = (contentWidth - (this.gridRowCount - 1) * Constants.GRID_GUTTER -
1056      Constants.NUMBER_2 * margin) / this.gridRowCount;
1057    Log.info(TAG, `initGridRowCount contentWidth: ${contentWidth}`);
1058  }
1059
1060  private onUpdateRemoteDevice(res: string, deviceId: string): void {
1061    Log.info(TAG, `onUpdateRemoteDevice`);
1062    if (res == 'offline') {
1063      Log.debug(TAG, `device offline route to album main`);
1064      router.back({
1065        url: 'pages/index',
1066        params: {
1067          jumpSource: JumpSourceToMain.ALBUM,
1068        }
1069      });
1070    } else {
1071      Log.error(TAG, `res code is err ${res}`);
1072      return;
1073    }
1074  }
1075}
1076
1077interface Params {
1078  albumName: string;
1079  albumUri: string;
1080  pageType: string;
1081};
1082
1083interface ParamAlbumInfo {
1084  item: string;
1085  isFromFACard: boolean;
1086};