1/* 2 * Copyright (c) 2022 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 type { SmartPickerDataInterface } from '../interface/SmartPickerDataInterface'; 17import type common from '@ohos.app.ability.common'; 18import SmartPickerRecommendInfo from '../common/SmartPickerRecommendInfo'; 19import SmartPickerConstants from '../common/SmartPickerConstants'; 20import { Log } from '@ohos/common/src/main/ets/default/utils/Log'; 21import dataSharePredicates from '@ohos.data.dataSharePredicates'; 22import type { AsyncCallback } from '@ohos/common/src/main/ets/default/model/common/AsyncCallback'; 23import { MediaItem } from '@ohos/common/src/main/ets/default/model/browser/photo/MediaItem'; 24import type { QueryParam } from '@ohos/common/src/main/ets/default/model/browser/BrowserDataImpl'; 25import { SmartPickerUtils } from '../utils/SmartPickerUtils'; 26import { Constants } from '@ohos/common/src/main/ets/default/model/common/Constants'; 27import photoAccessHelper from '@ohos.file.photoAccessHelper'; 28import type SmartPickerDataAdapter from '../common/SmartPickerDataAdapter'; 29import type { RecommendationOptions } from '../common/SmartPickerManager'; 30import { StringUtil } from '@ohos/common/src/main/ets/default/utils/StringUtil'; 31 32const TAG: string = 'SmartPickerPhotosDataImpl'; 33 34export class SmartPickerPhotosDataImpl implements SmartPickerDataInterface { 35 private uriLabelAlbumMap: Map<string, photoAccessHelper.Album> = new Map<string, photoAccessHelper.Album>(); 36 private labelIdNameMap: Map<string, string> = new Map<string, string>(); 37 private context: common.Context; 38 private dataAdapter: SmartPickerDataAdapter; 39 40 constructor(context: common.Context, dataAdapter: SmartPickerDataAdapter) { 41 this.context = context; 42 this.dataAdapter = dataAdapter; 43 } 44 45 private resetData(): void { 46 this.uriLabelAlbumMap.clear(); 47 this.labelIdNameMap.clear(); 48 } 49 50 async getTabInfoList(recommendationOptions: RecommendationOptions, param?: string): Promise<Array<SmartPickerRecommendInfo>> { 51 this.resetData(); 52 let recommendationType = recommendationOptions.recommendationType; 53 if (recommendationType >= SmartPickerConstants.QR_OR_BAR_CODE && recommendationType <= SmartPickerConstants.PROFILE_PICTURE) { 54 this.addLabelIdNameInfo(recommendationType); 55 } 56 if (this.labelIdNameMap.size <= 0) { 57 Log.error(TAG, 'getTabInfoList labelIdNameMap size is 0'); 58 return []; 59 } 60 return this.getLabelAlbumTabInfoList(); 61 } 62 63 private addLabelIdNameInfo(recommendationType?: number): void { 64 try { 65 if (recommendationType !== undefined) { 66 switch (recommendationType) { 67 case SmartPickerConstants.QR_OR_BAR_CODE: 68 this.labelIdNameMap.set(SmartPickerConstants.LABEL_QR_CODE, SmartPickerConstants.NAME_QR_CODE); 69 this.labelIdNameMap.set(SmartPickerConstants.LABEL_BAR_CODE, SmartPickerConstants.NAME_BAR_CODE); 70 break; 71 case SmartPickerConstants.QR_CODE: 72 this.labelIdNameMap.set(SmartPickerConstants.LABEL_QR_CODE, SmartPickerConstants.NAME_QR_CODE); 73 break; 74 case SmartPickerConstants.BAR_CODE: 75 this.labelIdNameMap.set(SmartPickerConstants.LABEL_BAR_CODE, SmartPickerConstants.NAME_BAR_CODE); 76 break; 77 case SmartPickerConstants.ID_CARD: 78 this.labelIdNameMap.set(SmartPickerConstants.LABEL_ID_CARD, SmartPickerConstants.NAME_ID_CARD); 79 break; 80 case SmartPickerConstants.PROFILE_PICTURE: 81 this.labelIdNameMap.set(SmartPickerConstants.LABEL_AVATAR, SmartPickerConstants.NAME_AVATAR); 82 break; 83 } 84 } 85 } catch (err) { 86 Log.error(TAG, 'addLabelIdNameInfo err:' + err); 87 } 88 } 89 90 private buildFetchOptions(): photoAccessHelper.FetchOptions { 91 let dataPredicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates(); 92 let labelAlbumFetchOpt: photoAccessHelper.FetchOptions = { 93 fetchColumns: [], 94 predicates: dataPredicates 95 }; 96 return labelAlbumFetchOpt; 97 } 98 99 async getLabelAlbumTabInfoList(): Promise<Array<SmartPickerRecommendInfo>> { 100 try { 101 let photoHelper = photoAccessHelper.getPhotoAccessHelper(this.context); 102 let albumFetOpt = this.buildFetchOptions(); 103 albumFetOpt.predicates.in(SmartPickerConstants.LABEL_ID_KEY, Array.from(this.labelIdNameMap.keys())); 104 albumFetOpt.predicates.orderByAsc(SmartPickerConstants.LABEL_ID_KEY); 105 //@ts-ignore 106 let albumsFetchResult = await photoHelper.getAlbums(photoAccessHelper.AlbumKeys.SMART, 107 //@ts-ignore 108 photoAccessHelper.AlbumSubtype.CLASSIFY, albumFetOpt); 109 if (albumsFetchResult === undefined || albumsFetchResult === null || albumsFetchResult.getCount() <= 0) { 110 this.labelIdNameMap.clear(); 111 Log.error(TAG, 'albumsFetchResult is invalid'); 112 return []; 113 } 114 let albumList = await albumsFetchResult.getAllObjects(); 115 albumsFetchResult.close(); 116 let pickerRecommendInfoList: SmartPickerRecommendInfo[] = []; 117 for (let i = 0; i < albumList.length; i++) { 118 let album: photoAccessHelper.Album = albumList[i]; 119 if (album.count > 0) { 120 let tabInfo = this.buildTabInfoByAlbum(album); 121 pickerRecommendInfoList.push(tabInfo); 122 this.uriLabelAlbumMap.set(album.albumUri, album); 123 } else { 124 this.labelIdNameMap.delete(album.albumName); 125 } 126 } 127 return pickerRecommendInfoList; 128 } catch (err) { 129 Log.error(TAG, 'getLabelAlbumTabInfoList err' + err); 130 } 131 return []; 132 } 133 134 private buildTabInfoByAlbum(album: photoAccessHelper.Album): SmartPickerRecommendInfo { 135 let tabInfo = new SmartPickerRecommendInfo(); 136 tabInfo.setAlbumUri(album.albumUri); 137 tabInfo.setRecommendType(SmartPickerConstants.RECOMMEND_TYPE_LABEL); 138 tabInfo.setLabelId(album.albumName); 139 tabInfo.setTotalCount(album.count); 140 return tabInfo; 141 } 142 143 getData(callback: AsyncCallback<MediaItem[]>, param: QueryParam): void { 144 let albumUri = param.albumUri; 145 let start = param.start; 146 let count = param.count; 147 let filterMediaType = param.filterMediaType; 148 this.getLabelPhotoData(callback, albumUri, start, count, filterMediaType); 149 } 150 151 private getLabelPhotoData(callback: AsyncCallback<MediaItem[]>, albumUri: string, startIndex?: number, count?: number, filterMediaType?: string): void { 152 if (StringUtil.isEmpty(albumUri)) { 153 callback.callback([], albumUri); 154 return; 155 } 156 try { 157 let labelPhotoFetchOption = this.buildFetchOptions(); 158 labelPhotoFetchOption.predicates.limit(count, startIndex); 159 labelPhotoFetchOption.fetchColumns = Array.prototype.slice.call(SmartPickerConstants.ALL_IMAGE_VIDEO_FETCH_COLUMNS) as string[]; 160 let album = this.uriLabelAlbumMap.get(albumUri); 161 this.getPhotoAssetDataByAlbum(album, labelPhotoFetchOption).then(async (mediaItemList: Array<MediaItem>) => { 162 if (mediaItemList) { 163 callback.callback(mediaItemList, albumUri); 164 } else { 165 callback.callback([], albumUri); 166 } 167 }); 168 } catch (err) { 169 Log.error(TAG, 'getLabelPhotoData err:' + err); 170 callback.callback([], albumUri); 171 } 172 } 173 174 async getPhotoAssetDataByAlbum(album: photoAccessHelper.Album, fileFetchOpt: photoAccessHelper.FetchOptions): Promise<Array<MediaItem>> { 175 if (album === null || album === undefined) { 176 Log.error(TAG, 'getPhotoAssetDataByAlbum album is invalid'); 177 return []; 178 } 179 try { 180 let photoFetchResult = await album.getAssets(fileFetchOpt); 181 let fileAssetList = await photoFetchResult.getAllObjects(); 182 photoFetchResult.close(); 183 let mediaItemList: MediaItem[] = []; 184 for (let photoAsset of fileAssetList) { 185 let mediaItem: MediaItem = new MediaItem(photoAsset); 186 if (this.dataAdapter) { 187 mediaItem.setThumbnail(SmartPickerUtils.getThumbnailSafe(photoAsset.uri, String(photoAsset.get(Constants.KEY_FILE_DATA)))); 188 mediaItemList.push(mediaItem); 189 } 190 } 191 return mediaItemList; 192 } catch (err) { 193 Log.error(TAG, 'getPhotoAssetDataByAlbum err:' + err); 194 } 195 return []; 196 } 197 198 async getDataCount(albumUri: string, filterMediaType?: string): Promise<number> { 199 let count = 0; 200 if (!StringUtil.isEmpty(albumUri) && this.uriLabelAlbumMap.get(albumUri) !== undefined) { 201 let album = this.uriLabelAlbumMap.get(albumUri); 202 if (!filterMediaType) { 203 return album.count; 204 } 205 let fetchOpt = this.buildFetchOptions(); 206 fetchOpt.fetchColumns = Array.prototype.slice.call(SmartPickerConstants.ALL_IMAGE_VIDEO_FETCH_COLUMNS) as string[]; 207 let fetResult = await album.getAssets(fetchOpt); 208 count = fetResult.getCount(); 209 fetResult.close(); 210 } 211 return count; 212 } 213}