• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import router from '@system.router';
17import Want from '@ohos.application.Want';
18import MediaLib from '@ohos.multimedia.mediaLibrary';
19import { Log } from '@ohos/base/src/main/ets/utils/Log';
20import { Action } from '../../../common/view/browserOperation/Action';
21import type { MenuOperation } from '@ohos/base/src/main/ets/operation/MenuOperation';
22import { MenuContext } from '@ohos/base/src/main/ets/operation/MenuContext';
23import {
24    GotoPhotosMenuOperation
25} from '@ohos/browser/src/main/ets/operation/GotoPhotosMenuOperation';
26import { BatchDeleteMenuOperation } from '@ohos/base/src/main/ets/operation/BatchDeleteMenuOperation';
27import { BatchRecoverMenuOperation } from '@ohos/base/src/main/ets/operation/BatchRecoverMenuOperation';
28import { ClearRecycleMenuOperation } from '@ohos/base/src/main/ets/operation/ClearRecycleMenuOperation';
29import { MediaConstants } from '@ohos/base/src/main/ets/constants/MediaConstants';
30import { MoveMenuOperation } from '@ohos/base/src/main/ets/operation/MoveMenuOperation';
31import { CopyMenuOperation } from '@ohos/base/src/main/ets/operation/CopyMenuOperation';
32import { DateUtil } from '@ohos/base/src/main/ets/utils/DateUtil';
33import { CustomDialogView } from '../../../common/view/dialog/CustomDialogView';
34import { Constants } from '../../../common/model/common/Constants';
35import { Broadcast } from '@ohos/base/src/main/ets/utils/Broadcast';
36import { BroadcastConstants } from '@ohos/base/src/main/ets/constants/BroadcastConstants';
37import broadcastManager from '@ohos/base/src/main/ets/manager/BroadcastManager';
38import { Constants as PhotoConstants } from '@ohos/browser/src/main/ets/constants/Constants';
39import { PhotoBrowserBg } from '@ohos/browser/src/main/ets/components/PhotoBrowserBg';
40import { PhotoBrowserActionBar } from './PhotoBrowserActionBar';
41import { ToolBar } from '../../../common/view/actionbar/ToolBar';
42import { PhotoSwiper } from '@ohos/browser/src/main/ets/components/PhotoSwiper';
43import screenManager from '@ohos/base/src/main/ets/manager/ScreenManager';
44import { JumpSourceToMain } from '@ohos/base/src/main/ets/data/JumpSourceToMain';
45import { RenameMenuOperation } from '@ohos/browser/src/main/ets/operation/RenameMenuOperation';
46import { MediaOperationType } from '@ohos/base/src/main/ets/data/MediaOperationType';
47import { showToast } from '@ohos/base/src/main/ets/utils/UiUtil';
48import { getResourceString } from '@ohos/base/src/main/ets/utils/ResourceUtils';
49import { CommonObserverCallback } from '@ohos/base/src/main/ets/observer/CommonObserverCallback';
50import mediaObserver from '@ohos/base/src/main/ets/observer/MediaObserver';
51import mMultimodalInputManager from '@ohos/base/src/main/ets/manager/MultimodalInputManager';
52import { startTrace, finishTrace } from '@ohos/base/src/main/ets/utils/TraceControllerUtils';
53import { GroupItemDataSource } from '@ohos/base/src/main/ets/vm/GroupItemDataSource';
54import { MediaDataItem } from '@ohos/base/src/main/ets/data/MediaDataItem';
55import { InnerMediaDataItem } from '@ohos/browser/src/main/ets/data/InnerMediaDataItem';
56import { SimpleAlbumDataItem } from '@ohos/base/src/main/ets/data/SimpleAlbumDataItem';
57import { getAlbumDisplayName } from '@ohos/base/src/main/ets/helper/MediaDataHelper';
58import { startAbility, terminateSelf } from '@ohos/base/src/main/ets/utils/AbilityUtils';
59import mediaDataItemCache from '@ohos/base/src/main/ets/data/MediaDataItemCache';
60import { PhotoEditorManager } from '../../editor/PhotoEditorManager';
61// page of large photo
62
63const TAG = "PhotoBrowser"
64
65@Entry
66@Component
67struct PhotoBrowser {
68    @State mOpacity: number = 1;
69    @Provide browserBackgroundColor: Resource = $r('app.color.default_background_color');
70    @Provide('dateTitle') photoDate: string = '';
71    @Provide('timeLocationTitle') timeAndLocation: string = '';
72    @Provide menuList: Array<Action> = new Array<Action>();
73    @State toolMenuList: Array<Action> = new Array<Action>();
74    @Provide topMenuList: Array<Action> = new Array<Action>();
75    @Provide moreMenuList: Array<Action> = new Array<Action>();
76    @Provide broadCast: Broadcast = new Broadcast();
77    @Provide isShowBar: boolean = true;
78    @Provide isPullingDown: boolean = false;
79    @Provide pageFrom: number = Constants.ENTRY_FROM.NORMAL;
80    @Provide canSwipe: boolean = false;
81    private timeoutId: number = 0;
82    @State @Watch('currentShowChange') currentShow: boolean = true;
83    @StorageLink('isHorizontal') isHorizontal: boolean = screenManager.isHorizontal();
84    @StorageLink('TimelinePageIndex') TimelinePageIndex: number = Constants.INVALID;
85    @StorageLink('PhotoGridPageIndex') PhotoGridPageIndex: number = Constants.INVALID;
86    @StorageLink('isSplitMode') isSplitMode: boolean = screenManager.isSplitMode();
87    @StorageLink('leftBlank') leftBlank: [number, number, number, number] = [0, 0, 0, 0];
88    @StorageLink('entryFromHap') entryFromHap: number = Constants.ENTRY_FROM_NONE;
89    photoBrowserTransition: string;
90    @State isDataChanged:boolean = true;
91    private isFromCard = false;
92
93    // swiper currentIndex, there may not be onChanged callback during data refresh, so mediaItem cannot be saved
94    @Provide('transitionIndex') currentIndex: number = 0;
95    controller: SwiperController = new SwiperController();
96    private dataObserver: CommonObserverCallback = new CommonObserverCallback(this);
97
98    // The global Broadcast of the application process. Event registration and destruction should be paired
99    private appBroadcast: Broadcast = broadcastManager.getBroadcast();
100    private isFromCamera = false;
101    private isFromViewData = false;
102
103    // the source of jump to the index page
104    private jumpSourceToMain: number = JumpSourceToMain.None;
105
106    // time to view the current picture
107    private checkedTransition: string;
108
109    // When clicking quickly, only run aboutToAppear for the first time
110    private hasAppeared: boolean;
111    private albumInfo: SimpleAlbumDataItem;
112    private deviceName = '';
113    private backFromCopy = false;
114    private pullDownFlag: boolean = false;
115    private browserDataSource: GroupItemDataSource = new GroupItemDataSource()
116    private isToEdit = false;
117
118    onMenuClicked(action: Action) {
119        Log.info(TAG, `onMenuClicked, action: ${action.actionID}, isPullingDown: ${this.isPullingDown}`);
120        if (this.isPullingDown) {
121            return;
122        }
123        let menuOperation: MenuOperation;
124        let menuContext: MenuContext = new MenuContext();
125        let currentPhoto = this.getCurrentPhoto();
126        switch (action) {
127            case Action.BACK:
128                this.onBackPress();
129                return;
130            case Action.INFO:
131                if (currentPhoto == undefined) {
132                    return;
133                }
134                this.broadCast.emit(BroadcastConstants.SHOW_DETAIL_DIALOG, [currentPhoto, this.pageFrom == Constants.ENTRY_FROM.DISTRIBUTED]);
135                return;
136            case Action.SHARE:
137                if (currentPhoto == undefined) {
138                    return;
139                }
140                let want: Want = {
141                    'action': 'com.huawei.intent.action.hwCHOOSER',
142                    'parameters': {
143                        'ability.want.params.INTENT': {
144                            'action': 'ability.intent.SEND_DATA',
145                            'type': '*/*',
146                            'parameters': {
147                                'ability.params.stream': currentPhoto.uri
148                            }
149                        }
150                    }
151                }
152                startAbility(want)
153                return;
154            case Action.NOT_FAVORITE:
155            case Action.FAVORITE:
156                if (currentPhoto == undefined) {
157                    return;
158                }
159                currentPhoto.setFavor().then((isSuccess: boolean) => this.setFavourite(isSuccess))
160                return;
161            case Action.DELETE:
162                if (currentPhoto == undefined) {
163                    return;
164                }
165                menuContext.withItems([currentPhoto])
166                    .withDeletePageFromType(BroadcastConstants.DELETE_FROM_BROWSER)
167                    .withAlbumId(this.albumInfo && this.albumInfo.id)
168                    .withBroadCast(this.broadCast)
169                    .withOperationEndCallback(this.onDeleteEnd.bind(this))
170                menuOperation = new BatchDeleteMenuOperation(menuContext);
171                break;
172            case Action.CLEAR_RECYCLE:
173                if (currentPhoto == undefined) {
174                    return;
175                }
176                menuContext.withItems([currentPhoto])
177                    .withBroadCast(this.broadCast)
178                    .withOperationEndCallback(this.onDeleteEnd.bind(this))
179                menuOperation = new ClearRecycleMenuOperation(menuContext);
180                break;
181            case Action.RECOVER:
182                if (currentPhoto == undefined) {
183                    return;
184                }
185                menuContext = new MenuContext();
186                this.onDeleteEnd = this.onDeleteEnd.bind(this);
187                menuContext.withItems([currentPhoto])
188                    .withOperationEndCallback(this.onDeleteEnd)
189                    .withBroadCast(this.broadCast)
190                menuOperation = new BatchRecoverMenuOperation(menuContext);
191                break;
192            case Action.GOTO_PHOTOS:
193                menuContext.withJumpSourceToMain(this.jumpSourceToMain);
194                menuOperation = new GotoPhotosMenuOperation(menuContext);
195                break;
196            case Action.EDIT:
197                if (currentPhoto == undefined || currentPhoto.size == 0) {
198                    return;
199                }
200                this.isToEdit = true
201                globalThis.EditorMediaItem = currentPhoto;
202                router.push({
203                    uri: 'feature/editor/view/EditMain'
204                })
205                return;
206            case Action.RENAME:
207                if (currentPhoto == undefined) {
208                    return;
209                }
210                menuContext.withItems([currentPhoto])
211                    .withBroadCast(this.broadCast)
212                    .withAlbumInfo(this.albumInfo);
213                menuOperation = new RenameMenuOperation(menuContext);
214                break;
215            case Action.ROTATE:
216                if (currentPhoto == undefined) {
217                    return;
218                }
219                currentPhoto.setOrientation().then(() => this.setOrientation())
220                return;
221            case Action.MOVE:
222                this.backFromCopy = true;
223                this.routeSelectAlbumPage(MediaOperationType.Move);
224                return;
225            case Action.COPY:
226                this.backFromCopy = true;
227                this.routeSelectAlbumPage(MediaOperationType.Copy);
228                return;
229            case Action.DOWNLOAD:
230                this.downLoad();
231                return;
232            default:
233                return;
234        }
235        menuOperation.doAction();
236    }
237
238    private setFavourite(isSuccess: boolean) {
239        Log.debug(TAG, 'set favor !');
240
241        if (isSuccess) {
242            let currentPhoto = this.getCurrentPhoto();
243            if (currentPhoto == undefined) {
244                return;
245            }
246            if (mediaDataItemCache.hasKey(currentPhoto.uri)) {
247                mediaDataItemCache.get(currentPhoto.uri).favouriteStatus = currentPhoto.favouriteStatus;
248            }
249            // 收藏相册进入大图,点击取消收藏会导致Item成员变少,所以要dataRemove
250            if(this.albumInfo.id === MediaConstants.ALBUM_ID_FAVOR) {
251                this.browserDataSource.reloadGroupItemData(false).then(() => {
252                    this.operateEnd();
253                });
254            }
255            this.updateMenu();
256            this.appBroadcast.emit(BroadcastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
257        }
258    }
259
260    private operateEnd() {
261        if (this.currentIndex == 0 || AppStorage.Get("isLeftSwiper") == 0) {
262            this.broadCast.emit(BroadcastConstants.ON_DATA_RELOADED, []);
263        } else {
264            Log.info(TAG, `operateEnd curIndex : ` + this.currentIndex);
265            this.broadCast.emit(BroadcastConstants.ON_DATA_RELOADED, []);
266            this.currentIndex--;
267        }
268    }
269
270    private onDeleteEnd() {
271        Log.debug(TAG, `onDeleteEnd start`);
272        AppStorage.SetOrCreate("isDelete", 0);
273        this.operateEnd();
274    }
275
276    private setOrientation() {
277        Log.debug(TAG, `setOrientation`);
278        let currentPhoto = this.getCurrentPhoto();
279        if (currentPhoto == undefined) {
280            return;
281        }
282        this.browserDataSource.notifyDataChange(this.currentIndex);
283        this.appBroadcast.emit(BroadcastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
284    }
285
286    onToggleBars() {
287        if (this.isShowBar) {
288            this.hideBars();
289        } else {
290            this.showBars();
291        }
292        Log.info(TAG, `Toggle bars, isShowBar: ${this.isShowBar}`);
293    }
294
295    showBars(): void {
296        if (!this.isShowBar) {
297            this.isShowBar = true;
298            this.browserBackgroundColor = $r('app.color.default_background_color');
299            screenManager.setSystemUi(true);
300        }
301    }
302
303    hideBars(): void {
304        if (this.isShowBar) {
305            this.isShowBar = false;
306            this.browserBackgroundColor = $r('app.color.black');
307            screenManager.setSystemUi(false);
308        }
309    }
310
311    routeSelectAlbumPage(pageType: string): void {
312        router.push({
313            uri: 'common/view/browserOperation/MediaOperationPage',
314            params: {
315                pageType: pageType,
316                albumInfo: JSON.stringify(this.albumInfo)
317            }
318        });
319    }
320
321    onPhotoChanged(index: number): void{
322        index = Math.min(index, this.browserDataSource.totalCount() - 1);
323        Log.info(TAG, `onPhotoChanged start ${index}`);
324        this.currentIndex = this.isToEdit ? 0 : index;
325        this.updateActionBar();
326    }
327
328    onDataSizeChanged(size: number): void {
329        Log.info(TAG, `onDataSizeChanged, size is ${size}`);
330        if (size == 0) {
331            if (this.pageFrom == Constants.ENTRY_FROM.CARD) {
332                let menuContext: MenuContext = new MenuContext();
333                menuContext.withJumpSourceToMain(this.jumpSourceToMain);
334                let menuOperation = new GotoPhotosMenuOperation(menuContext);
335                menuOperation.doAction();
336            } else {
337                this.onBackPress();
338            }
339        }
340    }
341
342    updateActionBar() {
343        let currentPhoto = this.getCurrentPhoto();
344        if (currentPhoto == undefined || this.isFromViewData) {
345            Log.warn(TAG, `currentPhoto is undefined:${currentPhoto == undefined} this.isFromViewData:${this.isFromViewData} `)
346            return;
347        }
348
349        // PhotoItems 和 这里都会有load, 极端情况下可能产生一次无效的load
350        currentPhoto.load(false).then(() => {
351            this.photoDate = DateUtil.getLocalizedDate(currentPhoto.dateAdded);
352            if (this.pageFrom == Constants.ENTRY_FROM.DISTRIBUTED) {
353                this.timeAndLocation = `${this.deviceName}/${DateUtil.getLocalizedTime(currentPhoto.dateAdded)}`;
354            } else {
355                this.timeAndLocation = DateUtil.getLocalizedTime(currentPhoto.dateAdded);
356            }
357            this.updateMenu();
358        })
359    }
360
361    updateMenu(): void{
362        let currentPhoto = this.getCurrentPhoto();
363        if (currentPhoto == undefined) {
364            return;
365        }
366        this.toolMenuList = [];
367        this.getActionList(currentPhoto).then((list: Array<Action>) => {
368            if (this.pageFrom == Constants.ENTRY_FROM.CAMERA || this.pageFrom == Constants.ENTRY_FROM.CARD) {
369                this.menuList = [Action.GOTO_PHOTOS, Action.INFO];
370            } else if (this.pageFrom == Constants.ENTRY_FROM.RECYCLE) {
371                this.menuList = [];
372            } else {
373                this.menuList = [Action.INFO];
374            }
375            if (this.isHorizontal) {
376                this.menuList = this.menuList.concat(list);
377            } else {
378                this.toolMenuList = list;
379            }
380            this.updateMoreMenu();
381        })
382    }
383
384    private async getActionList(currentPhoto: MediaDataItem): Promise<Array<Action>> {
385        let list: Array<Action> = new Array<Action>();
386        if (this.pageFrom == Constants.ENTRY_FROM.RECYCLE) {
387            list.push(Action.RECOVER, Action.DELETE);
388        } else if (this.pageFrom == Constants.ENTRY_FROM.DISTRIBUTED) {
389            list.push(Action.SHARE, Action.DOWNLOAD);
390        } else {
391            let isFavor = await currentPhoto.isFavor();
392            list.push(Action.SHARE,
393                    isFavor ? Action.FAVORITE : Action.NOT_FAVORITE,
394                    currentPhoto.mediaType == MediaLib.MediaType.IMAGE ? Action.EDIT : Action.EDIT_INVALID,
395                Action.DELETE,
396                Action.MORE); // TODO: delete edit
397        }
398        return list;
399    }
400
401    private currentShowChange() {
402        this.updateMoreMenu();
403    }
404
405    private updateMoreMenu() {
406        let currentPhoto = this.getCurrentPhoto();
407        this.moreMenuList = [Action.MOVE, Action.COPY, Action.RENAME];
408        if (currentPhoto == undefined) {
409            return;
410        }
411        if (currentPhoto.mediaType == MediaLib.MediaType.IMAGE) {
412            if (this.currentShow) {
413                this.moreMenuList.push(Action.ROTATE);
414            }
415        }
416    }
417
418    getCurrentPhoto(): MediaDataItem {
419        return this.browserDataSource.getDataByIndex(this.currentIndex);
420    }
421
422    getPhotoByIndex(index: number): MediaDataItem {
423        return this.browserDataSource.getDataByIndex(index);
424    }
425
426    async onMoveEnd(err, count, total) {
427        Log.debug(TAG, `onMoveEnd count: ${count}, total: ${total}`);
428        if (err) {
429            getResourceString($r('app.string.move_failed_single')).then((message: string) => {
430                showToast(message)
431            })
432            return;
433        }
434        let currentPhoto = this.getCurrentPhoto();
435        if (currentPhoto == undefined) {
436            return;
437        }
438        currentPhoto.path = (await currentPhoto.loadFileAsset()).relativePath;
439        this.appBroadcast.emit(BroadcastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
440    }
441
442    onCopyEnd(err, count, total): void {
443        Log.debug(TAG, `onCopyEnd count: ${count}, total: ${total}`);
444        this.dataSourceLoadFinish()
445        if (err) {
446            getResourceString($r('app.string.copy_failed_single')).then((message: string) => {
447                showToast(message);
448            })
449        }
450    }
451
452    async onDownloadEnd(err, count, total) {
453        Log.debug(TAG, `onDownloadEnd count: ${count}, total: ${total}`);
454        if (err) {
455            getResourceString($r('app.string.download_failed_single')).then((message: string) => {
456                showToast(message);
457            })
458        } else {
459            getResourceString($r('app.string.download_progress_done')).then((message: string) => {
460                showToast(message);
461            })
462        }
463    }
464
465    onBackPress() {
466        Log.info(TAG, 'onBackPress');
467        this.controller.finishAnimation(this.onBackPressInner.bind(this));
468        return true;
469    }
470
471    onBackPressInner(): void {
472        Log.info(TAG, `onBackPressInner ${this.checkedTransition}`);
473        switch (this.checkedTransition) {
474            case Constants.PHOTO_TRANSITION_TIMELINE:
475                Log.info(TAG, 'onBackPress TimelinePage');
476                this.TimelinePageIndex = this.currentIndex; // call scrollTo
477                break;
478            case Constants.PHOTO_TRANSITION_ALBUM:
479                Log.info(TAG, 'onBackPress PhotoGridPage');
480                this.PhotoGridPageIndex = this.currentIndex; // call scrollTo
481                break;
482            case Constants.PHOTO_TRANSITION_CAMERA:
483                Log.info(TAG, 'onBackPress Camera');
484                if (this.pageFrom == Constants.ENTRY_FROM.CARD && !this.pullDownFlag) {
485                    this.routerGridPaged();
486                } else {
487                    if (this.pullDownFlag) {
488                        this.pullDownFlag = false;
489                    }
490                    // Entering from the camera does not need to return to close directly
491                    terminateSelf();
492                }
493                return;
494            default:
495                break
496        }
497        router.back({
498            params: {
499                index: this.currentIndex
500            }
501        });
502    }
503
504    aboutToDisappear(): void {
505        Log.info(TAG, 'aboutToDisappear');
506        screenManager.setNavigationBarColor('#00FFFFFF', '#FF000000');
507        if (!this.isShowBar) {
508            screenManager.setSystemUi(true);
509        }
510        // Click the thumbnail quickly, hasAppeared is false if it is not the first click. Return directly
511        if (!this.hasAppeared) {
512            return;
513        }
514        mediaObserver.unregisterObserver(this.dataObserver);
515        this.dataObserver.clearSource();
516        mMultimodalInputManager.unregisterListener();
517        this.broadCast.off(null, null);
518        this.controller = undefined;
519    }
520
521    aboutToAppear(): void {
522        startTrace('PhotoBrowserAboutToAppear');
523        Log.info(TAG, 'photoBrowser aboutToAppear');
524        AppStorage.SetOrCreate("isDelete", 0);
525        AppStorage.SetOrCreate("isLeftSwiper", 0);
526        screenManager.setNavigationBarColor('#FFF1F3F5', '#FF000000');
527        this.hasAppeared = true;
528        mMultimodalInputManager.registerListener((control: number) => {
529            Log.info(TAG, `key control: ${control} index ${this.currentIndex}`);
530            if (control == 0) {
531                if (this.currentIndex > 0) {
532                    this.onPhotoChanged(this.currentIndex - 1);
533                }
534            } else if (control == 1) {
535                if (this.currentIndex < this.browserDataSource.totalCount() - 1) {
536                    this.onPhotoChanged(this.currentIndex + 1);
537                }
538            } else {
539                this.onBackPress();
540            }
541        });
542        let param = router.getParams();
543        if (param) {
544            Log.info(TAG, `photoBrowser start with param`);
545            Log.debug(TAG, `param: ${JSON.stringify(param)}`);
546            if (param.pageFrom) {
547                this.pageFrom = parseInt(param.pageFrom.toString());
548            }
549            if (this.pageFrom == Constants.ENTRY_FROM.CAMERA) {
550                this.isFromCamera = true;
551                this.albumInfo = new SimpleAlbumDataItem(MediaConstants.ALBUM_ID_CAMERA, "", "", "", "")
552                this.browserDataSource.setAlbumId(this.albumInfo.id)
553                this.jumpSourceToMain = JumpSourceToMain.CAMERA;
554            } else if (this.pageFrom == Constants.ENTRY_FROM.VIEW_DATA) {
555                this.isFromViewData = true;
556            }
557
558            if (param.albumInfo) {
559                this.albumInfo = param.albumInfo as SimpleAlbumDataItem;
560                this.deviceName = this.albumInfo.deviceName;
561                this.browserDataSource.setAlbumId(this.albumInfo.id)
562                this.browserDataSource.setDeviceId(this.albumInfo.deviceId);
563            }
564
565            let items: MediaDataItem[];
566            if (param.viewData) {
567                items = []
568                let uriArr: string[] = String(param.viewData).split(',');
569                for (let i = 0;i < uriArr.length; i++) {
570                    items.push(new InnerMediaDataItem(uriArr[i], i));
571                }
572            } else {
573                items = AppStorage.Get<MediaDataItem[]>(Constants.APP_KEY_PHOTO_BROWSER);
574            }
575
576            if (items && !this.isFromCamera) {
577                this.browserDataSource.groupDataItem = items;
578                this.onPhotoChanged(new Number(param.position).valueOf() || 0);
579            } else {
580                this.browserDataSource.reloadGroupItemData(false).then((isEmpty: boolean) => {
581                    this.onPhotoChanged(0);
582                    this.browserDataSource.notifyDataReload();
583                })
584            }
585
586            this.photoBrowserTransition = (this.isFromCamera || this.isFromViewData)
587                ? Constants.PHOTO_TRANSITION_CAMERA : (param.transition ? param.transition.toString() : '');
588        } else {
589            Log.info(TAG, `photoBrowser start without param`);
590            if (this.entryFromHap == Constants.ENTRY_FROM_FORM_ABILITY) {
591                this.isFromCard = true;
592                this.pageFrom = Constants.ENTRY_FROM.CARD;
593                this.albumInfo = new SimpleAlbumDataItem(AppStorage.Get(Constants.FROM_ALBUM_ID), "", "", "", "");
594            } else {
595                this.pageFrom = Constants.ENTRY_FROM.CAMERA;
596                this.albumInfo = new SimpleAlbumDataItem(MediaConstants.ALBUM_ID_CAMERA, "", "", "", "");
597            }
598            AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_NONE);
599            this.browserDataSource.setAlbumId(this.albumInfo.id);
600            this.browserDataSource.reloadGroupItemData(false).then((isEmpty: boolean) => {
601                this.isDataChanged = isEmpty;
602                this.onPhotoChanged(AppStorage.Get(Constants.FROM_CURRENT_INDEX) || 0);
603                this.browserDataSource.notifyDataReload()
604            });
605            this.isFromCamera = true;
606            this.jumpSourceToMain = JumpSourceToMain.CAMERA;
607
608            this.photoBrowserTransition = Constants.PHOTO_TRANSITION_CAMERA;
609        }
610
611        mediaObserver.registerObserver(this.dataObserver);
612        this.checkedTransition = this.photoBrowserTransition;
613
614        this.onMenuClicked = this.onMenuClicked.bind(this);
615
616        // register event handling
617        this.broadCast.on(PhotoConstants.TOGGLE_BAR, () => {
618            this.onToggleBars();
619        });
620
621        this.broadCast.on(PhotoConstants.HIDE_BARS, () => {
622            this.hideBars();
623        });
624
625        this.broadCast.on(PhotoConstants.PULL_DOWN_START, () => {
626            Log.info(TAG, 'pulling down start');
627        });
628
629        this.broadCast.on(PhotoConstants.PULL_DOWN_END, () => {
630            this.pullDownFlag = true;
631            this.onBackPress();
632        });
633
634        this.broadCast.on(PhotoConstants.DATA_SIZE_CHANGED, (size: number) => {
635            this.onDataSizeChanged(size);
636        });
637
638        this.broadCast.on(PhotoConstants.DATA_CONTENT_CHANGED, () => {
639            this.onPhotoChanged(this.currentIndex);
640        });
641
642        this.broadCast.on(PhotoConstants.RENAME, (result: string[]) => {
643            Log.info(TAG, `rename refresh: ${result[0]}, ${result[1]}`);
644            let currentPhoto = this.getCurrentPhoto();
645            if (currentPhoto == undefined) {
646                return;
647            }
648            currentPhoto.title = result[0];
649            currentPhoto.displayName = result[1];
650            this.appBroadcast.emit(BroadcastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
651        });
652
653        this.broadCast.on(PhotoConstants.PULL_DOWN_START, (event) => {
654            Log.debug(TAG, `pulling down start : ${JSON.stringify(event)}`);
655            this.isPullingDown = true;
656        })
657
658        this.broadCast.on(PhotoConstants.PULL_DOWN_CANCEL, () => {
659            Log.info(TAG, 'pulling down cancel');
660            this.isPullingDown = false;
661        })
662
663        this.broadCast.on(PhotoConstants.PHOTO_SHOW_STATE, (state: boolean) => {
664            Log.debug(TAG, 'current photo show state change');
665            this.currentShow = state;
666        });
667
668        this.broadCast.on(PhotoConstants.SET_DISABLE_SWIPE, (value: boolean) => {
669            Log.info(TAG, `set swiper swipe ${value}`);
670            this.canSwipe = value;
671        });
672
673        finishTrace('PhotoBrowserAboutToAppear');
674    }
675
676    private async dataSourceLoadFinish() {
677        await this.browserDataSource.reloadGroupItemData(false);
678        for(let i = 0;i < this.browserDataSource.groupDataItem.length;i++) {
679           await this.browserDataSource.groupDataItem[i].load(false);
680        }
681        if(AppStorage.Get(Constants.EDIT_REPLACE) == 0) {
682            this.isToEdit = false;
683        }
684        this.onPhotoChanged(this.currentIndex);
685		    this.browserDataSource.notifyDataChange(this.currentIndex);
686        if (this.isToEdit) {
687            this.isToEdit = false;
688            this.appBroadcast.emit(BroadcastConstants.PHOTO_EDIT_SAVE_COMPLETE, []);
689        } else {
690            this.appBroadcast.emit(BroadcastConstants.PHOTO_EDIT_SAVE_COMPLETE, []);
691        }
692    }
693
694    onPageShow() {
695        startTrace('PhotoBrowserOnPageShow');
696        this.appBroadcast.emit(BroadcastConstants.THIRD_ROUTE_PAGE, []);
697        this.broadCast.emit(BroadcastConstants.CHANGE_SWIPER_DURATION, [400]);
698        let params = router.getParams();
699        if (params != null && params.pageType != null && this.backFromCopy) {
700            Log.debug(TAG, `MediaOperation back ${JSON.stringify(params)}`)
701            let menuContext = new MenuContext();
702            let menuOperation: MenuOperation;
703            let currentPhoto = this.getCurrentPhoto();
704            if (currentPhoto == undefined) {
705                Log.warn(TAG, 'MediaOperation currentPhoto is undefined');
706                return;
707            }
708            switch (params.pageType) {
709                case MediaOperationType.Move:
710                    this.onMoveEnd = this.onMoveEnd.bind(this);
711                    menuContext.withItems([currentPhoto])
712                        .withBroadCast(this.broadCast)
713                        .withAlbumInfo(JSON.parse(params.albumInfo ? params.albumInfo.toString() : ''))
714                        .withOperationEndCallback(this.onMoveEnd);
715                    menuOperation = new MoveMenuOperation(menuContext);
716                    break;
717                case MediaOperationType.Copy:
718                    this.onCopyEnd = this.onCopyEnd.bind(this);
719                    menuContext.withItems([currentPhoto])
720                        .withBroadCast(this.broadCast)
721                        .withAlbumInfo(JSON.parse(params.albumInfo ? params.albumInfo.toString() : ''))
722                        .withOperationEndCallback(this.onCopyEnd);
723                    menuOperation = new CopyMenuOperation(menuContext);
724                    break;
725            }
726            menuOperation.doAction();
727        }
728        this.backFromCopy = false;
729        finishTrace('PhotoBrowserOnPageShow');
730    }
731
732    private downLoad() {
733        Log.info(TAG, 'downLoad run');
734        let menuContext = new MenuContext();
735        let menuOperation: MenuOperation;
736        let currentPhoto = this.getCurrentPhoto();
737        this.onDownloadEnd = this.onDownloadEnd.bind(this);
738        if (currentPhoto == undefined) {
739            Log.warn(TAG, 'MediaOperation currentPhoto is undefined');
740            return;
741        }
742        menuContext.withItems([currentPhoto])
743            .withBroadCast(this.broadCast)
744            .withRemoteDevice(this.albumInfo.deviceId)
745            .withOperationEndCallback(this.onDownloadEnd)
746        menuOperation = new CopyMenuOperation(menuContext);
747        menuOperation.doAction();
748    }
749
750    onPageHide() {
751        this.showBars();
752    }
753
754    onMediaLibDataChange(changeType) {
755        Log.info(TAG, `onMediaLibDataChange type: ${changeType}`);
756        if (!PhotoEditorManager.getInstance().isSaving) {
757            this.dataSourceLoadFinish();
758        }
759    }
760
761    async routerGridPaged() {
762        AppStorage.SetOrCreate(Constants.BACK_FROM_FORM_DETAIL, true);
763        let displayName = await getAlbumDisplayName(MediaConstants.ALBUM_ID_CAMERA)
764        let item: SimpleAlbumDataItem = new SimpleAlbumDataItem(MediaConstants.ALBUM_ID_CAMERA, displayName, "", "", "")
765        Log.info(TAG, `item.displayName: ${item.displayName} item ${JSON.stringify(item)}`);
766        router.replace({
767            uri: 'feature/photoGrid/view/PhotoGridPage',
768            params: {
769                item: JSON.stringify(item)
770            }
771        });
772    }
773
774    build() {
775        Stack({ alignContent: Alignment.TopStart }) {
776            PhotoBrowserBg()
777            if (!this.isDataChanged || !this.isFromCard == true) {
778                PhotoSwiper({
779                    dataSource: this.browserDataSource,
780                    photoSwiperTransition: this.photoBrowserTransition,
781                    swiperController: this.controller,
782                    onPhotoChanged: this.onPhotoChanged.bind(this)
783                })
784            }
785            if (!this.isFromViewData) {
786                if (this.isShowBar) {
787                    PhotoBrowserActionBar({
788                        onMenuClicked: this.onMenuClicked,
789                    })
790                    ToolBar({
791                        toolMenuList: $toolMenuList,
792                        onMenuClicked: this.onMenuClicked,
793                        isFromPhotoBrowser: true
794                    })
795                }
796                CustomDialogView()
797            } else {
798                Column() {
799                    if (this.isShowBar) {
800                        PhotoBrowserActionBar({
801                            onMenuClicked: (action) => this.onMenuClicked(action)
802                        })
803                    }
804                    Text(`${this.currentIndex + 1}/${this.browserDataSource.totalCount()}`)
805                        .height($r('app.float.menu_height'))
806                        .fontColor($r('app.color.text_color_secondary'))
807                        .fontSize($r('sys.float.ohos_id_text_size_body1'))
808                        .markAnchor({ x: '0%', y: '0%' })
809                        .position({
810                            x: '0%',
811                            y: screenManager.getStatusBarHeight() + Constants.ActionBarHeight
812                        })
813                }.alignItems(HorizontalAlign.Start)
814            }
815        }
816    }
817
818    pageTransition() {
819        PageTransitionEnter({ type: RouteType.None, duration: PhotoConstants.PAGE_SHOW_ANIMATION_DURATION })
820            .opacity(0)
821        PageTransitionExit({ duration: PhotoConstants.PAGE_SHOW_ANIMATION_DURATION })
822            .opacity(0)
823    }
824}