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 16class PrefetchCount { 17 private readonly itemsOnScreen: IItemsOnScreenProvider; 18 private readonly MAX_SCREENS = 4; 19 private readonly MIN_SCREENS = 0.6; 20 private min = 0; 21 private max = 0; 22 23 constructor(itemsOnScreen: IItemsOnScreenProvider) { 24 this.itemsOnScreen = itemsOnScreen; 25 this.itemsOnScreen.register(() => { 26 this.updateLimits(); 27 }); 28 } 29 30 private _prefetchCountValue = 0; 31 32 get prefetchCountValue(): number { 33 return this._prefetchCountValue; 34 } 35 36 set prefetchCountValue(v: number) { 37 this._prefetchCountValue = v; 38 Logger.log(`{"tm":${Date.now()},"prefetch_count":${v}}`); 39 } 40 41 private _currentLimit = 0; 42 43 get currentLimit(): number { 44 return this._currentLimit; 45 } 46 47 private _maxRatio = 0.5; 48 49 get maxRatio(): number { 50 return this._maxRatio; 51 } 52 53 set maxRatio(value: number) { 54 this._maxRatio = value; 55 this.updateCurrentLimit(); 56 } 57 58 getPrefetchCountByRatio(ratio: number): number { 59 return this.min + Math.ceil(ratio * (this.currentLimit - this.min)); 60 } 61 62 getRangeToPrefetch(totalCount: number): IndexRange { 63 const visibleRange = this.itemsOnScreen.visibleRange; 64 let start = 0; 65 let end = 0; 66 switch (this.itemsOnScreen.direction) { 67 case 'UNKNOWN': 68 start = Math.max(0, visibleRange.start - Math.round(this.prefetchCountValue)); 69 end = Math.min(totalCount, visibleRange.end + Math.round(this.prefetchCountValue)); 70 break; 71 case 'UP': 72 start = Math.max(0, visibleRange.start - Math.round(this.prefetchCountValue)); 73 end = Math.min(totalCount, visibleRange.end + Math.round(this.prefetchCountValue * 0.5)); 74 break; 75 case 'DOWN': 76 start = Math.max(0, visibleRange.start - Math.round(this.prefetchCountValue * 0.5)); 77 end = Math.min(totalCount, visibleRange.end + Math.round(this.prefetchCountValue)); 78 break; 79 } 80 return new IndexRange(start, end); 81 } 82 83 private updateLimits(): void { 84 this.min = Math.ceil(this.itemsOnScreen.meanValue * this.MIN_SCREENS); 85 this.max = Math.max(this.min, Math.ceil(this.MAX_SCREENS * this.itemsOnScreen.meanValue)); 86 this.updateCurrentLimit(); 87 } 88 89 private updateCurrentLimit(): void { 90 this._currentLimit = Math.max(this.min, Math.ceil(this.max * this._maxRatio)); 91 } 92} 93