• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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