1/** 2 * Copyright (c) 2023-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 BaseDataSource from '../datasource/BaseDataSource'; 17import { 18 Log, 19 CardItemInfo, 20 FormModel, 21 NumberConstants 22} from '@ohos/common'; 23import ArrayList from '@ohos.util.ArrayList'; 24import List from '@ohos.util.List'; 25import FormConstants from '../common/constants/FormConstants'; 26 27const TAG = 'CardsDataPool'; 28 29/** 30 * card resource pool 31 */ 32export default abstract class CardsDataPool { 33 private mDatasourceMap: Map<string, BaseDataSource> = new Map(); 34 private mLastStartIndex: number = 0; 35 private mLastEndIndex: number = 0; 36 private mDataSize: number = 0; 37 private SEPARATOR: string = '&'; 38 private mPoolDataMap: Map<string, ArrayList<CardItemInfo>> = new Map(); 39 mFormModel: FormModel = FormModel.getInstance(); 40 41 constructor() { 42 } 43 44 /** 45 * 添加数据到轮播卡片资源池 46 * 47 * @param dataSource 数据源 48 */ 49 addDataPool(dataSource: BaseDataSource): void { 50 if (dataSource !== null) { 51 this.mDatasourceMap.set(<string> dataSource.getName(), dataSource); 52 } 53 } 54 55 /** 56 * 更新卡轮播池的显示起始位置. 57 * 只需要刷新起始位置,在获取列表时动态计算结束位置. 58 */ 59 refreshPool(): void { 60 Log.showInfo(TAG, `There are ${this.mDataSize} cards in the card pool.`); 61 if (this.mLastEndIndex + NumberConstants.CONSTANT_NUMBER_ONE === this.mDataSize) { 62 this.mLastStartIndex = NumberConstants.CONSTANT_NUMBER_ZERO; 63 } else { 64 this.mLastStartIndex = this.mLastEndIndex + NumberConstants.CONSTANT_NUMBER_ONE; 65 } 66 } 67 68 /** 69 * 获取实际显示的卡片列表. 70 * 71 * @return 实际显示的卡片列表 72 */ 73 getShowDataList(): Promise<ArrayList<CardItemInfo>> { 74 Log.showInfo(TAG, 'getShowDataList'); 75 this.initData(); 76 return this.getDataList(); 77 } 78 79 private initData(): void { 80 this.mPoolDataMap = this.getOriginalDataList(); 81 } 82 83 /** 84 * 获取数据源map. 85 * 86 * @return 数据源map. 87 */ 88 protected getDataSourceMap(): Map<string, BaseDataSource> { 89 return this.mDatasourceMap; 90 } 91 92 private async filterData(): Promise<List<CardItemInfo>> { 93 let resultList: List<CardItemInfo> = new List(); 94 let dataList: List<CardItemInfo> = this.transMapToList(); 95 if (dataList.length === 0) { 96 return resultList; 97 } 98 let formSet: Set<string> = new Set(); 99 for (let i: number = 0; i < dataList.length; i++) { 100 let formUniqueKey: string = this.getFormUniqueKey(dataList.get(i)); 101 if (!formSet.has(formUniqueKey)) { 102 resultList.add(dataList.get(i)); 103 formSet.add(formUniqueKey); 104 } 105 } 106 return resultList; 107 } 108 109 private getOriginalDataList(): Map<string, ArrayList<CardItemInfo>> { 110 let resultMap: Map<string, ArrayList<CardItemInfo>> = new Map(); 111 let dataSourceMap: Map<string, BaseDataSource> = this.getDataSourceMap(); 112 if (dataSourceMap.size === 0) { 113 return resultMap; 114 } 115 for (let [dataSourceName, dataSource] of dataSourceMap.entries()) { 116 Log.showInfo(TAG, `get ${dataSourceName} cards`); 117 let dataList: ArrayList<CardItemInfo> = dataSource.getDataList(); 118 Log.showInfo(TAG, `FormDataSource: ${dataSourceName} has ${dataList?.length} cards`); 119 if (dataList !== null && dataList.length > 0) { 120 resultMap.set(dataSourceName, dataList); 121 } 122 } 123 return resultMap; 124 } 125 126 private async getDataList(): Promise<ArrayList<CardItemInfo>> { 127 let resultList: ArrayList<CardItemInfo> = new ArrayList(); 128 let dataList: List<CardItemInfo> = await this.filterData(); 129 if (dataList.length === 0) { 130 Log.showInfo(TAG, 'The card pool data is empty'); 131 return resultList; 132 } 133 this.mDataSize = dataList.length; 134 if (this.mLastStartIndex >= dataList.length) { 135 this.mLastStartIndex = NumberConstants.CONSTANT_NUMBER_ZERO; 136 } 137 let smallList: ArrayList<CardItemInfo> = new ArrayList(); 138 let mediumList: ArrayList<CardItemInfo> = new ArrayList(); 139 Log.showInfo(TAG, 'getDataList mLastStartIndex:' + this.mLastStartIndex + ' mLastEndIndex:' + this.mLastEndIndex); 140 let startIndex: number = this.getRecommendCardIndexEverytime(smallList, mediumList, dataList); 141 this.mLastEndIndex = startIndex; 142 if (mediumList.length === 0) { 143 this.mLastEndIndex = await this.getTransMediumFormIndex(startIndex, smallList, mediumList, dataList); 144 } 145 146 for (let i: number = 0; i < mediumList.length; i++) { 147 resultList.add(mediumList[i]); 148 } 149 for (let i: number = 0; i < smallList.length; i++) { 150 resultList.add(smallList[i]); 151 } 152 return resultList; 153 } 154 155 private getFormUniqueKey(formInfo: CardItemInfo): string { 156 if (formInfo === null) { 157 return ''; 158 } 159 return formInfo.moduleName + this.SEPARATOR + formInfo.bundleName + this.SEPARATOR + 160 formInfo.abilityName + this.SEPARATOR + formInfo.cardName + this.SEPARATOR + formInfo.cardDimension; 161 } 162 163 private async getTransMediumFormIndex(startIndex: number, smallList: ArrayList<CardItemInfo>, 164 mediumList: ArrayList<CardItemInfo>, dataList: List<CardItemInfo>): Promise<number> { 165 let allFormInfoList: CardItemInfo[] = await this.mFormModel.getAllFormsInfo(); 166 let mediumCardCount: number = this.getAddMediumCardCount(); 167 let mediumListTmp: ArrayList<CardItemInfo> = new ArrayList(); 168 for (let i: number = 0; i < smallList.length; i++) { 169 if (mediumList.length >= mediumCardCount) { 170 break; 171 } 172 let mediumForm: CardItemInfo = await this.getMediumForm(allFormInfoList, smallList[i]); 173 if (mediumForm !== null) { 174 Log.showInfo(TAG, `getMediumForm mediumForm: ${mediumForm.bundleName}`); 175 mediumList.add(mediumForm); 176 mediumListTmp.add(smallList[i]); 177 } 178 } 179 for (let i: number = 0; i < mediumListTmp.length; i++) { 180 smallList.remove(mediumListTmp[i]); 181 } 182 // 转换为大卡片后,恢复index 183 if (startIndex >= mediumListTmp.length) { 184 return startIndex - mediumListTmp.length; 185 } else { 186 return dataList.length - (mediumListTmp.length - startIndex); 187 } 188 } 189 190 private async getMediumForm(allFormInfoList: CardItemInfo[], abilityFormInfo: CardItemInfo): Promise<CardItemInfo> { 191 for (let i: number = 0; i < allFormInfoList.length; i++) { 192 if (abilityFormInfo.bundleName === allFormInfoList[i].bundleName && 193 allFormInfoList[i].cardDimension === FormConstants.MEDIUM_SIZE_SERVICE_FORM) { 194 return allFormInfoList[i]; 195 } 196 } 197 return null; 198 } 199 200 private getRecommendCardIndexEverytime(smallList: ArrayList<CardItemInfo>, mediumList: ArrayList<CardItemInfo>, 201 dataList: List<CardItemInfo>): number { 202 let columnCount: number = this.getRecommendCardColumnCount(); 203 let row: number = this.getRecommendCardRow(); 204 let perLineCount: number = this.getRecommendCardCountPerLine(); 205 let maxSmallCardCount: number = row / perLineCount * columnCount / perLineCount; 206 let size: number = 0; 207 let isBackOrigin: boolean = false; 208 let startIndex: number = this.mLastStartIndex; 209 while (!isBackOrigin && size < maxSmallCardCount) { 210 let cardItemInfo: CardItemInfo = dataList.get(startIndex); 211 if (cardItemInfo.cardDimension === FormConstants.SMALL_SIZE_SERVICE_FORM) { 212 smallList.add(cardItemInfo); 213 size++; 214 } 215 if (cardItemInfo.cardDimension === FormConstants.MEDIUM_SIZE_SERVICE_FORM) { 216 mediumList.add(cardItemInfo); 217 // 中卡片相当于两张小卡片. 218 size = size + perLineCount; 219 } 220 if (startIndex !== dataList.length - NumberConstants.CONSTANT_NUMBER_ONE) { 221 startIndex++; 222 } else { 223 startIndex = NumberConstants.CONSTANT_NUMBER_ZERO; 224 } 225 // 回到原点,需要结束循环 226 if (startIndex === this.mLastStartIndex) { 227 isBackOrigin = true; 228 } 229 } 230 return startIndex; 231 } 232 233 private getRecommendCardColumnCount(): number { 234 return <number> FormConstants.SERVICE_FORM_VIEW_FENCE_COUNT_PHONE; 235 } 236 237 private getRecommendCardCountPerLine(): number { 238 return <number> FormConstants.SERVICE_FORM_VIEW_SMALL_FORM_COUNT_EACH_ROW_PHONE; 239 } 240 241 private getRecommendCardRow(): number { 242 return <number> FormConstants.SERVICE_FORM_VIEW_FORM_ROW_PHONE; 243 } 244 245 private getAddMediumCardCount(): number { 246 return <number> FormConstants.SERVICE_FORM_VIEW_ALLOW_MEDIUM_FORM_COUNT_PHONE; 247 } 248 249 private transMapToList(): List<CardItemInfo> { 250 let resultList: List<CardItemInfo> = new List(); 251 if (this.mPoolDataMap.size === 0) { 252 return resultList; 253 } 254 for (let cardItemInfos of this.mPoolDataMap.values()) { 255 for (let i: number = 0; i < cardItemInfos.length; i++) { 256 resultList.add(cardItemInfos[i]); 257 } 258 } 259 return resultList; 260 } 261} 262