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'; 24import { PhotoDataSource } from '../model/browser/photo/PhotoDataSource'; 25import { MediaItem } from '../model/browser/photo/MediaItem'; 26 27const TAG: string = 'common_PhotoSwiper'; 28 29export interface Results { 30 data: MediaItem; 31 pos: number; 32 thumbnail: string; 33}; 34 35@Component 36export struct PhotoSwiper { 37 mTransition: string = ''; 38 @Consume currentIndex: number; 39 @Link broadCast: BroadCast; 40 @State mDuration: number = 300; 41 onPhotoChanged: Function = (): void => {}; 42 swiperController?: SwiperController; 43 isInSelectedMode: boolean = false; 44 @Consume canSwipe: boolean; 45 swiperItemSpace: number = Constants.NUMBER_8; 46 verifyPhotoScaledFunc: (matrix?: Matrix4.Matrix4Transit) => void = (matrix?: Matrix4.Matrix4Transit): void => {} 47 @Link isRunningAnimation: boolean; 48 isLeftSwiper: boolean = false; 49 @Consume isDeleting: boolean; 50 @State isOnSwiperAnimation: boolean = false; 51 private dataSource?: PhotoDataSource; 52 private geometryTransitionEnable: boolean = false; 53 private isFromFACard: boolean = false; 54 private SWIPE_CACHE_COUNT: number = 2; 55 private onDataReloadFunc: Function = (addCount: number): void => this.onDataReload(addCount); 56 private onChangeSwiperDurationFunc: Function = (value: number): void => this.onChangeSwiperDuration(value); 57 58 private onDataReload(addCount: number): void { 59 let totalCount = this.dataSource == null ? 0 : this.dataSource.totalCount(); 60 let add = addCount; 61 if (add > Constants.NUMBER_0) { 62 if (this.dataSource != null) { 63 this.dataSource.onDataReloaded(); 64 } 65 if (this.currentIndex + add < totalCount) { 66 this.currentIndex += add; 67 } 68 Log.info(TAG, `ON_DATA_RELOADED: ${this.currentIndex}, ${add}`); 69 return; 70 } 71 Log.debug(TAG, 'animate to data reloaded start'); 72 animateTo({ 73 duration: 300, // 删除动画时长 74 curve: Curves.cubicBezier(0.0, 0.0, 0.2, 1.0), // 减速曲线参数 75 onFinish: () => { 76 if (this.dataSource != null) { 77 let totalCount = this.dataSource.totalCount(); 78 this.dataSource.onDataChanged(this.currentIndex); 79 // UPDATE NEXT TWO DATA FOR AVOID NOT LOADING DATA 80 if (this.currentIndex + 1 < totalCount) { 81 this.dataSource.onDataChanged(this.currentIndex + 1); 82 } 83 if (this.currentIndex + 2 < totalCount) { 84 this.dataSource.onDataChanged(this.currentIndex + 2); 85 } 86 this.dataSource.onDataReloaded(); 87 } 88 } }, () => { 89 if (this.dataSource != null && this.isDeleting) { 90 this.dataSource.deleteData(this.currentIndex); 91 } 92 if (this.dataSource != null && this.currentIndex === this.dataSource.totalCount() || (this.isDeleting && this.isLeftSwiper && this.currentIndex > 0)) { 93 this.currentIndex--; 94 } 95 this.isDeleting = false; 96 }) 97 } 98 99 private onChangeSwiperDuration(value: number): void { 100 Log.debug(TAG, `change duration start ${value}`); 101 this.mDuration = value; 102 } 103 104 aboutToAppear() { 105 this.broadCast.on(BroadCastConstants.ON_DATA_RELOADED, this.onDataReloadFunc); 106 this.broadCast.on(BroadCastConstants.CHANGE_SWIPER_DURATION, this.onChangeSwiperDurationFunc); 107 } 108 109 aboutToDisappear(): void { 110 this.swiperController = undefined; 111 this.broadCast.off(BroadCastConstants.ON_DATA_RELOADED, this.onDataReloadFunc); 112 this.broadCast.off(BroadCastConstants.CHANGE_SWIPER_DURATION, this.onChangeSwiperDurationFunc); 113 } 114 115 build() { 116 Swiper(this.swiperController) { 117 LazyForEach(this.dataSource as PhotoDataSource, (item: Results, index?: number) => { 118 if (!!item) { 119 Column() { 120 PhotoItem({ 121 item: item.data, 122 mPosition: item.pos, 123 thumbnail: item.thumbnail, 124 transitionTag: this.mTransition ? this.mTransition : 'default_id', 125 verifyPhotoScaled: this.verifyPhotoScaledFunc, 126 albumUri: (this.dataSource == null ? '' : this.dataSource.getAlbumUri()), 127 geometryTransitionEnable: this.geometryTransitionEnable, 128 broadCast: $broadCast, 129 isRunningAnimation: $isRunningAnimation, 130 isFromFACard: this.isFromFACard, 131 isInSelectedMode: this.isInSelectedMode, 132 isOnSwiperAnimation: $isOnSwiperAnimation, 133 dataSource: this.dataSource 134 }) 135 }.zIndex(item.pos == this.currentIndex ? 2 : 1) 136 } 137 }, (item: Results, index?: number) => { 138 if (item == null || item == undefined) { 139 return JSON.stringify(item) + index; 140 } 141 return `${item.data.uri}_${item.data.size}_${item.data.orientation}_${index}`; 142 }) 143 } 144 .cachedCount(this.SWIPE_CACHE_COUNT) 145 .duration(BrowserConstants.PHOTO_SWIPE_DURATION) 146 .itemSpace(this.swiperItemSpace) 147 .onGestureSwipe(() => { 148 if (!this.isOnSwiperAnimation) { 149 this.isOnSwiperAnimation = true; 150 } 151 }) 152 .index(this.currentIndex) 153 .indicator(false) 154 .loop(false) 155 .onChange((index: number) => { 156 if (this.currentIndex - index == 1) { 157 this.isLeftSwiper = true; 158 } else if (this.currentIndex - index == -1) { 159 this.isLeftSwiper = false; 160 } 161 if (this.mDuration != 0) { 162 this.onPhotoChanged(index); 163 164 if (!!this.verifyPhotoScaledFunc) { 165 this.verifyPhotoScaledFunc(undefined) 166 } 167 } 168 }) 169 .disableSwipe(this.canSwipe) 170 .onAnimationStart((index: number) => { 171 this.isOnSwiperAnimation = true; 172 }) 173 .onAnimationEnd(() => { 174 this.isOnSwiperAnimation = false; 175 }) 176 } 177}