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}