• 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            this.browserDataSource.reloadGroupItemData(false).then(() => {
251                this.operateEnd();
252            });
253            this.updateMenu();
254            this.appBroadcast.emit(BroadcastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
255        }
256    }
257
258    private operateEnd() {
259        if (this.currentIndex == 0 || AppStorage.Get("isLeftSwiper") == 0) {
260            this.broadCast.emit(BroadcastConstants.ON_DATA_RELOADED, []);
261        } else {
262            Log.info(TAG, `operateEnd curIndex : ` + this.currentIndex);
263            this.broadCast.emit(BroadcastConstants.ON_DATA_RELOADED, []);
264            this.currentIndex--;
265        }
266    }
267
268    private onDeleteEnd() {
269        Log.debug(TAG, `onDeleteEnd start`);
270        AppStorage.SetOrCreate("isDelete", 0);
271        this.operateEnd();
272    }
273
274    private setOrientation() {
275        Log.debug(TAG, `setOrientation`);
276        let currentPhoto = this.getCurrentPhoto();
277        if (currentPhoto == undefined) {
278            return;
279        }
280        this.browserDataSource.notifyDataChange(this.currentIndex);
281        this.appBroadcast.emit(BroadcastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
282    }
283
284    onToggleBars() {
285        if (this.isShowBar) {
286            this.hideBars();
287        } else {
288            this.showBars();
289        }
290        Log.info(TAG, `Toggle bars, isShowBar: ${this.isShowBar}`);
291    }
292
293    showBars(): void {
294        if (!this.isShowBar) {
295            this.isShowBar = true;
296            this.browserBackgroundColor = $r('app.color.default_background_color');
297            screenManager.setSystemUi(true);
298        }
299    }
300
301    hideBars(): void {
302        if (this.isShowBar) {
303            this.isShowBar = false;
304            this.browserBackgroundColor = $r('app.color.black');
305            screenManager.setSystemUi(false);
306        }
307    }
308
309    routeSelectAlbumPage(pageType: string): void {
310        router.push({
311            uri: 'common/view/browserOperation/MediaOperationPage',
312            params: {
313                pageType: pageType,
314                albumInfo: JSON.stringify(this.albumInfo)
315            }
316        });
317    }
318
319    onPhotoChanged(index: number): void{
320        index = Math.min(index, this.browserDataSource.totalCount() - 1);
321        Log.info(TAG, `onPhotoChanged start ${index}`);
322        this.currentIndex = this.isToEdit ? 0 : index;
323        this.updateActionBar();
324    }
325
326    onDataSizeChanged(size: number): void {
327        Log.info(TAG, `onDataSizeChanged, size is ${size}`);
328        if (size == 0) {
329            if (this.pageFrom == Constants.ENTRY_FROM.CARD) {
330                let menuContext: MenuContext = new MenuContext();
331                menuContext.withJumpSourceToMain(this.jumpSourceToMain);
332                let menuOperation = new GotoPhotosMenuOperation(menuContext);
333                menuOperation.doAction();
334            } else {
335                this.onBackPress();
336            }
337        }
338    }
339
340    updateActionBar() {
341        let currentPhoto = this.getCurrentPhoto();
342        if (currentPhoto == undefined || this.isFromViewData) {
343            Log.warn(TAG, `currentPhoto is undefined:${currentPhoto == undefined} this.isFromViewData:${this.isFromViewData} `)
344            return;
345        }
346
347        // PhotoItems 和 这里都会有load, 极端情况下可能产生一次无效的load
348        currentPhoto.load(false).then(() => {
349            this.photoDate = DateUtil.getLocalizedDate(currentPhoto.dateAdded);
350            if (this.pageFrom == Constants.ENTRY_FROM.DISTRIBUTED) {
351                this.timeAndLocation = `${this.deviceName}/${DateUtil.getLocalizedTime(currentPhoto.dateAdded)}`;
352            } else {
353                this.timeAndLocation = DateUtil.getLocalizedTime(currentPhoto.dateAdded);
354            }
355            this.updateMenu();
356        })
357    }
358
359    updateMenu(): void{
360        let currentPhoto = this.getCurrentPhoto();
361        if (currentPhoto == undefined) {
362            return;
363        }
364        this.toolMenuList = [];
365        this.getActionList(currentPhoto).then((list: Array<Action>) => {
366            if (this.pageFrom == Constants.ENTRY_FROM.CAMERA || this.pageFrom == Constants.ENTRY_FROM.CARD) {
367                this.menuList = [Action.GOTO_PHOTOS, Action.INFO];
368            } else if (this.pageFrom == Constants.ENTRY_FROM.RECYCLE) {
369                this.menuList = [];
370            } else {
371                this.menuList = [Action.INFO];
372            }
373            if (this.isHorizontal) {
374                this.menuList = this.menuList.concat(list);
375            } else {
376                this.toolMenuList = list;
377            }
378            this.updateMoreMenu();
379        })
380    }
381
382    private async getActionList(currentPhoto: MediaDataItem): Promise<Array<Action>> {
383        let list: Array<Action> = new Array<Action>();
384        if (this.pageFrom == Constants.ENTRY_FROM.RECYCLE) {
385            list.push(Action.RECOVER, Action.DELETE);
386        } else if (this.pageFrom == Constants.ENTRY_FROM.DISTRIBUTED) {
387            list.push(Action.SHARE, Action.DOWNLOAD);
388        } else {
389            let isFavor = await currentPhoto.isFavor();
390            list.push(Action.SHARE,
391                    isFavor ? Action.FAVORITE : Action.NOT_FAVORITE,
392                    currentPhoto.mediaType == MediaLib.MediaType.IMAGE ? Action.EDIT : Action.EDIT_INVALID,
393                Action.DELETE,
394                Action.MORE); // TODO: delete edit
395        }
396        return list;
397    }
398
399    private currentShowChange() {
400        this.updateMoreMenu();
401    }
402
403    private updateMoreMenu() {
404        let currentPhoto = this.getCurrentPhoto();
405        this.moreMenuList = [Action.MOVE, Action.COPY, Action.RENAME];
406        if (currentPhoto == undefined) {
407            return;
408        }
409        if (currentPhoto.mediaType == MediaLib.MediaType.IMAGE) {
410            if (this.currentShow) {
411                this.moreMenuList.push(Action.ROTATE);
412            }
413        }
414    }
415
416    getCurrentPhoto(): MediaDataItem {
417        return this.browserDataSource.getDataByIndex(this.currentIndex);
418    }
419
420    getPhotoByIndex(index: number): MediaDataItem {
421        return this.browserDataSource.getDataByIndex(index);
422    }
423
424    async onMoveEnd(err, count, total) {
425        Log.debug(TAG, `onMoveEnd count: ${count}, total: ${total}`);
426        if (err) {
427            getResourceString($r('app.string.move_failed_single')).then((message: string) => {
428                showToast(message)
429            })
430            return;
431        }
432        let currentPhoto = this.getCurrentPhoto();
433        if (currentPhoto == undefined) {
434            return;
435        }
436        currentPhoto.path = (await currentPhoto.loadFileAsset()).relativePath;
437        this.appBroadcast.emit(BroadcastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
438    }
439
440    onCopyEnd(err, count, total): void {
441        Log.debug(TAG, `onCopyEnd count: ${count}, total: ${total}`);
442        this.dataSourceLoadFinish()
443        if (err) {
444            getResourceString($r('app.string.copy_failed_single')).then((message: string) => {
445                showToast(message);
446            })
447        }
448    }
449
450    async onDownloadEnd(err, count, total) {
451        Log.debug(TAG, `onDownloadEnd count: ${count}, total: ${total}`);
452        if (err) {
453            getResourceString($r('app.string.download_failed_single')).then((message: string) => {
454                showToast(message);
455            })
456        } else {
457            getResourceString($r('app.string.download_progress_done')).then((message: string) => {
458                showToast(message);
459            })
460        }
461    }
462
463    onBackPress() {
464        Log.info(TAG, 'onBackPress');
465        this.controller.finishAnimation(this.onBackPressInner.bind(this));
466        return true;
467    }
468
469    onBackPressInner(): void {
470        Log.info(TAG, `onBackPressInner ${this.checkedTransition}`);
471        switch (this.checkedTransition) {
472            case Constants.PHOTO_TRANSITION_TIMELINE:
473                Log.info(TAG, 'onBackPress TimelinePage');
474                this.TimelinePageIndex = this.currentIndex; // call scrollTo
475                break;
476            case Constants.PHOTO_TRANSITION_ALBUM:
477                Log.info(TAG, 'onBackPress PhotoGridPage');
478                this.PhotoGridPageIndex = this.currentIndex; // call scrollTo
479                break;
480            case Constants.PHOTO_TRANSITION_CAMERA:
481                Log.info(TAG, 'onBackPress Camera');
482                if (this.pageFrom == Constants.ENTRY_FROM.CARD && !this.pullDownFlag) {
483                    this.routerGridPaged();
484                } else {
485                    if (this.pullDownFlag) {
486                        this.pullDownFlag = false;
487                    }
488                    // Entering from the camera does not need to return to close directly
489                    terminateSelf();
490                }
491                return;
492            default:
493                break
494        }
495        router.back({
496            params: {
497                index: this.currentIndex
498            }
499        });
500    }
501
502    aboutToDisappear(): void {
503        Log.info(TAG, 'aboutToDisappear');
504        screenManager.setNavigationBarColor('#00FFFFFF', '#FF000000');
505        if (!this.isShowBar) {
506            screenManager.setSystemUi(true);
507        }
508        // Click the thumbnail quickly, hasAppeared is false if it is not the first click. Return directly
509        if (!this.hasAppeared) {
510            return;
511        }
512        mediaObserver.unregisterObserver(this.dataObserver);
513        mMultimodalInputManager.unregisterListener();
514    }
515
516    aboutToAppear(): void {
517        startTrace('PhotoBrowserAboutToAppear');
518        Log.info(TAG, 'photoBrowser aboutToAppear');
519        AppStorage.SetOrCreate("isDelete", 0);
520        AppStorage.SetOrCreate("isLeftSwiper", 0);
521        screenManager.setNavigationBarColor('#FFF1F3F5', '#FF000000');
522        this.hasAppeared = true;
523        mMultimodalInputManager.registerListener((control: number) => {
524            Log.info(TAG, `key control: ${control} index ${this.currentIndex}`);
525            if (control == 0) {
526                if (this.currentIndex > 0) {
527                    this.onPhotoChanged(this.currentIndex - 1);
528                }
529            } else if (control == 1) {
530                if (this.currentIndex < this.browserDataSource.totalCount() - 1) {
531                    this.onPhotoChanged(this.currentIndex + 1);
532                }
533            } else {
534                this.onBackPress();
535            }
536        });
537        let param = router.getParams();
538        if (param) {
539            Log.info(TAG, `photoBrowser start with param`);
540            Log.debug(TAG, `param: ${JSON.stringify(param)}`);
541            if (param.pageFrom) {
542                this.pageFrom = parseInt(param.pageFrom.toString());
543            }
544            if (this.pageFrom == Constants.ENTRY_FROM.CAMERA) {
545                this.isFromCamera = true;
546                this.albumInfo = new SimpleAlbumDataItem(MediaConstants.ALBUM_ID_CAMERA, "", "", "", "")
547                this.browserDataSource.setAlbumId(this.albumInfo.id)
548                this.jumpSourceToMain = JumpSourceToMain.CAMERA;
549            } else if (this.pageFrom == Constants.ENTRY_FROM.VIEW_DATA) {
550                this.isFromViewData = true;
551            }
552
553            if (param.albumInfo) {
554                this.albumInfo = param.albumInfo as SimpleAlbumDataItem;
555                this.deviceName = this.albumInfo.deviceName;
556                this.browserDataSource.setAlbumId(this.albumInfo.id)
557                this.browserDataSource.setDeviceId(this.albumInfo.deviceId);
558            }
559
560            let items: MediaDataItem[];
561            if (param.viewData) {
562                items = []
563                let uriArr: string[] = String(param.viewData).split(',');
564                for (let i = 0;i < uriArr.length; i++) {
565                    items.push(new InnerMediaDataItem(uriArr[i], i));
566                }
567            } else {
568                items = AppStorage.Get<MediaDataItem[]>(Constants.APP_KEY_PHOTO_BROWSER);
569            }
570
571            if (items && !this.isFromCamera) {
572                this.browserDataSource.groupDataItem = items;
573                this.onPhotoChanged(new Number(param.position).valueOf() || 0);
574            } else {
575                this.browserDataSource.reloadGroupItemData(false).then((isEmpty: boolean) => {
576                    this.onPhotoChanged(0);
577                    this.browserDataSource.notifyDataReload();
578                })
579            }
580
581            this.photoBrowserTransition = (this.isFromCamera || this.isFromViewData)
582                ? Constants.PHOTO_TRANSITION_CAMERA : (param.transition ? param.transition.toString() : '');
583        } else {
584            Log.info(TAG, `photoBrowser start without param`);
585            if (this.entryFromHap == Constants.ENTRY_FROM_FORM_ABILITY) {
586                this.isFromCard = true;
587                this.pageFrom = Constants.ENTRY_FROM.CARD;
588                this.albumInfo = new SimpleAlbumDataItem(AppStorage.Get(Constants.FROM_ALBUM_ID), "", "", "", "");
589            } else {
590                this.pageFrom = Constants.ENTRY_FROM.CAMERA;
591                this.albumInfo = new SimpleAlbumDataItem(MediaConstants.ALBUM_ID_CAMERA, "", "", "", "");
592            }
593            AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_NONE);
594            this.browserDataSource.setAlbumId(this.albumInfo.id);
595            this.browserDataSource.reloadGroupItemData(false).then((isEmpty: boolean) => {
596                this.isDataChanged = isEmpty;
597                this.onPhotoChanged(AppStorage.Get(Constants.FROM_CURRENT_INDEX) || 0);
598                this.browserDataSource.notifyDataReload()
599            });
600            this.isFromCamera = true;
601            this.jumpSourceToMain = JumpSourceToMain.CAMERA;
602
603            this.photoBrowserTransition = Constants.PHOTO_TRANSITION_CAMERA;
604        }
605
606        mediaObserver.registerObserver(this.dataObserver);
607        this.checkedTransition = this.photoBrowserTransition;
608
609        this.onMenuClicked = this.onMenuClicked.bind(this);
610
611        // register event handling
612        this.broadCast.on(PhotoConstants.TOGGLE_BAR, () => {
613            this.onToggleBars();
614        });
615
616        this.broadCast.on(PhotoConstants.HIDE_BARS, () => {
617            this.hideBars();
618        });
619
620        this.broadCast.on(PhotoConstants.PULL_DOWN_START, () => {
621            Log.info(TAG, 'pulling down start');
622        });
623
624        this.broadCast.on(PhotoConstants.PULL_DOWN_END, () => {
625            this.pullDownFlag = true;
626            this.onBackPress();
627        });
628
629        this.broadCast.on(PhotoConstants.DATA_SIZE_CHANGED, (size: number) => {
630            this.onDataSizeChanged(size);
631        });
632
633        this.broadCast.on(PhotoConstants.DATA_CONTENT_CHANGED, () => {
634            this.onPhotoChanged(this.currentIndex);
635        });
636
637        this.broadCast.on(PhotoConstants.RENAME, (result: string[]) => {
638            Log.info(TAG, `rename refresh: ${result[0]}, ${result[1]}`);
639            let currentPhoto = this.getCurrentPhoto();
640            if (currentPhoto == undefined) {
641                return;
642            }
643            currentPhoto.title = result[0];
644            currentPhoto.displayName = result[1];
645            this.appBroadcast.emit(BroadcastConstants.UPDATE_DATA_SOURCE, [currentPhoto]);
646        });
647
648        this.broadCast.on(PhotoConstants.PULL_DOWN_START, (event) => {
649            Log.debug(TAG, `pulling down start : ${JSON.stringify(event)}`);
650            this.isPullingDown = true;
651        })
652
653        this.broadCast.on(PhotoConstants.PULL_DOWN_CANCEL, () => {
654            Log.info(TAG, 'pulling down cancel');
655            this.isPullingDown = false;
656        })
657
658        this.broadCast.on(PhotoConstants.PHOTO_SHOW_STATE, (state: boolean) => {
659            Log.debug(TAG, 'current photo show state change');
660            this.currentShow = state;
661        });
662
663        this.broadCast.on(PhotoConstants.SET_DISABLE_SWIPE, (value: boolean) => {
664            Log.info(TAG, `set swiper swipe ${value}`);
665            this.canSwipe = value;
666        });
667
668        finishTrace('PhotoBrowserAboutToAppear');
669    }
670
671    private async dataSourceLoadFinish() {
672        await this.browserDataSource.reloadGroupItemData(false);
673        for(let i = 0;i < this.browserDataSource.groupDataItem.length;i++) {
674           await this.browserDataSource.groupDataItem[i].load(false);
675        }
676        this.onPhotoChanged(this.currentIndex);
677		    this.browserDataSource.notifyDataChange(this.currentIndex);
678        if (this.isToEdit) {
679            this.isToEdit = false;
680            this.appBroadcast.emit(BroadcastConstants.PHOTO_EDIT_SAVE_COMPLETE, []);
681        }
682    }
683
684    onPageShow() {
685        startTrace('PhotoBrowserOnPageShow');
686        this.appBroadcast.emit(BroadcastConstants.THIRD_ROUTE_PAGE, []);
687        this.broadCast.emit(BroadcastConstants.CHANGE_SWIPER_DURATION, [400]);
688        let params = router.getParams();
689        if (params != null && params.pageType != null && this.backFromCopy) {
690            Log.debug(TAG, `MediaOperation back ${JSON.stringify(params)}`)
691            let menuContext = new MenuContext();
692            let menuOperation: MenuOperation;
693            let currentPhoto = this.getCurrentPhoto();
694            if (currentPhoto == undefined) {
695                Log.warn(TAG, 'MediaOperation currentPhoto is undefined');
696                return;
697            }
698            switch (params.pageType) {
699                case MediaOperationType.Move:
700                    this.onMoveEnd = this.onMoveEnd.bind(this);
701                    menuContext.withItems([currentPhoto])
702                        .withBroadCast(this.broadCast)
703                        .withAlbumInfo(JSON.parse(params.albumInfo ? params.albumInfo.toString() : ''))
704                        .withOperationEndCallback(this.onMoveEnd);
705                    menuOperation = new MoveMenuOperation(menuContext);
706                    break;
707                case MediaOperationType.Copy:
708                    this.onCopyEnd = this.onCopyEnd.bind(this);
709                    menuContext.withItems([currentPhoto])
710                        .withBroadCast(this.broadCast)
711                        .withAlbumInfo(JSON.parse(params.albumInfo ? params.albumInfo.toString() : ''))
712                        .withOperationEndCallback(this.onCopyEnd);
713                    menuOperation = new CopyMenuOperation(menuContext);
714                    break;
715            }
716            menuOperation.doAction();
717        }
718        this.backFromCopy = false;
719        finishTrace('PhotoBrowserOnPageShow');
720    }
721
722    private downLoad() {
723        Log.info(TAG, 'downLoad run');
724        let menuContext = new MenuContext();
725        let menuOperation: MenuOperation;
726        let currentPhoto = this.getCurrentPhoto();
727        this.onDownloadEnd = this.onDownloadEnd.bind(this);
728        if (currentPhoto == undefined) {
729            Log.warn(TAG, 'MediaOperation currentPhoto is undefined');
730            return;
731        }
732        menuContext.withItems([currentPhoto])
733            .withBroadCast(this.broadCast)
734            .withRemoteDevice(this.albumInfo.deviceId)
735            .withOperationEndCallback(this.onDownloadEnd)
736        menuOperation = new CopyMenuOperation(menuContext);
737        menuOperation.doAction();
738    }
739
740    onPageHide() {
741        this.showBars();
742    }
743
744    onMediaLibDataChange(changeType) {
745        Log.info(TAG, `onMediaLibDataChange type: ${changeType}`);
746        if (!PhotoEditorManager.getInstance().isSaving) {
747            this.dataSourceLoadFinish();
748        }
749    }
750
751    async routerGridPaged() {
752        AppStorage.SetOrCreate(Constants.BACK_FROM_FORM_DETAIL, true);
753        let displayName = await getAlbumDisplayName(MediaConstants.ALBUM_ID_CAMERA)
754        let item: SimpleAlbumDataItem = new SimpleAlbumDataItem(MediaConstants.ALBUM_ID_CAMERA, displayName, "", "", "")
755        Log.info(TAG, `item.displayName: ${item.displayName} item ${JSON.stringify(item)}`);
756        router.replace({
757            uri: 'feature/photoGrid/view/PhotoGridPage',
758            params: {
759                item: JSON.stringify(item)
760            }
761        });
762    }
763
764    build() {
765        Stack({ alignContent: Alignment.TopStart }) {
766            PhotoBrowserBg()
767            if (!this.isDataChanged || !this.isFromCard == true) {
768                PhotoSwiper({
769                    dataSource: this.browserDataSource,
770                    photoSwiperTransition: this.photoBrowserTransition,
771                    swiperController: this.controller,
772                    onPhotoChanged: this.onPhotoChanged.bind(this)
773                })
774            }
775            if (!this.isFromViewData) {
776                if (this.isShowBar) {
777                    PhotoBrowserActionBar({
778                        onMenuClicked: this.onMenuClicked,
779                    })
780                    ToolBar({
781                        toolMenuList: $toolMenuList,
782                        onMenuClicked: this.onMenuClicked,
783                        isFromPhotoBrowser: true
784                    })
785                }
786                CustomDialogView()
787            } else {
788                Column() {
789                    if (this.isShowBar) {
790                        PhotoBrowserActionBar({
791                            onMenuClicked: (action) => this.onMenuClicked(action)
792                        })
793                    }
794                    Text(`${this.currentIndex + 1}/${this.browserDataSource.totalCount()}`)
795                        .height($r('app.float.menu_height'))
796                        .fontColor($r('app.color.text_color_secondary'))
797                        .fontSize($r('sys.float.ohos_id_text_size_body1'))
798                        .markAnchor({ x: '0%', y: '0%' })
799                        .position({
800                            x: '0%',
801                            y: screenManager.getStatusBarHeight() + Constants.ActionBarHeight
802                        })
803                }.alignItems(HorizontalAlign.Start)
804            }
805        }
806    }
807
808    pageTransition() {
809        PageTransitionEnter({ type: RouteType.None, duration: PhotoConstants.PAGE_SHOW_ANIMATION_DURATION })
810            .opacity(0)
811        PageTransitionExit({ duration: PhotoConstants.PAGE_SHOW_ANIMATION_DURATION })
812            .opacity(0)
813    }
814}