• 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 bundle from '@ohos.bundle';
18import CommonEvent from '@ohos.commonEvent';
19import window from '@ohos.window';
20import { MenuOperation, ViewData } from '@ohos/common';
21import {
22  Action,
23  AddMenuOperation,
24  AlbumDefine,
25  AlbumInfo,
26  BigDataConstants,
27  BreakpointSystem,
28  BroadCast,
29  BroadCastConstants,
30  BroadCastManager,
31  CommonObserverCallback,
32  Constants,
33  DateUtil,
34  DeleteMenuOperation,
35  JumpSourceToMain,
36  Log,
37  MediaDataSource,
38  MediaItem,
39  MediaObserver,
40  MediaOperationType,
41  MenuContext,
42  MenuOperationFactory,
43  MoveMenuOperation,
44  BrowserConstants as PhotoConstants,
45  PhotoDataSource,
46  RemoveMenuOperation,
47  ReportToBigDataUtil,
48  ScreenManager,
49  ShareMenuOperation,
50  TraceControllerUtils,
51  UiUtil,
52  UriDataSource,
53  UserFileManagerAccess,
54  WindowUtil
55} from '@ohos/common';
56import {
57  BrowserController,
58  CustomDialogView,
59  PhotoBrowserComponentBg,
60  PhotoBrowserHolder,
61  PhotoSwiper
62} from '@ohos/common/CommonComponents';
63import {
64  AddNotesMenuOperation,
65  FavoriteMenuOperation,
66  GotoPhotosMenuOperation,
67  RecoverMenuOperation,
68  RenameMenuOperation,
69  RotateMenuOperation
70} from '@ohos/browser';
71import {
72  PhotoBrowserActionBar,
73  PhotoBrowserToolBar
74} from '@ohos/browser/BrowserComponents';
75import ability from '@ohos.ability.ability';
76import common from '@ohos.app.ability.common';
77
78const TAG: string = 'PhotoBrowserComponent';
79
80interface ParamBrowser {
81  pageFrom: number;
82  albumInfo: AlbumInfo;
83  clickThumbnailTime: number;
84  albumUri: string;
85  uri: string;
86  viewData: ViewData;
87  viewDataIndex: string;
88  viewDataAlbum: string;
89  transition: string;
90  position: number;
91  isShowMenuFromThirdView: boolean;
92  deviceName: string;
93  deviceId: string;
94};
95
96interface Params {
97  pageType: string;
98  albumName: string;
99  albumUri: string;
100};
101
102interface TitleName {
103  title: string;
104  displayName: string;
105}
106
107// page of large photo
108@Component
109export struct PhotoBrowserComponent {
110  @Provide backgroundColorResource: Resource = $r('app.color.default_background_color');
111  @Provide('dateTitle') photoDate: string = '';
112  @Provide('timeLocationTitle') timeAndLocation: string = '';
113  @Provide menuList: Array<Action> = new Array<Action>();
114  @Provide toolMenuList: Array<Action> = new Array<Action>();
115  @Provide topMenuList: Array<Action> = new Array<Action>();
116  @Provide moreMenuList: Array<Action> = new Array<Action>();
117  @State broadCast: BroadCast = new BroadCast();
118  @Provide isShowBar: boolean = true;
119  @Provide onlyChangeBgColor: boolean = false;
120  @Provide canSwipe: boolean = true;
121  @Provide pageFrom: number = Constants.ENTRY_FROM.NORMAL;
122  @State @Watch('updateMoreMenu') currentShow: boolean = true;
123  @StorageLink('isHorizontal') @Watch('updateIsHorizontal') isHorizontal: boolean = ScreenManager.getInstance()
124    .isHorizontal();
125  @StorageLink('TimelinePageIndex') TimelinePageIndex: number = Constants.INVALID;
126  @StorageLink('PhotoGridPageIndex') PhotoGridPageIndex: number = Constants.INVALID;
127  @StorageLink('isSplitMode') isSplitMode: boolean = ScreenManager.getInstance().isSplitMode();
128  @StorageLink('leftBlank') leftBlank: number[]
129    = [0, ScreenManager.getInstance().getStatusBarHeight(), 0, ScreenManager.getInstance().getNaviBarHeight()];
130  @StorageLink('entryFromHap') entryFromHap: number = Constants.ENTRY_FROM_NONE;
131  mTransition: string = '';
132  albumUri = '';
133  // swiper currentIndex, there may not be onChanged callback during data refresh, so mediaItem cannot be saved
134  @Provide('transitionIndex') currentIndex: number = Constants.NUMBER_0;
135  controller: SwiperController = new SwiperController();
136  @Prop @Watch('onPageChanged') pageStatus: boolean = false;
137  @StorageLink('geometryOpacity') geometryOpacity: number = 1;
138  @State geometryTransitionId: string = '';
139  @Link isRunningAnimation: boolean;
140  @ObjectLink browserController: BrowserController;
141  @Provide isDeleting: boolean = false;
142  @Provide hidePopup: boolean = false;
143  private isFirstLoad: boolean = true;
144  private bundleFlags = Constants.NUMBER_0;
145  // DataSource
146  private dataSource: PhotoDataSource = new PhotoDataSource();
147  private dataObserver: CommonObserverCallback = new CommonObserverCallback(this);
148  // The global BroadCast of the application process. Event registration and destruction should be paired
149  private appBroadCast: BroadCast = BroadCastManager.getInstance().getBroadCast();
150  private isFromCamera = false;
151  private isFromViewDataWithMediaUri = false;
152  private isFromViewDataWithThirdUri = false;
153  private isFromFACard = false;
154  private isPullDown = false;
155  // the source of jump to the index page
156  private jumpSourceToMain: number = JumpSourceToMain.None;
157  // time when clicks the thumbnail from the camera
158  private clickThumbnailTime = Constants.NUMBER_0;
159  // time to view the current picture
160  private checkedTransition: string = '';
161  private viewTime = Constants.NUMBER_0;
162  // When clicking quickly, only run aboutToAppear for the first time
163  private hasAppeared: boolean = false;
164  private albumInfo?: AlbumInfo;
165  private deviceName = '';
166  private backFromCopy = false;
167  private uriFromThirdPartyApp: string = '';
168  private editNewUri: string = "";
169  private favorCacheItemsMap = new Map<String, MediaItem>()
170  private breakpointSystem: BreakpointSystem = new BreakpointSystem();
171  private theDeleteItem: MediaItem | null = null;
172  private geometryTransitionEnable: boolean = false;
173  private isShowMenuFromThirdView: boolean = true;
174  private isToEdit = false;
175  private photoBrowserBackFunc: Function = (): void => this.photoBrowserBack();
176  private onToggleBarsFunc: Function = (backgroundColorResource?: Resource): void => this.onToggleBars(backgroundColorResource);
177  private showBarsFunc: Function = (backgroundColorResource?: Resource): void => this.showBars(backgroundColorResource);
178  private hideBarsFunc: Function = (backgroundColorResource?: Resource): void => this.hideBars(backgroundColorResource);
179  private pullDownStartFunc: Function = (): void => this.pullDownStart();
180  private pullDownEndFunc: Function = (): void => this.pullDownEnd();
181  private onDataSizeChangedFunc: Function = (size: number): void => this.onDataSizeChanged(size);
182  private onDataContentChangedFunc: Function = (): void => this.onDataContentChanged();
183  private setFavorFunc: Function = (isFavor: boolean): void => this.setFavor(isFavor);
184  private doRenameFunc: Function = (result: TitleName): void => this.doRename(result);
185  private doRotateFunc: Function = (result: number): void => this.doRotate(result);
186  private pullDownStartWithEventFunc: Function = (event: KeyEvent): void => this.pullDownStartWithEvent(event);
187  private pullDownCancelFunc: Function = (): void => this.pullDownCancel();
188  private onPhotoBrowserDeleteConfirmFunc: Function = (): void => this.onPhotoBrowserDeleteConfirm();
189  private onPhotoBrowserRemoveConfirmFunc: Function = (): void => this.onPhotoBrowserRemoveConfirm();
190  private doDeleteFunc: Function = (): void => this.doDelete();
191  private onPhotoShowStateChangedFunc: Function = (state: boolean): void => this.onPhotoShowStateChanged(state);
192  private setSwiperDisableFunc: Function = (value: boolean): void => this.setSwiperDisable(value);
193  private onDataReloadWithEditFunc: Function = (): void => this.onDataReloadWithEdit();
194
195
196  onPageChanged() {
197    Log.info(TAG, `call page status changed ${this.pageStatus}`)
198    if (this.pageStatus) {
199      this.onPageShow();
200    } else {
201      this.onPageHide();
202    }
203  }
204
205  discardCallback(): void {
206    Log.debug(TAG, 'discardCallback called');
207  }
208
209  updateIsHorizontal(): void {
210    if (this.isHorizontal) {
211      ScreenManager.getInstance().setSystemUi(false);
212    } else {
213      if (this.isShowBar) {
214        ScreenManager.getInstance().setSystemUi(true);
215      }
216    }
217
218    if (!this.isFirstLoad) {
219      this.updateMenu();
220    } else {
221      this.isFirstLoad = false;
222    }
223  }
224
225  onMenuClicked(action: Action): void {
226    let actionID: number = action.actionID;
227    Log.info(TAG, `onMenuClicked, actionID: ${actionID}`);
228    let menuOperation: MenuOperation | null = null;
229    let menuContext: MenuContext = new MenuContext();
230    let currentPhoto = this.getCurrentPhoto();
231    if (actionID === Action.BACK.actionID) {
232      this.onBackPress();
233    } else if (actionID === Action.INFO.actionID) {
234      if (currentPhoto == undefined) {
235        Log.warn(TAG, 'currentPhoto is undefined');
236        return;
237      }
238      this.broadCast.emit(BroadCastConstants.SHOW_DETAIL_DIALOG, [currentPhoto, this.pageFrom == Constants.ENTRY_FROM.DISTRIBUTED]);
239    } else if (actionID === Action.SHARE.actionID) {
240      if (currentPhoto == undefined) {
241        Log.warn(TAG, 'currentPhoto is undefined');
242        return;
243      }
244      menuContext.withFromSelectMode(false).withMediaItem(currentPhoto);
245      menuOperation = MenuOperationFactory.getInstance()
246        .createMenuOperation(ShareMenuOperation, menuContext);
247    } else if (actionID === Action.NOT_FAVORITE.actionID || actionID === Action.FAVORITE.actionID) {
248      if (currentPhoto == undefined) {
249        Log.warn(TAG, 'currentPhoto is undefined.');
250        return;
251      }
252      currentPhoto.isFavor = !currentPhoto.isFavor;
253
254      if (this.albumUri !== UserFileManagerAccess.getInstance()
255        .getSystemAlbumUri(UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE)) {
256        let currentPhoto = this.getCurrentPhoto();
257        menuContext.withMediaItem(currentPhoto).withBroadCast(this.broadCast);
258        menuOperation = MenuOperationFactory.getInstance().createMenuOperation(FavoriteMenuOperation, menuContext);
259        this.appBroadCast.emit(BroadCastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
260      } else {
261        if (currentPhoto.isFavor === true) {
262          if (this.favorCacheItemsMap.has(currentPhoto.uri)) {
263            this.favorCacheItemsMap.delete(currentPhoto.uri);
264          } else {
265            Log.error(TAG, `not fount item uri ${currentPhoto.uri}`);
266          }
267        } else {
268          this.favorCacheItemsMap.set(currentPhoto.uri, currentPhoto);
269        }
270      }
271      this.updateMenu();
272      this.geometryTransitionId = this.browserController.pageFrom + currentPhoto.getHashCode() + 'false';
273      AppStorage.SetOrCreate<string>('geometryTransitionBrowserId', this.geometryTransitionId);
274    } else if (actionID === Action.DELETE.actionID) {
275      if (currentPhoto == undefined) {
276        Log.warn(TAG, 'currentPhoto is undefined.');
277        return;
278      }
279      menuContext.withAlbumInfo(this.albumInfo);
280      this.theDeleteItem = currentPhoto;
281      menuContext.withMediaItem(currentPhoto).withBroadCast(this.broadCast);
282      menuOperation = MenuOperationFactory.getInstance()
283        .createMenuOperation(DeleteMenuOperation, menuContext);
284    } else if (actionID === Action.RECOVER.actionID) {
285      if (currentPhoto == undefined) {
286        Log.warn(TAG, 'currentPhoto is undefined.');
287        return;
288      }
289      menuContext.withMediaItem(currentPhoto).withBroadCast(this.broadCast);
290      menuOperation = MenuOperationFactory.getInstance()
291        .createMenuOperation(RecoverMenuOperation, menuContext);
292    } else if (actionID === Action.GOTO_PHOTOS.actionID) {
293      if (currentPhoto == undefined) {
294        Log.warn(TAG, 'currentPhoto is undefined.');
295        return;
296      }
297      menuContext.withJumpSourceToMain(this.jumpSourceToMain);
298      menuOperation = MenuOperationFactory.getInstance()
299        .createMenuOperation(GotoPhotosMenuOperation, menuContext);
300    } else if (actionID === Action.EDIT.actionID) {
301      if (currentPhoto == undefined || currentPhoto.size == 0) {
302        Log.warn(TAG, 'currentPhoto is undefined or size is 0.');
303        return;
304      }
305      AppStorage.setOrCreate<MediaItem | undefined>('EditorMediaItem', currentPhoto);
306      AppStorage.setOrCreate<string>('EditorAlbumUri', this.albumUri);
307      router.pushUrl({
308        url: 'pages/EditMain'
309      })
310      this.isToEdit = true;
311    } else if (actionID === Action.EDIT_INVALID.actionID) {
312      if (currentPhoto == undefined || currentPhoto.size == 0) {
313        Log.warn(TAG, 'currentPhoto is undefined or size is 0.');
314        return;
315      }
316    } else if (actionID === Action.RENAME.actionID) {
317      this.hidePopup = true;
318      if (currentPhoto == undefined) {
319        Log.warn(TAG, 'currentPhoto is undefined.');
320        return;
321      }
322      menuContext.withMediaItem(currentPhoto).withBroadCast(this.broadCast).withAlbumUri(this.albumUri);
323      menuOperation = MenuOperationFactory.getInstance().createMenuOperation(RenameMenuOperation, menuContext);
324    } else if (actionID === Action.ROTATE.actionID) {
325      if (currentPhoto == undefined) {
326        Log.warn(TAG, 'currentPhoto is undefined when onMenuClicked Action.RENAME.');
327        return;
328      }
329      let rotateValue = currentPhoto.orientation - Constants.DEFAULT_ROTATE_VALUE + Constants.ROTATE_AROUND;
330      if (rotateValue >= Constants.ROTATE_AROUND) {
331        rotateValue = rotateValue - Constants.ROTATE_AROUND;
332      }
333      currentPhoto.orientation = rotateValue;
334      menuContext.withMediaItem(currentPhoto).withBroadCast(this.broadCast);
335      menuOperation = MenuOperationFactory.getInstance().createMenuOperation(RotateMenuOperation, menuContext);
336    } else if (actionID === Action.ADD_NOTES.actionID) {
337      if (currentPhoto == undefined) {
338        Log.warn(TAG, 'currentPhoto is undefined when onMenuClicked Action.RENAME.');
339        return;
340      }
341      menuContext.withMediaItem(currentPhoto).withBroadCast(this.broadCast);
342      menuOperation = MenuOperationFactory.getInstance().createMenuOperation(AddNotesMenuOperation, menuContext);
343    } else if (actionID === Action.MOVE.actionID) {
344      if (currentPhoto == undefined) {
345        Log.warn(TAG, 'currentPhoto is undefined when onMenuClicked Action.MOVE.');
346        return;
347      }
348      this.backFromCopy = true;
349      currentPhoto && currentPhoto.mediaType &&
350      this.routeToSelectAlbumPage(MediaOperationType.Move, currentPhoto.mediaType);
351      return;
352    } else if (actionID === Action.ADD.actionID) {
353      if (currentPhoto == undefined) {
354        Log.warn(TAG, 'currentPhoto is undefined when onMenuClicked Action.ADD.');
355        return;
356      }
357      this.backFromCopy = true;
358      currentPhoto && currentPhoto.mediaType &&
359      this.routeToSelectAlbumPage(MediaOperationType.Add, currentPhoto.mediaType);
360    } else if (actionID === Action.REMOVE_FROM.actionID) {
361      if (currentPhoto == undefined) {
362        Log.warn(TAG, 'currentPhoto is undefined.');
363        return;
364      }
365
366      menuContext.withAlbumUri(this.albumUri);
367      menuContext.withMediaItem(currentPhoto).withBroadCast(this.broadCast);
368      menuOperation = MenuOperationFactory.getInstance()
369        .createMenuOperation(RemoveMenuOperation, menuContext);
370    } else if (actionID === Action.DOWNLOAD.actionID) {
371      this.downLoad();
372    }
373    if (!!menuOperation) {
374      menuOperation.doAction();
375    }
376  }
377
378  routeToSelectAlbumPage(pageType: string, mediaType: number): void {
379    router.pushUrl({
380      url: 'pages/MediaOperationPage',
381      params: {
382        pageFrom: Constants.MEDIA_OPERATION_FROM_PHOTO_BROWSER,
383        pageType: pageType,
384        albumInfo: this.albumInfo,
385        mediaType: mediaType
386      }
387    });
388  }
389
390  onPhotoChanged(index: number): void {
391    Log.info(TAG, `onPhotoChanged start, index=${index}`);
392    this.reportToBigDataForPhotoSlide(index);
393    this.currentIndex = index;
394    this.updateActionBar && this.updateActionBar();
395    let currentPhoto = this.getCurrentPhoto();
396    if (currentPhoto == undefined) {
397      Log.error(TAG, 'onPhotoChanged, item is undefined');
398    } else {
399      let timelineIndex = this.dataSource.getPositionByIndex(index);
400      AppStorage.SetOrCreate<number>('placeholderIndex', timelineIndex);
401      this.geometryTransitionId = this.browserController.pageFrom + currentPhoto.getHashCode() + 'false';
402      AppStorage.SetOrCreate<string>('geometryTransitionBrowserId', this.geometryTransitionId);
403      Log.debug(TAG, `onPhotoChanged, index: ${index}, currentPhoto: ${currentPhoto.uri}, \
404        placeholderIndex ${AppStorage.get<number>('placeholderIndex') as number},\
405        geometryTransitionBrowserId ${this.geometryTransitionId}, this.mTransition ${this.mTransition}, \
406        pageFrom = ${this.pageFrom}`);
407    }
408    this.updatePixMapDataSource();
409  }
410
411  onDataSizeChanged(size: number): void {
412    Log.info(TAG, `onDataSizeChanged, size is ${size}`);
413    if (size == 0 && !this.isToEdit) {
414      if (this.uriFromThirdPartyApp) {
415        return;
416      }
417      this.onBackPress();
418    }
419  }
420
421  resetAlbum(albumUri: string): void {
422    this.currentIndex = 0;
423    Log.info(TAG, `not found in album[${this.albumUri}], so use ${albumUri} instead`);
424    this.albumUri = albumUri;
425    this.dataSource.resetAlbumUri(this.albumUri);
426    return;
427  }
428
429  updatePixMapDataSource(): void {
430    this.dataSource.updatePixMapDataSource(this.currentIndex);
431  }
432
433  updateActionBar(): void {
434    let currentPhoto = this.getCurrentPhoto();
435    if (currentPhoto == undefined || this.isFromViewDataWithThirdUri) {
436      return;
437    }
438    this.photoDate = DateUtil.getLocalizedDate(currentPhoto.getDataTaken());
439    if (this.pageFrom == Constants.ENTRY_FROM.DISTRIBUTED) {
440      this.timeAndLocation = `${this.deviceName}/${DateUtil.getLocalizedTime(currentPhoto.getDataTaken())}`;
441    } else {
442      this.timeAndLocation = DateUtil.getLocalizedTime(currentPhoto.getDataTaken());
443    }
444    this.updateMenu();
445  }
446
447  updateMenu(): void {
448    let currentPhoto = this.getCurrentPhoto();
449    if (!currentPhoto) {
450      return;
451    }
452
453    if (this.albumUri == UserFileManagerAccess.getInstance()
454      .getSystemAlbumUri(UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE)) {
455      let key = currentPhoto.uri;
456      if (this.favorCacheItemsMap.has(key)) {
457        let tempPhotoItem: MediaItem = this.favorCacheItemsMap.get(key) as MediaItem;
458        currentPhoto.isFavor = tempPhotoItem.isFavor;
459        this.favorCacheItemsMap.set(key, currentPhoto);
460      }
461    }
462
463    let pageFrom: number = this.pageFrom;
464    if (this.albumUri === UserFileManagerAccess.getInstance()
465      .getSystemAlbumUri(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE)) {
466      pageFrom = Constants.ENTRY_FROM.RECYCLE;
467    }
468
469    Log.info(TAG, `updateMenu album[${this.albumUri}]`);
470
471    let menuTemp: Array<Action> = new Array<Action>();
472    if (this.pageFrom == Constants.ENTRY_FROM.CAMERA ||
473      this.pageFrom == Constants.ENTRY_FROM.CARD ||
474      (this.isFromViewDataWithMediaUri == true &&
475        this.albumUri != UserFileManagerAccess.getInstance()
476          .getSystemAlbumUri(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE))) {
477      menuTemp = [Action.GOTO_PHOTOS, Action.INFO];
478    } else if (pageFrom == Constants.ENTRY_FROM.RECYCLE || this.isFromViewDataWithThirdUri == true) {
479      menuTemp = [];
480    } else {
481      menuTemp = [Action.INFO];
482    }
483    if (!UiUtil.isActionArrayEqual(this.menuList, menuTemp)) {
484      this.menuList = menuTemp;
485    }
486
487    let list: Array<Action> = new Array<Action>();
488    if (pageFrom === Constants.ENTRY_FROM.NORMAL || pageFrom === Constants.ENTRY_FROM.CAMERA) {
489      list.push(currentPhoto.isFavor ? Action.FAVORITE : Action.NOT_FAVORITE,
490        ((currentPhoto.mediaType == UserFileManagerAccess.MEDIA_TYPE_IMAGE))
491          ? Action.EDIT : Action.EDIT_INVALID, Action.DELETE, Action.MORE); // TODO: delete edit
492    } else if (pageFrom === Constants.ENTRY_FROM.RECYCLE) {
493      list.push(Action.RECOVER, Action.DELETE);
494    } else if (pageFrom === Constants.ENTRY_FROM.DISTRIBUTED) {
495      list.push(Action.DOWNLOAD);
496    } else {
497      list.push(currentPhoto.isFavor ? Action.FAVORITE : Action.NOT_FAVORITE,
498        ((currentPhoto.mediaType == UserFileManagerAccess.MEDIA_TYPE_IMAGE))
499          ? Action.EDIT : Action.EDIT_INVALID, Action.DELETE, Action.MORE); // TODO: delete edit
500    }
501
502    if (this.isHorizontal) {
503      if (this.isShowMenuFromThirdView) {
504        this.menuList = this.menuList.concat(list);
505      }
506      this.toolMenuList = [];
507    } else {
508      if (this.isShowMenuFromThirdView) {
509        if (!UiUtil.isActionArrayEqual(this.toolMenuList, list)) {
510          this.toolMenuList = list;
511        }
512      } else {
513        this.toolMenuList = [];
514      }
515    }
516    let menuTempList: Array<Action>;
517    if (!this.albumInfo) {
518      // 照片页
519      menuTempList = [Action.ADD, Action.RENAME];
520    } else {
521      // 指定相册
522      menuTempList = this.albumInfo.isSystemAlbum ?
523        [Action.ADD, Action.RENAME] : [Action.MOVE, Action.ADD, Action.REMOVE_FROM, Action.RENAME];
524    }
525    if (!UiUtil.isActionArrayEqual(this.moreMenuList, menuTempList)) {
526      this.moreMenuList = menuTempList;
527    }
528  }
529
530  isShowMenuBigData(isShowMenuFromThirdView: boolean): void {
531    interface ShowMenuMsg {
532      isShowMenuFromThirdView: string
533    }
534    let isShowMenuMsg: ShowMenuMsg;
535    if (isShowMenuFromThirdView) {
536      this.isShowMenuFromThirdView = true;
537      isShowMenuMsg = {
538        isShowMenuFromThirdView: BigDataConstants.SHOW_MENU
539      }
540    } else if (isShowMenuFromThirdView == false) {
541      this.isShowMenuFromThirdView = false;
542      isShowMenuMsg = {
543        isShowMenuFromThirdView: BigDataConstants.HIDE_MENU
544      }
545    } else {
546      this.isShowMenuFromThirdView = true;
547      isShowMenuMsg = {
548        isShowMenuFromThirdView: BigDataConstants.UNDEFINED_IS_SHOW_MENU
549      }
550    }
551    this.updateMenu();
552    ReportToBigDataUtil.statisticReport(BigDataConstants.IS_SHOW_MENU_ID, isShowMenuMsg);
553  }
554
555  updateMoreMenu(): void {
556    this.moreMenuList = this.albumInfo?.isSystemAlbum ?
557      [Action.ADD, Action.RENAME] : [Action.MOVE, Action.ADD, Action.REMOVE_FROM, Action.RENAME];
558  }
559
560  getCurrentPhoto(): MediaItem {
561    return this.dataSource.getRawData(this.currentIndex).data;
562  }
563
564  getPhotoByIndex(index: number): MediaItem {
565    return this.dataSource.getRawData(index).data;
566  }
567
568  async onMoveEnd(err: Object, count: number, total: number): Promise<void> {
569    Log.debug(TAG, `onMoveEnd count: ${count}, total: ${total}`);
570    if (err) {
571      UiUtil.showToast($r('app.string.move_failed_single'));
572      return;
573    }
574    let currentPhoto = this.getCurrentPhoto();
575    let newItem = await this.dataSource.getDataByUri(currentPhoto.uri)
576    this.appBroadCast.emit(BroadCastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
577  }
578
579  onCopyEnd(err: Object, count: number, total: number): void {
580    Log.debug(TAG, `onCopyEnd count: ${count}, total: ${total}`);
581    if (err) {
582      UiUtil.showToast($r('app.string.copy_failed_single'));
583    }
584  }
585
586  async onDownloadEnd(err: Object, count: number, total: number): Promise<void> {
587    Log.debug(TAG, `onDownloadEnd count: ${count}, total: ${total}`);
588    this.appBroadCast.emit(BroadCastConstants.PHOTO_BROWSER_ACTIVE, [true, this.checkedTransition]);
589    if (err) {
590      UiUtil.showToast($r('app.string.download_failed_single'));
591    } else {
592      UiUtil.showToast($r('app.string.download_progress_done'));
593    }
594  }
595
596  onBackPress(): boolean {
597    Log.info(TAG, 'onBackPress');
598    this.appBroadCast.emit('hideBar', []);
599    this.controller.finishAnimation((): void => this.onBackPressInner());
600    return true;
601  }
602
603  onBackPressInner(): void {
604    Log.info(TAG, `onBackPressInner ${this.checkedTransition}`);
605    this.dataSource.release();
606    if (this.checkedTransition === Constants.PHOTO_TRANSITION_TIMELINE) {
607      Log.info(TAG, 'onBackPress TimelinePage');
608      this.TimelinePageIndex = this.currentIndex; // call scrollTo
609      this.TimelinePageIndex = Constants.INVALID;
610    } else if (this.checkedTransition === Constants.PHOTO_TRANSITION_ALBUM) {
611      Log.info(TAG, 'onBackPress PhotoGridPage');
612      this.PhotoGridPageIndex = this.currentIndex; // call scrollTo
613      this.PhotoGridPageIndex = Constants.INVALID;
614
615      if (this.isFromFACard) {
616        if (this.isPullDown) {
617          this.isPullDown = false;
618          let context: common.UIAbilityContext = AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext;
619          context.terminateSelf();
620        } else {
621          let displayName: string = AppStorage.get<string>('form_displayName') as string;
622          let uri: string = AppStorage.get<string>('form_albumUri') as string;
623          let item: AlbumInfo = new AlbumInfo(undefined);
624          item.uri = uri;
625          item.albumName = displayName;
626          //item.innerId = uri;
627          router.replaceUrl({
628            url: 'pages/PhotoGridPage',
629            params: {
630              item: JSON.stringify(item),
631              isFromFACard: this.isFromFACard
632            }
633          });
634        }
635
636        if (this.geometryTransitionEnable) {
637          UiUtil.resetGeometryTransitionParams();
638        }
639        this.breakpointSystem.unregisterOrientationChange();
640        WindowUtil.setPreferredOrientation(AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext,
641          window.Orientation.UNSPECIFIED);
642        return;
643      }
644    } else if (this.checkedTransition === Constants.PHOTO_TRANSITION_CAMERA) {
645      Log.info(TAG, 'onBackPress Camera');
646      // Entering from the camera does not need to return to close directly
647      let context: common.UIAbilityContext = AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext;
648      context.terminateSelf();
649    } else if (this.checkedTransition === Constants.PHOTO_TRANSITION_THIRD_APP) {
650      Log.info(TAG, 'onBackPress third app');
651      this.setViewDataResult(true);
652    }
653    if (this.geometryTransitionEnable) {
654      this.browserController.hideBrowser();
655    } else {
656      router.back({
657        url: '',
658        params: {
659          index: this.currentIndex
660        }
661      });
662    }
663  }
664
665  updatePhotoName(result: TitleName): void {
666    let currentPhoto = this.getCurrentPhoto();
667    currentPhoto.setTitle(result.title);
668    currentPhoto.displayName = result.displayName;
669    this.appBroadCast.emit(BroadCastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
670  }
671
672  aboutToDisappear(): void {
673    Log.info(TAG, 'photoBrowser aboutToDisappear');
674    this.favorCacheItemsMap.forEach((item) => {
675      let menuFavorContext = new MenuContext().withMediaItem(item).withBroadCast(this.broadCast);
676      let menuFavorOperation = MenuOperationFactory.getInstance()
677        .createMenuOperation(FavoriteMenuOperation, menuFavorContext);
678      menuFavorOperation.doAction();
679    });
680
681    if (!this.isShowBar && !this.isHorizontal) {
682      ScreenManager.getInstance().setSystemUi(true);
683    }
684    // Click the thumbnail quickly, hasAppeared is false if it is not the first click. Return directly
685    if (!this.hasAppeared) {
686      return;
687    }
688    MediaObserver.getInstance().unregisterObserver(this.dataObserver);
689    this.dataObserver.clearSource();
690
691    if (!this.isFromFACard) {
692      this.breakpointSystem.unregisterOrientationChange();
693      WindowUtil.setPreferredOrientation(AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext,
694        window.Orientation.UNSPECIFIED);
695    }
696
697    this.broadCast.off(PhotoConstants.TOGGLE_BAR, this.onToggleBarsFunc);
698    this.broadCast.off(PhotoConstants.HIDE_BARS, this.hideBarsFunc);
699    this.broadCast.off(PhotoConstants.SHOW_BARS, this.showBarsFunc);
700    this.broadCast.off(PhotoConstants.PULL_DOWN_START, this.pullDownStartFunc);
701    this.broadCast.off(PhotoConstants.PULL_DOWN_END, this.pullDownEndFunc);
702    this.broadCast.off(PhotoConstants.DATA_SIZE_CHANGED, this.onDataSizeChangedFunc);
703    this.broadCast.off(PhotoConstants.DATA_CONTENT_CHANGED, this.onDataContentChangedFunc);
704    this.broadCast.off(PhotoConstants.SET_FAVOR, this.setFavorFunc);
705    this.broadCast.off(PhotoConstants.RENAME, this.doRenameFunc);
706    this.broadCast.off(PhotoConstants.ROTATE, this.doRotateFunc);
707    this.broadCast.off(PhotoConstants.PULL_DOWN_START, this.pullDownStartWithEventFunc);
708    this.broadCast.off(PhotoConstants.PULL_DOWN_CANCEL, this.pullDownCancelFunc);
709    this.broadCast.off(PhotoConstants.PHOTO_BROWSER_DELETE_CONFIRM, this.onPhotoBrowserDeleteConfirmFunc);
710    this.broadCast.off(PhotoConstants.PHOTO_BROWSER_REMOVE_CONFIRM, this.onPhotoBrowserRemoveConfirmFunc);
711    this.broadCast.off(PhotoConstants.DELETE, this.doDeleteFunc);
712    this.broadCast.off(PhotoConstants.PHOTO_SHOW_STATE, this.onPhotoShowStateChangedFunc);
713    this.broadCast.off(PhotoConstants.SET_DISABLE_SWIPE, this.setSwiperDisableFunc);
714    this.broadCast.off(BroadCastConstants.ON_DATA_RELOADED_WITH_EDIT, this.onDataReloadWithEditFunc);
715    this.appBroadCast.off(BroadCastConstants.PHOTO_BROWSER_BACK_PRESS_EVENT, this.photoBrowserBackFunc);
716  }
717
718  getAlbumUriByUri(albumUri: string) {
719    if (albumUri && albumUri.length > 0) {
720      return albumUri;
721    }
722
723    return "";
724  }
725
726  aboutToAppear(): void {
727    TraceControllerUtils.startTrace('PhotoBrowserAboutToAppear');
728    Log.info(TAG, 'photoBrowser aboutToAppear');
729    this.geometryTransitionId = AppStorage.get<string>('geometryTransitionBrowserId') as string;
730    this.hasAppeared = true;
731    this.updateIsHorizontal();
732
733    WindowUtil.setPreferredOrientation(AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext,
734      window.Orientation.AUTO_ROTATION_RESTRICTED);
735    this.appBroadCast.emit('hideBar', []);
736    let param: ParamBrowser = this.browserController.browserParam as ParamBrowser;
737    let entryFromCamera = (AppStorage.get<number>('entryFromHapCamera')) as number == Constants.ENTRY_FROM_CAMERA;
738    Log.info(TAG, `photoBrowser start with entryFrom ` + JSON.stringify(entryFromCamera));
739    if (entryFromCamera) {
740      param = {
741        pageFrom: Constants.ENTRY_FROM.CAMERA
742      } as ParamBrowser;
743      AppStorage.SetOrCreate('entryFromHapCamera', Constants.ENTRY_FROM_NONE);
744    }
745
746    if (param) {
747      Log.info(TAG, `photoBrowser start with param`);
748      Log.debug(TAG, `param: ${JSON.stringify(param)}`);
749      if (param.pageFrom) {
750        this.pageFrom = param.pageFrom;
751      }
752      if (param.albumInfo) {
753        this.albumInfo = param.albumInfo;
754        this.albumUri = param.albumInfo.uri;
755        this.deviceName = param.albumInfo.deviceName;
756      }
757      if (this.pageFrom == Constants.ENTRY_FROM.CAMERA) {
758        this.dataSource = new PhotoDataSource();
759        this.dataSource.initData();
760        this.isFromCamera = true;
761        this.clickThumbnailTime = param.clickThumbnailTime ? param.clickThumbnailTime : 0;
762        this.albumUri = "";
763        this.jumpSourceToMain = JumpSourceToMain.CAMERA;
764        MediaObserver.getInstance().registerObserver(this.dataObserver);
765        AppStorage.SetOrCreate('entryFromHap', Constants.ENTRY_FROM_NONE);
766      } else if (this.pageFrom == Constants.ENTRY_FROM.CARD) {
767        this.dataSource = new PhotoDataSource();
768        this.albumUri = param.albumUri;
769        this.dataSource.enableGetData(false);
770        this.dataSource.setAlbumUri(this.albumUri);
771        this.dataSource.initData();
772        this.isFromCamera = true;
773        this.jumpSourceToMain = JumpSourceToMain.CAMERA;
774        MediaObserver.getInstance().registerObserver(this.dataObserver);
775        this.uriFromThirdPartyApp = param.uri;
776        this.currentIndex = 0;
777        this.dataSource.getItemIndexByUri(this.uriFromThirdPartyApp, (index: number): void => this.onGetItemIndexByUri(index));
778        this.isFromFACard = true;
779        this.geometryTransitionEnable = true;
780      } else if (this.pageFrom == Constants.ENTRY_FROM.RECYCLE) {
781        this.dataSource.setAlbumUri(this.albumUri);
782        this.dataSource.setAlbumDataSource(AppStorage.get<MediaDataSource>(Constants.APP_KEY_PHOTO_BROWSER) as MediaDataSource);
783      } else if (this.pageFrom == Constants.ENTRY_FROM.DISTRIBUTED) {
784        this.dataSource.setDeviceId(param.albumInfo.deviceId);
785        this.dataSource.setAlbumDataSource(AppStorage.get<MediaDataSource>(Constants.APP_KEY_PHOTO_BROWSER) as MediaDataSource);
786      } else if (this.pageFrom == Constants.ENTRY_FROM.VIEW_DATA) {
787        if (String(param.viewData).length === 0) {
788          Log.error(TAG, 'Invalid uri');
789          this.setViewDataResult(false);
790          return;
791        }
792        Log.info(TAG, `Found viewIndex: ${String(param.viewDataIndex).length}`);
793        if (String(param.viewDataIndex).length > 0) {
794          Log.debug(TAG, `Found viewIndex`);
795          this.dataSource = new UriDataSource(String(param.viewData).split('?'));
796          let viewIndex = Number.parseInt(param.viewDataIndex);
797          if (Number.isNaN(viewIndex) || viewIndex <= 0 || viewIndex > String(param.viewData).split('?').length) {
798            viewIndex = 0;
799          } else {
800            viewIndex -= 1;
801          }
802          this.isFromViewDataWithThirdUri = true;
803          this.currentIndex = viewIndex;
804          param.position = viewIndex;
805        } else {
806          let uriCount = String(param.viewData).split(',').length;
807          if (uriCount > Constants.NUMBER_1) {
808            Log.error(TAG, 'Invalid uri');
809            this.setViewDataResult(false);
810            return;
811          }
812
813          if (String(param.viewData).startsWith(PhotoDataSource.MEIDA_URL_PREFIX_STR) ||
814          String(param.viewData).startsWith(PhotoDataSource.IMAGE_URL_PREFIX_STR_V10) ||
815          String(param.viewData).startsWith(PhotoDataSource.VIDEO_URL_PREFIX_STR_V10) ||
816          String(param.viewData).startsWith(PhotoDataSource.IMAGE_VIDEO_URL_PREFIX_STR_V10)) {
817            Log.debug(TAG, `Found media library uri`);
818            this.dataSource = new PhotoDataSource(this.albumUri);
819            this.albumUri = this.getAlbumUriByUri(param.viewDataAlbum);
820            Log.info(TAG, `album id: ${this.albumUri}`);
821            this.dataSource.enableGetData(false);
822            this.dataSource.setAlbumUri(this.albumUri);
823            this.dataSource.initData();
824            this.isFromViewDataWithMediaUri = true;
825            this.clickThumbnailTime = 0;
826            this.jumpSourceToMain = JumpSourceToMain.CAMERA;
827            MediaObserver.getInstance().registerObserver(this.dataObserver);
828            this.uriFromThirdPartyApp = String(param.viewData);
829            this.currentIndex = 0;
830            this.dataSource.getItemIndexByUri(this.uriFromThirdPartyApp, (index: number): void => this.onGetItemIndexByUri(index));
831            // 是否显示菜单栏并且处理大数据打点
832            this.isShowMenuBigData(param.isShowMenuFromThirdView);
833          } else {
834            Log.debug(TAG, `Not found media library uri`);
835            this.dataSource = new UriDataSource(String(param.viewData).split(','));
836            this.isFromViewDataWithThirdUri = true;
837          }
838        }
839      } else {
840        MediaObserver.getInstance().registerObserver(this.dataObserver);
841        this.dataSource.setAlbumDataSource(AppStorage.get<MediaDataSource>(Constants.APP_KEY_PHOTO_BROWSER) as MediaDataSource);
842      }
843
844      this.onPhotoChanged(param.position || 0);
845      if (this.isFromFACard) {
846        this.mTransition = Constants.PHOTO_TRANSITION_ALBUM;
847      } else if (this.isFromCamera) {
848        this.mTransition = Constants.PHOTO_TRANSITION_CAMERA;
849      } else if (this.isFromViewDataWithMediaUri || this.isFromViewDataWithThirdUri) {
850        this.mTransition = Constants.PHOTO_TRANSITION_THIRD_APP;
851      } else {
852        this.mTransition = param.transition;
853      }
854    } else {
855      Log.info(TAG, `photoBrowser start without param`);
856      if (this.entryFromHap == Constants.ENTRY_FROM_FORM_ABILITY) {
857        this.pageFrom = Constants.ENTRY_FROM.CARD;
858        this.albumUri = AppStorage.get<string>('form_albumUri') as string;
859      } else {
860        this.pageFrom = Constants.ENTRY_FROM.CAMERA;
861        this.albumUri = UserFileManagerAccess.getInstance()
862          .getSystemAlbumUri(UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE);
863      }
864      AppStorage.SetOrCreate('entryFromHap', Constants.ENTRY_FROM_NONE);
865      let albumDataSource: MediaDataSource = AppStorage.get<MediaDataSource>(Constants.APP_KEY_PHOTO_BROWSER) as MediaDataSource;
866      if (albumDataSource) {
867        this.dataSource.setAlbumDataSource(albumDataSource);
868      } else {
869        Log.error(TAG, `Constants.APP_KEY_PHOTO_BROWSER is null, so use all album instead`);
870        this.dataSource.initData();
871      }
872      this.isFromCamera = true;
873      this.jumpSourceToMain = JumpSourceToMain.CAMERA;
874      MediaObserver.getInstance().registerObserver(this.dataObserver);
875      this.onPhotoChanged(AppStorage.Get('form_currentIndex') || 0);
876      this.mTransition = Constants.PHOTO_TRANSITION_CAMERA;
877    }
878
879    this.checkedTransition = this.mTransition
880
881    if (this.mTransition.endsWith('ERROR')) {
882      this.checkedTransition = this.mTransition.substr(0, this.mTransition.length - 5)
883    }
884
885    this.dataSource.setBroadCast(this.broadCast);
886    this.dataSource.setBroadCastToAlbum(this.broadCast);
887
888    // register event handling
889    this.broadCast.on(PhotoConstants.TOGGLE_BAR, this.onToggleBarsFunc);
890    this.broadCast.on(PhotoConstants.HIDE_BARS, this.hideBarsFunc);
891    this.broadCast.on(PhotoConstants.SHOW_BARS, this.showBarsFunc);
892    this.broadCast.on(PhotoConstants.PULL_DOWN_START, this.pullDownStartFunc);
893    this.broadCast.on(PhotoConstants.PULL_DOWN_END, this.pullDownEndFunc);
894    this.broadCast.on(PhotoConstants.DATA_SIZE_CHANGED, this.onDataSizeChangedFunc);
895    this.broadCast.on(PhotoConstants.DATA_CONTENT_CHANGED, this.onDataContentChangedFunc);
896    this.broadCast.on(PhotoConstants.SET_FAVOR, this.setFavorFunc);
897    this.broadCast.on(PhotoConstants.RENAME, this.doRenameFunc);
898    this.broadCast.on(PhotoConstants.ROTATE, this.doRotateFunc);
899    this.broadCast.on(PhotoConstants.PULL_DOWN_START, this.pullDownStartWithEventFunc);
900    this.broadCast.on(PhotoConstants.PULL_DOWN_CANCEL, this.pullDownCancelFunc);
901    this.broadCast.on(PhotoConstants.PHOTO_BROWSER_DELETE_CONFIRM, this.onPhotoBrowserDeleteConfirmFunc);
902    this.broadCast.on(PhotoConstants.PHOTO_BROWSER_REMOVE_CONFIRM, this.onPhotoBrowserRemoveConfirmFunc);
903    this.broadCast.on(PhotoConstants.DELETE, this.doDeleteFunc);
904    this.broadCast.on(PhotoConstants.PHOTO_SHOW_STATE, this.onPhotoShowStateChangedFunc);
905    this.broadCast.on(PhotoConstants.SET_DISABLE_SWIPE, this.setSwiperDisableFunc);
906    this.broadCast.on(BroadCastConstants.ON_DATA_RELOADED_WITH_EDIT, this.onDataReloadWithEditFunc);
907
908    this.appBroadCast.on(BroadCastConstants.PHOTO_BROWSER_BACK_PRESS_EVENT, this.photoBrowserBackFunc);
909
910    interface MsgNavigation {
911      from: string;
912      fovMode: number;
913    }
914
915    let msg: MsgNavigation = {
916      from: BigDataConstants.LOCAL_MEDIA,
917      fovMode: 0
918    }
919    ReportToBigDataUtil.report(BigDataConstants.ENTER_PHOTO_BROWSER_ID, msg);
920    this.breakpointSystem.registerOrientationChange();
921    TraceControllerUtils.finishTrace('PhotoBrowserAboutToAppear');
922  }
923
924  onToggleBars(backgroundColorResource?: Resource): void {
925    if (this.isShowBar) {
926      this.hideBars(backgroundColorResource);
927    } else {
928      this.showBars(backgroundColorResource);
929    }
930    Log.info(TAG, `Toggle bars, isShowBar: ${this.isShowBar}`);
931  }
932
933  showBars(backgroundColorResource?: Resource): void {
934    this.backgroundColorResource = backgroundColorResource ?
935      backgroundColorResource : $r('app.color.default_background_color');
936    if (!this.isShowBar) {
937      this.isShowBar = !this.isShowBar;
938      if (!this.isHorizontal) {
939        ScreenManager.getInstance().setSystemUi(true);
940      }
941    } else {
942      this.onlyChangeBgColor = !this.onlyChangeBgColor;
943    }
944  }
945
946  hideBars(backgroundColorResource?: Resource): void {
947    this.backgroundColorResource = backgroundColorResource ?
948      backgroundColorResource : $r('app.color.black');
949    if (this.isShowBar) {
950      this.isShowBar = !this.isShowBar;
951      ScreenManager.getInstance().setSystemUi(false);
952    } else {
953      this.onlyChangeBgColor = !this.onlyChangeBgColor;
954    }
955  }
956
957  private pullDownStart(): void {
958    Log.info(TAG, 'pulling down start');
959  }
960
961  private pullDownEnd(): void {
962    Log.info(TAG, 'pulling down end');
963    if (this.isFromFACard) {
964      this.isPullDown = true;
965    }
966    this.onBackPress();
967  }
968
969  private onDataContentChanged(): void {
970    this.reportToBigDataForCameraIn();
971    Log.debug(TAG, `PhotoConstants.DATA_CONTENT_CHANGED`);
972    this.onPhotoChanged(this.currentIndex);
973  }
974
975  private setFavor(isFavor: boolean): void {
976    Log.debug(TAG, 'set favor !')
977    let currentPhoto = this.getCurrentPhoto();
978    if (!isFavor) {
979      currentPhoto.isFavor = isFavor;
980      this.updateMenu();
981    } else {
982      Log.debug(TAG, 'update favor !');
983    }
984  }
985
986  private doRename(result: TitleName): void {
987    Log.info(TAG, `rename refresh: ${result.title}, ${result.displayName}`);
988    this.updatePhotoName(result);
989  }
990
991  private doRotate(result: number): void {
992    Log.debug(TAG, `rotate finish: ${result}`);
993    let currentPhoto = this.getCurrentPhoto();
994    currentPhoto.orientation = result;
995    let temp = currentPhoto.height;
996    currentPhoto.height = currentPhoto.width;
997    currentPhoto.width = temp;
998    this.dataSource.onDataChanged(this.currentIndex);
999    this.appBroadCast.emit(BroadCastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
1000  }
1001
1002  private pullDownStartWithEvent(event: KeyEvent): void {
1003    Log.debug(TAG, `pulling down start : ${JSON.stringify(event)}`);
1004    if (this.isFromViewDataWithThirdUri) {
1005      return;
1006    }
1007  }
1008
1009  private pullDownCancel(): void {
1010    Log.info(TAG, 'pulling down cancel');
1011  }
1012
1013  private onPhotoBrowserDeleteConfirm(): void {
1014    this.isDeleting = true;
1015    // clear temp not favorite items
1016    if (this.albumUri == UserFileManagerAccess.getInstance()
1017      .getSystemAlbumUri(UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE)) {
1018      let key = this.theDeleteItem?.uri ?? '';
1019      if (this.favorCacheItemsMap.has(key)) {
1020        let item = this.favorCacheItemsMap.get(key)
1021        let menuFavorContext = new MenuContext().withMediaItem(item as MediaItem).withBroadCast(this.broadCast);
1022        let menuFavorOperation = MenuOperationFactory.getInstance()
1023          .createMenuOperation(FavoriteMenuOperation, menuFavorContext);
1024        menuFavorOperation.doAction();
1025        this.favorCacheItemsMap.delete(key);
1026      }
1027    }
1028  }
1029
1030  private onPhotoBrowserRemoveConfirm(): void {
1031    this.isDeleting = true;
1032  }
1033
1034  private doDelete(): void {
1035    Log.info(TAG, 'delete finish now update data');
1036  }
1037
1038  private onPhotoShowStateChanged(state: boolean): void {
1039    Log.debug(TAG, 'current photo show state change');
1040    this.currentShow = state;
1041  }
1042
1043  private setSwiperDisable(value: boolean): void {
1044    Log.info(TAG, `set swiper swipe ${value}`);
1045    this.canSwipe = value;
1046  }
1047
1048  private onDataReloadWithEdit(): void {
1049    Log.debug(TAG, 'animate to data reloaded start with edit');
1050    try {
1051      let uri: string = AppStorage.get<string>(BroadCastConstants.PHOTO_EDIT_SAVE_URI) as string;
1052      Log.debug(TAG, `data reloaded start with edit by uri ${uri}`);
1053      if (uri) {
1054        let newIndex = this.dataSource.getDataIndexByUri(uri);
1055        let oldIndex = this.currentIndex;
1056        if (newIndex != Constants.NOT_FOUND) {
1057          // Search for the position of new image/video after edit in current 500 items succeed
1058          Log.debug(TAG, `data reloaded from ${oldIndex} move to ${newIndex}`);
1059          this.onPhotoChanged(newIndex);
1060        } else {
1061          // Search for the position of new image/video after edit in current 500 items failed
1062          Log.debug(TAG, `data reloaded from ${oldIndex} move to unknown`);
1063          this.editNewUri = uri;
1064          this.dataSource.enableGetData(false);
1065          this.currentIndex = 0;
1066          this.dataSource.getItemIndexByUri(uri, (index: number): void => this.onGetItemIndexByNewEditUri(index));
1067        }
1068      }
1069    } catch (e) {
1070      Log.error(TAG, `ON_DATA_RELOADED_WITH_EDIT error ${e}`);
1071    } finally {
1072      this.appBroadCast.emit(BroadCastConstants.PHOTO_EDIT_SAVE_COMPLETE, []);
1073    }
1074  }
1075
1076  private photoBrowserBack(): void {
1077    Log.debug(TAG, 'hook back press from page.');
1078    this.onBackPress();
1079  }
1080
1081  onGetItemIndexByUri(index: number): void {
1082    Log.info(TAG, `onGetItemIndexByUri: index=${index}`);
1083    if (this.uriFromThirdPartyApp) {
1084      if (index != Constants.NOT_FOUND) {
1085        this.currentIndex = index;
1086        this.uriFromThirdPartyApp = '';
1087        this.dataSource.enableGetData(true);
1088        this.dataSource.getData(this.currentIndex);
1089        this.dataSource.onDataReloaded();
1090        Log.info(TAG, `Found: ${this.currentIndex}, ${this.albumUri}`);
1091      } else {
1092        if (this.albumUri === UserFileManagerAccess.getInstance()
1093          .getSystemAlbumUri(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE)) {
1094          if (this.isFromViewDataWithMediaUri || this.isFromViewDataWithThirdUri) {
1095            Log.error(TAG, `Uri from third party app is invalid`);
1096          } else if (this.isFromFACard) {
1097            Log.error(TAG, `Uri from FA is invalid`);
1098          } else {
1099            Log.error(TAG, `Uri from others is invalid`);
1100          }
1101          this.uriFromThirdPartyApp = '';
1102          this.dataSource.enableGetData(true);
1103          this.setViewDataResult(false);
1104        } else if (this.albumUri === "") {
1105          this.resetAlbum(UserFileManagerAccess.getInstance()
1106            .getSystemAlbumUri(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE));
1107          this.dataSource.getItemIndexByUri(this.uriFromThirdPartyApp, (index: number): void => this.onGetItemIndexByUri(index));
1108        } else {
1109          this.resetAlbum("");
1110          this.dataSource.getItemIndexByUri(this.uriFromThirdPartyApp, (index: number): void => this.onGetItemIndexByUri(index));
1111        }
1112      }
1113      this.onPhotoChanged(this.currentIndex);
1114    }
1115  }
1116
1117  onGetItemIndexByNewEditUri(index: number): void {
1118    Log.info(TAG, `onGetItemIndexByNewEditUri: index=${index}`);
1119    if (this.editNewUri.length > 0) {
1120      if (index != Constants.NOT_FOUND) {
1121        Log.info(TAG, `data reloaded move to ${index}`);
1122        this.currentIndex = index;
1123        if (this.checkedTransition == Constants.PHOTO_TRANSITION_TIMELINE) {
1124          this.TimelinePageIndex = this.currentIndex; // call scrollTo
1125          this.TimelinePageIndex = Constants.INVALID;
1126        } else if (this.checkedTransition == Constants.PHOTO_TRANSITION_ALBUM) {
1127          this.PhotoGridPageIndex = this.currentIndex; // call scrollTo
1128          this.PhotoGridPageIndex = Constants.INVALID;
1129        }
1130        this.dataSource.enableGetData(true);
1131        this.dataSource.getData(this.currentIndex);
1132        this.dataSource.onDataReloaded();
1133        this.editNewUri = "";
1134      } else {
1135        Log.error(TAG, `edit new uri ${this.editNewUri} is invalid`);
1136        this.editNewUri = "";
1137        this.currentIndex = 0;
1138        this.dataSource.enableGetData(true);
1139      }
1140      this.onPhotoChanged(this.currentIndex);
1141    }
1142  }
1143
1144  onPageShow(): void {
1145    TraceControllerUtils.startTrace('PhotoBrowseronPageShow');
1146    Log.info(TAG, 'photoBrowser page show');
1147    WindowUtil.setPreferredOrientation(AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext,
1148      window.Orientation.AUTO_ROTATION_RESTRICTED);
1149    let currentPhoto = this.getCurrentPhoto();
1150    if (currentPhoto) {
1151      this.syncPhotoName(currentPhoto).then((result) => {
1152        if (result) {
1153          this.updatePhotoName(result);
1154          this.broadCast.emit(PhotoConstants.UPDATE_PHOTO_NAME + currentPhoto.uri, [result.title]);
1155        }
1156      });
1157    }
1158    this.updateActionBar();
1159    if (!this.isHorizontal) {
1160      ScreenManager.getInstance().setSystemUi(true);
1161    }
1162    this.appBroadCast.emit(BroadCastConstants.THIRD_ROUTE_PAGE, []);
1163    this.appBroadCast.emit(BroadCastConstants.PHOTO_BROWSER_ACTIVE, [true, this.checkedTransition]);
1164    this.broadCast.emit(BroadCastConstants.CHANGE_SWIPER_DURATION, [400]);
1165    this.viewTime = Date.now();
1166    let params: Params = router.getParams() as Params;
1167    if (params != null && params.pageType != null && this.backFromCopy) {
1168      Log.debug(TAG, `MediaOperation back ${JSON.stringify(params)}`)
1169      let menuContext = new MenuContext();
1170      let menuOperation: MenuOperation | null = null;
1171      if (currentPhoto == undefined) {
1172        Log.error(TAG, 'MediaOperation currentPhoto is undefined');
1173        return;
1174      }
1175      if (params.pageType === MediaOperationType.Move) {
1176        let onMoveEndFunc = async (err: Error, count: number, total: number): Promise<void> => {
1177          await this.onMoveEnd(err as Object, count, total)};
1178        menuContext.withMediaItem(currentPhoto)
1179          .withBroadCast(this.broadCast)
1180          .withTargetAlbumName(params.albumName)
1181          .withAlbumUri(params.albumUri)
1182          .withOperationEndCallback(onMoveEndFunc);
1183        menuOperation = MenuOperationFactory.getInstance().createMenuOperation(MoveMenuOperation, menuContext);
1184        AppStorage.setOrCreate<string | undefined>(Constants.APP_KEY_NEW_ALBUM_SOURCE, this.albumInfo?.uri);
1185      } else if (params.pageType === MediaOperationType.Remove) {
1186        let onMoveEndFunc = async (err: Error, count: number, total: number): Promise<void> => {
1187          await this.onMoveEnd(err as Object, count, total)};
1188        menuContext.withMediaItem(currentPhoto)
1189          .withBroadCast(this.broadCast)
1190          .withTargetAlbumName(params.albumName)
1191          .withAlbumUri(params.albumUri)
1192          .withOperationEndCallback(onMoveEndFunc);
1193        menuOperation = MenuOperationFactory.getInstance().createMenuOperation(RemoveMenuOperation, menuContext);
1194        AppStorage.setOrCreate<string | undefined>(Constants.APP_KEY_NEW_ALBUM_SOURCE, this.albumInfo?.uri);
1195      } else if (params.pageType === MediaOperationType.Add) {
1196        // "添加到"不需要设置源相册
1197        let onCopyEndFunc = (err: Error, count: number, total: number): void => {
1198          this.onCopyEnd(err as Object, count, total)};
1199        menuContext.withMediaItem(currentPhoto)
1200          .withBroadCast(this.broadCast)
1201          .withTargetAlbumName(params.albumName)
1202          .withAlbumUri(params.albumUri)
1203          .withOperationEndCallback(onCopyEndFunc);
1204        menuOperation = MenuOperationFactory.getInstance().createMenuOperation(AddMenuOperation, menuContext);
1205        this.appBroadCast.emit(BroadCastConstants.PHOTO_BROWSER_ACTIVE, [false, this.checkedTransition]);
1206      }
1207
1208      if (menuOperation != null) {
1209        menuOperation.doAction();
1210      }
1211    }
1212    this.backFromCopy = false;
1213    TraceControllerUtils.finishTrace('PhotoBrowseronPageShow');
1214  }
1215
1216  onPageHide(): void {
1217    Log.info(TAG, `call onPageHide`);
1218    this.appBroadCast.emit(BroadCastConstants.PHOTO_BROWSER_ACTIVE, [false, this.checkedTransition]);
1219    WindowUtil.setPreferredOrientation(AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext,
1220      window.Orientation.UNSPECIFIED);
1221  }
1222
1223  onMediaLibDataChange(changeType: string): void {
1224    Log.info(TAG, `onMediaLibDataChange type: ${changeType}`);
1225    this.dataSource.onChange(changeType);
1226  }
1227
1228  build() {
1229    Stack({ alignContent: Alignment.TopStart }) {
1230      PhotoBrowserComponentBg({ isShowBar: $isShowBar, isFromPhotoBrowser: true })
1231        .opacity(this.geometryOpacity)
1232        .transition(TransitionEffect.opacity(0))
1233
1234      PhotoSwiper({
1235        dataSource: this.dataSource,
1236        mTransition: this.mTransition,
1237        swiperController: this.controller,
1238        onPhotoChanged: (index: number): void => this.onPhotoChanged(index),
1239        geometryTransitionEnable: this.geometryTransitionEnable,
1240        broadCast: $broadCast,
1241        isRunningAnimation: $isRunningAnimation,
1242        isFromFACard: this.isFromFACard
1243      })
1244
1245      if (!this.isFromViewDataWithThirdUri) {
1246        PhotoBrowserActionBar({
1247          onMenuClicked: (action: Action): void => this.onMenuClicked(action),
1248        })
1249          .opacity(this.geometryOpacity)
1250          .transition(TransitionEffect.opacity(0))
1251
1252        if (!this.isHorizontal) {
1253          PhotoBrowserToolBar({
1254            onMenuClicked: (action: Action): void => this.onMenuClicked(action),
1255            isFromPhotoBrowser: true
1256          })
1257            .opacity(this.geometryOpacity)
1258            .transition(TransitionEffect.opacity(0))
1259            .markAnchor({ x: Constants.PERCENT_0, y: Constants.PERCENT_100 })
1260            .position({ x: Constants.PERCENT_0, y: Constants.PERCENT_100 })
1261        }
1262
1263        CustomDialogView({ broadCast: $broadCast })
1264          .opacity(this.geometryOpacity)
1265          .transition(TransitionEffect.opacity(0))
1266
1267      } else {
1268        PhotoBrowserActionBar({
1269          onMenuClicked: (action: Action): void => this.onMenuClicked(action),
1270        })
1271          .opacity(this.geometryOpacity)
1272          .transition(TransitionEffect.opacity(0))
1273      }
1274    }
1275  }
1276
1277  private setViewDataResult(result: boolean): void {
1278    if (!this.isFromViewDataWithMediaUri && !this.isFromViewDataWithThirdUri) {
1279      return;
1280    }
1281
1282    let resultCode = 0;
1283    if (result == false) {
1284      resultCode = -1;
1285    }
1286
1287    let abilityResult: ability.AbilityResult = {
1288      resultCode: resultCode,
1289      want: {}
1290    };
1291
1292    let context: common.UIAbilityContext = AppStorage.get<common.UIAbilityContext>('photosAbilityContext') as common.UIAbilityContext;
1293    context.terminateSelfWithResult(abilityResult).then((result: void) => {
1294      Log.info(TAG, `terminateSelfWithResult result: ${result}`);
1295    });
1296  }
1297
1298  private downLoad(): void {
1299    Log.info(TAG, 'downLoad run');
1300    let menuContext = new MenuContext();
1301    let menuOperation: MenuOperation;
1302    let currentPhoto = this.getCurrentPhoto();
1303    let onDownloadEndFunc = async (err: Error, count: number, total: number): Promise<void> => {
1304      await this.onDownloadEnd(err as Object, count, total)};
1305    if (currentPhoto == undefined) {
1306      Log.error(TAG, 'MediaOperation currentPhoto is undefined');
1307      return;
1308    }
1309    menuContext
1310      .withMediaItem(currentPhoto)
1311      .withBroadCast(this.broadCast)
1312      .withRemoteDevice('0') // TODO input deviceId
1313      .withOperationEndCallback(onDownloadEndFunc)
1314    menuOperation = MenuOperationFactory.getInstance().createMenuOperation(AddMenuOperation, menuContext);
1315    this.appBroadCast.emit(BroadCastConstants.PHOTO_BROWSER_ACTIVE, [false, this.checkedTransition]);
1316    menuOperation.doAction();
1317  }
1318
1319  private reportToBigDataForPhotoSlide(index: number): void {
1320    let currentPhoto = this.getCurrentPhoto();
1321    if (currentPhoto && index != this.currentIndex && this.viewTime != 0) {
1322      let currentTime = Date.now();
1323      interface Msg {
1324        type: string;
1325        duration: number;
1326      }
1327      let msg: Msg = {
1328        type: currentPhoto.mediaType == UserFileManagerAccess.MEDIA_TYPE_VIDEO ?
1329        BigDataConstants.VIDEO : BigDataConstants.NORMAL_PHOTO,
1330        duration: (currentTime - this.viewTime)
1331      }
1332      ReportToBigDataUtil.report(BigDataConstants.PHOTO_BROWSER_SLIDE_ID, msg);
1333      this.viewTime = Date.now();
1334    }
1335  }
1336
1337  private reportToBigDataForCameraIn(): void {
1338    if (this.clickThumbnailTime == 0 || !this.isFromCamera) {
1339      return;
1340    }
1341    interface Msg {
1342      clickThumbnailTime: number;
1343      ShowSinglePhoto: number;
1344      FileName?: string;
1345    }
1346    let msg: Msg = {
1347      clickThumbnailTime: this.clickThumbnailTime,
1348      ShowSinglePhoto: Date.now()
1349    }
1350    let fileName = ReportToBigDataUtil.getFileNameOfPhotoTakenByCamera(this.getPhotoByIndex(0));
1351    ReportToBigDataUtil.setFileNameProperty(msg, fileName);
1352    ReportToBigDataUtil.report(BigDataConstants.BROWSE_PHOTO_FROM_CAMERA_ID, msg);
1353    this.clickThumbnailTime = 0;
1354  }
1355
1356  private async syncPhotoName(currentPhoto: MediaItem): Promise<TitleName> {
1357    Log.debug(TAG, 'syncPhotoName start');
1358    let renameResult: TitleName = {title: '', displayName: ''};
1359    let fileAsset = await this.dataSource.getDataByUri(currentPhoto.uri);
1360    if (fileAsset) {
1361      renameResult = {
1362        title: fileAsset.get(UserFileManagerAccess.FILE_KEY_TITLE.toString()) as string,
1363        displayName: fileAsset.displayName
1364      };
1365    } else {
1366      let key: string = 'renameResult' + currentPhoto.uri;
1367      renameResult = AppStorage.get<TitleName>(key) as TitleName;
1368      AppStorage.Delete(key);
1369    }
1370    Log.debug(TAG, `syncPhotoName end, renameResult : ${JSON.stringify(renameResult)}`);
1371    return renameResult;
1372  }
1373}
1374