1/* 2 * Copyright (c) 2024 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 16interface IPrefetchRangeEvaluator { 17 get rangeToPrefetch(): IndexRange; 18 setTotal(totalItems: number): void; 19 visibleRangeChanged(minVisible: number, maxVisible: number): void; 20 itemPrefetched(index: number, fetchDuration: number): void; 21} 22 23class PrefetchRangeEvaluator implements IPrefetchRangeEvaluator { 24 private readonly itemsOnScreen = new ItemsOnScreenProvider(); 25 private readonly prefetchCount = new PrefetchCount(this.itemsOnScreen); 26 private readonly fetchedRegistry = new FetchedRegistry(); 27 private readonly prefetchRangeRatio = new PrefetchRangeRatio(this.itemsOnScreen, this.fetchedRegistry); 28 private totalItems = 0; 29 private rangeToPrefetch_ = new IndexRange(0, 0); 30 31 get rangeToPrefetch(): IndexRange { 32 return this.rangeToPrefetch_; 33 } 34 35 setTotal(totalItems: number): void { 36 this.totalItems = totalItems; 37 } 38 39 visibleRangeChanged(minVisible: number, maxVisible: number): void { 40 this.itemsOnScreen.update(minVisible, maxVisible); 41 42 Logger.log( 43 `visibleAreaChanged itemsOnScreen=${ 44 Math.abs(maxVisible - minVisible) + 1 45 }, meanImagesOnScreen=${this.itemsOnScreen.meanValue}, prefetchCountCurrentLimit=${this.prefetchCount.currentLimit}, prefetchCountMaxRatio=${this.prefetchCount.maxRatio}`, 46 ); 47 48 // +1 for inclusive maxVisible -> exclusive end 49 this.prefetchCount.prefetchCountValue = this.evaluatePrefetchCount('visible-area-changed'); 50 this.rangeToPrefetch_ = this.prefetchCount.getRangeToPrefetch(this.totalItems); 51 this.fetchedRegistry.updateRangeToPrefetch(this.rangeToPrefetch_); 52 } 53 54 itemPrefetched(index: number, fetchDuration: number): void { 55 let maxRatioChanged = false; 56 if (this.prefetchRangeRatio.update(fetchDuration) === 'ratio-changed') { 57 this.prefetchCount.maxRatio = this.prefetchRangeRatio.maxRatio; 58 maxRatioChanged = true; 59 Logger.log( 60 `choosePrefetchCountLimit prefetchCountMaxRatio=${this.prefetchCount.maxRatio}, prefetchCountCurrentLimit=${this.prefetchCount.currentLimit}`, 61 ); 62 } 63 64 this.fetchedRegistry.addFetched(index); 65 66 this.prefetchCount.prefetchCountValue = this.evaluatePrefetchCount('resolved', maxRatioChanged); 67 this.rangeToPrefetch_ = this.prefetchCount.getRangeToPrefetch(this.totalItems); 68 this.fetchedRegistry.updateRangeToPrefetch(this.rangeToPrefetch_); 69 } 70 71 private evaluatePrefetchCount(event: 'resolved' | 'visible-area-changed', maxRatioChanged?: boolean): number { 72 const ratio = this.prefetchRangeRatio.calculateRatio(this.prefetchCount.prefetchCountValue, this.totalItems); 73 let evaluatedPrefetchCount = this.prefetchCount.getPrefetchCountByRatio(ratio); 74 75 let nextRatio: number | undefined; 76 77 if (maxRatioChanged) { 78 nextRatio = this.prefetchRangeRatio.calculateRatio(evaluatedPrefetchCount, this.totalItems); 79 evaluatedPrefetchCount = this.prefetchCount.getPrefetchCountByRatio(nextRatio); 80 } 81 82 if ( 83 this.prefetchRangeRatio.range.contains(ratio) || 84 (event === 'resolved' && evaluatedPrefetchCount <= this.prefetchCount.prefetchCountValue) 85 ) { 86 return this.prefetchCount.prefetchCountValue; 87 } 88 89 this.prefetchRangeRatio.updateRatioRange(ratio); 90 Logger.log( 91 `evaluatePrefetchCount prefetchCount=${evaluatedPrefetchCount}, ratio=${ratio}, nextRatio=${nextRatio}, hysteresisRange=${this.prefetchRangeRatio.range}`, 92 ); 93 return evaluatedPrefetchCount; 94 } 95} 96