1/* 2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import Matrix4 from '@ohos.matrix4'; 17import { PhotoItem } from './PhotoItem'; 18import { BroadCastConstants } from '../model/common/BroadCastConstants'; 19import { Log } from '../utils/Log'; 20import { BroadCast } from '../utils/BroadCast'; 21import Curves from '@ohos.curves'; 22import { Constants } from '../model/common/Constants'; 23import { Constants as BrowserConstants } from '../model/browser/photo/Constants'; 24 25const TAG: string = 'common_PhotoSwiper'; 26 27@Component 28export struct PhotoSwiper { 29 mTransition: string; 30 @Consume currentIndex: number; 31 @Link broadCast: BroadCast; 32 @State mDuration: number = 300; 33 onPhotoChanged: Function; 34 swiperController: SwiperController; 35 isInSelectedMode: boolean; 36 @Consume canSwipe: boolean; 37 swiperItemSpace: number = Constants.NUMBER_8; 38 verifyPhotoScaledFunc: (matrix: Matrix4.Matrix4Transit) => void 39 @Link isRunningAnimation: boolean; 40 isLeftSwiper: boolean = false; 41 @Consume isDeleting: boolean; 42 @State isOnSwiperAnimation: boolean = false; 43 private dataSource; 44 private geometryTransitionEnable: boolean = false; 45 private isFromFACard: boolean = false; 46 private SWIPE_CACHE_COUNT: number = 2; 47 48 aboutToAppear() { 49 this.broadCast.on(BroadCastConstants.ON_DATA_RELOADED, (addCount) => { 50 let totalCount = this.dataSource.totalCount(); 51 if (addCount > Constants.NUMBER_0) { 52 this.dataSource.onDataReloaded(); 53 if (this.currentIndex + addCount < totalCount) { 54 this.currentIndex += addCount; 55 } 56 Log.info(TAG, `ON_DATA_RELOADED: ${this.currentIndex}, ${addCount}`); 57 return; 58 } 59 Log.debug(TAG, 'animate to data reloaded start'); 60 animateTo({ 61 duration: 300, // 删除动画时长 62 curve: Curves.cubicBezier(0.0, 0.0, 0.2, 1.0), // 减速曲线参数 63 onFinish: () => { 64 let totalCount = this.dataSource.totalCount(); 65 this.dataSource.onDataChanged(this.currentIndex); 66 // UPDATE NEXT TWO DATA FOR AVOID NOT LOADING DATA 67 if (this.currentIndex + 1 < totalCount) { 68 this.dataSource.onDataChanged(this.currentIndex + 1); 69 } 70 if (this.currentIndex + 2 < totalCount) { 71 this.dataSource.onDataChanged(this.currentIndex + 2); 72 } 73 this.dataSource.onDataReloaded(); 74 } }, () => { 75 if (this.isDeleting) { 76 this.dataSource.deleteData(this.currentIndex); 77 } 78 if (this.currentIndex === this.dataSource.totalCount() || (this.isDeleting && this.isLeftSwiper && this.currentIndex > 0)) { 79 this.currentIndex--; 80 } 81 this.isDeleting = false; 82 }) 83 }); 84 85 this.broadCast.on(BroadCastConstants.CHANGE_SWIPER_DURATION, (value) => { 86 Log.debug(TAG, `change duration start ${value}`); 87 this.mDuration = value; 88 }); 89 } 90 91 aboutToDisappear(): void { 92 this.swiperController = undefined; 93 } 94 95 build() { 96 Swiper(this.swiperController) { 97 LazyForEach(this.dataSource, (item, index?: number) => { 98 if (!!item) { 99 Column() { 100 PhotoItem({ 101 item: item.data, 102 mPosition: item.pos, 103 thumbnail: item.thumbnail, 104 transitionTag: this.mTransition ? this.mTransition : 'default_id', 105 verifyPhotoScaled: this.verifyPhotoScaledFunc, 106 albumUri: this.dataSource.getAlbumUri(), 107 geometryTransitionEnable: this.geometryTransitionEnable, 108 broadCast: $broadCast, 109 isRunningAnimation: $isRunningAnimation, 110 isFromFACard: this.isFromFACard, 111 isInSelectedMode: this.isInSelectedMode, 112 isOnSwiperAnimation: $isOnSwiperAnimation, 113 dataSource: this.dataSource 114 }) 115 }.zIndex(item.pos == this.currentIndex ? 2 : 1) 116 } 117 }, (item, index) => { 118 if (item == null || item == undefined) { 119 return JSON.stringify(item) + index; 120 } 121 return `${item.data.uri}_${item.data.size}_${item.data.orientation}_${index}`; 122 }) 123 } 124 .cachedCount(this.SWIPE_CACHE_COUNT) 125 .duration(BrowserConstants.PHOTO_SWIPE_DURATION) 126 .itemSpace(this.swiperItemSpace) 127 .parallelGesture(PanGesture({ 128 direction: PanDirection.Horizontal 129 }) 130 .onActionStart((event: GestureEvent) => { 131 if (!this.canSwipe) { 132 this.isOnSwiperAnimation = true; 133 } 134 }) 135 ) 136 .index(this.currentIndex) 137 .indicator(false) 138 .loop(false) 139 .onChange((index: number) => { 140 if (this.currentIndex - index == 1) { 141 this.isLeftSwiper = true; 142 } else if (this.currentIndex - index == -1) { 143 this.isLeftSwiper = false; 144 } 145 if (this.mDuration != 0) { 146 this.onPhotoChanged(index); 147 148 if (!!this.verifyPhotoScaledFunc) { 149 this.verifyPhotoScaledFunc(undefined) 150 } 151 } 152 }) 153 .disableSwipe(this.canSwipe) 154 .onAnimationStart((index: number) => { 155 this.isOnSwiperAnimation = true; 156 }) 157 .onAnimationEnd(() => { 158 this.isOnSwiperAnimation = false; 159 }) 160 } 161}