1/*
2 * Copyright (c) 2022-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 { AlbumDefine } from '../AlbumDefine';
17import { AlbumInfo } from './AlbumInfo';
18import type { AsyncCallback } from '../../common/AsyncCallback';
19import { BrowserDataImpl } from '../BrowserDataImpl';
20import type { Album, FetchOptions } from '../../../access/UserFileManagerAccess';
21import { UserFileManagerAccess } from '../../../access/UserFileManagerAccess';
22import { Log } from '../../../utils/Log';
23import { Constants } from '../../common/Constants';
24import { MediaItem } from '../photo/MediaItem';
25import { ImageUtil } from '../../../utils/ImageUtil';
26
27const TAG: string = 'common_AlbumDataImpl';
28
29type AlbumInfoEx = {
30  relativePath?: string
31};
32
33type QueryAlbumParam = {
34  filterMediaType?: string;
35  uris?: string[]
36};
37
38export type InitAlbumParam = {
39  deviceId?: string,
40  deviceName?: string,
41  moreInfo?: boolean
42};
43
44export type AlbumSimpleInfo = {
45  uris: string[],
46  count: number,
47  videoCount: number,
48};
49
50export class AlbumDataImpl extends BrowserDataImpl {
51  private moreInfo: boolean = false;
52
53  constructor(param: InitAlbumParam) {
54    super();
55
56    if (param && param.moreInfo) {
57      this.moreInfo = param.moreInfo
58    }
59  }
60
61  getDataByUri(uri: unknown) {
62  }
63
64  getData(callback: AsyncCallback<unknown>, param: QueryAlbumParam): void {
65    Log.info(TAG, 'load data  getData start : ' + param);
66    if (param == null) {
67      this.buildAlbums(callback);
68    } else if (param?.filterMediaType != undefined) {
69      this.buildAlbums(callback, param.filterMediaType);
70    } else {
71      // 删除相册时,计算图片视频数量
72      this.genAlbumsInfo(callback, param.uris);
73    }
74  }
75
76  async getDataByName(name: string, albumUri?: string): Promise<Album> {
77    let albums = await UserFileManagerAccess.getInstance().getUserAlbums(AlbumDefine.getAlbumFetchOptByName(name));
78    if (albums && albums.length > 0) {
79      let opt: FetchOptions = AlbumDefine.getFileFetchOpt();
80      let fileResult = await albums[0].getPhotoAssets(opt);
81      if (fileResult == null || fileResult == undefined) {
82        Log.warn(TAG, `not valid fileResult`);
83        return null;
84      }
85      let count = fileResult.getCount();
86      fileResult.close();
87      if (count <= 0) {
88        Log.warn(TAG, `Not valid album Name: ${albums[0].albumName}, URI: ${albums[0].albumUri}`);
89        return null;
90      }
91      return albums[0];
92    } else {
93      return null;
94    }
95  }
96
97  getDataCount(callback: AsyncCallback<unknown>, albumInfo: AlbumInfo): void {
98  }
99
100  getDataIndexByUri(callback: AsyncCallback<unknown>, param: QueryAlbumParam, uri: string): void {
101  }
102
103  getDataIndexById(callback: AsyncCallback<unknown>, param: QueryAlbumParam, id: number): void {
104  }
105
106  getMediaItemByUri(callback: AsyncCallback<unknown>, uri: string): void {
107  }
108
109  private async genAlbumsInfo(cb: AsyncCallback<AlbumSimpleInfo>, uris: string[]): Promise<void> {
110    Log.info(TAG, `genAlbumsInfo uris: ${JSON.stringify(uris)}`);
111    Log.info(TAG, 'load data  genAlbumsInfo start');
112
113    let res = {
114      uris: [],
115      count: 0,
116      videoCount: 0,
117    };
118
119    for (let uri of uris) {
120      let objects = await super.getItems(uri, Constants.INVALID, Constants.INVALID);
121      Log.info(TAG, `get album objects: uri: ${uri} length: ${objects.length}`);
122
123      res.count += objects.length;
124      for (let item of objects) {
125        if (item.fileType === UserFileManagerAccess.MEDIA_TYPE_VIDEO) {
126          res.videoCount++;
127        }
128        res.uris.push(item.uri);
129      }
130    }
131
132    Log.info(TAG, `genAlbumsInfo done`);
133    cb.callback(res);
134  }
135
136  private async buildAlbums(callback: AsyncCallback<AlbumInfo[]>, filterMediaType?: string) {
137    Log.debug(TAG, `buildAlbums`);
138    let sourceData = new Array<AlbumInfo>();
139    await this.getSystemAlbumsInfo(sourceData, filterMediaType);
140    await this.getUserAlbumsInfo(sourceData, filterMediaType);
141    await this.getTrashAlbumInfo(sourceData, filterMediaType);
142    callback.callback(sourceData);
143  }
144
145  private async getUserAlbumsInfo(albumArray: Array<AlbumInfo>, filterMediaType?: string): Promise<void> {
146    Log.info(TAG, 'getUserAlbumsInfo start');
147    let albums: Album[] = await UserFileManagerAccess.getInstance().getUserAlbums();
148    if (!albums) {
149      Log.error(TAG, 'getUserAlbumsInfo, albums undefined');
150    }
151    Log.info(TAG, `getUserAlbumsInfo fetch albums length : ${albums.length}`);
152    try {
153      for (let album of albums) {
154        let albumInfo: AlbumInfo = new AlbumInfo(album);
155        let albumName: string = await UserFileManagerAccess.getInstance().getAlbumName(album);
156        albumInfo.setAlbumName(albumName);
157        albumInfo.setFilterMediaType(filterMediaType as string);
158        let count = albumInfo.count;
159        albumInfo.setCount(count); // Waiting: album.count不为0时,在构造函数里直接获取
160        let videoCount = 0;
161        if (count > 0) {
162          // 没有相册,设置为第一张
163          let hasCoverUri: Boolean = false;
164          if (album.coverUri) {
165            await UserFileManagerAccess.getInstance().getFirstObject(AlbumDefine.getFileFetchOptByUri(album.coverUri)).then((obj) => {
166              if (obj && obj.obj) {
167                let mediaItem = new MediaItem(obj.obj);
168                mediaItem.setThumbnail(this.getThumbnailSafe(obj.obj.uri, String(obj.obj.get(Constants.KEY_FILE_DATA))));
169                albumInfo.setMediaItem(mediaItem);
170                albumInfo.setCoverUri(ImageUtil.calcThumbnail(obj.obj.uri, mediaItem.height, mediaItem.width));
171                hasCoverUri = true;
172              }
173            });
174          }
175          if (!hasCoverUri) {
176            await UserFileManagerAccess.getInstance().getAlbumFirstObject(album).then((obj) => {
177              if (obj) {
178                let mediaItem = new MediaItem(obj);
179                mediaItem.setThumbnail(this.getThumbnailSafe(obj.uri, String(obj.get(Constants.KEY_FILE_DATA))));
180                albumInfo.setMediaItem(mediaItem);
181                albumInfo.setCoverUri(ImageUtil.calcThumbnail(obj.uri, mediaItem.height, mediaItem.width));
182              }
183            });
184          }
185          // 相册的视频数量
186          videoCount = await this.getItemsCountOfAlbum(album, AlbumDefine.FILTER_MEDIA_TYPE_VIDEO);
187        }
188        albumInfo.setVideoCount(videoCount);
189        albumArray.push(albumInfo);
190        Log.info(TAG, `getUserAlbumsInfo done, albumInfo : ${JSON.stringify(albumInfo)}, albumArray length: ${albumArray.length}`);
191      }
192    } catch (error) {
193      Log.error(TAG, `getUserAlbumsInfo error occured: ${error}`);
194    }
195    Log.info(TAG, 'getUserAlbumsInfo done');
196  }
197
198  private async getSystemAlbumsInfo(albumArray: Array<AlbumInfo>, filterMediaType?: string): Promise<void> {
199    Log.debug(TAG, 'getSystemAlbumsInfo');
200
201    let albums: Album[] = await UserFileManagerAccess.getInstance().getSystemAlbums();
202    Log.debug(TAG, `getSystemAlbumsInfo albums is : ${albums}`);
203
204    if (albums) {
205      for (let album of albums) {
206        Log.info(TAG, `album ${JSON.stringify(album)}`)
207        let albumInfo: AlbumInfo = new AlbumInfo(album);
208        let count = await this.getItemsCount(album.albumUri);
209        // 系统相册为空时不展示
210        if (count === 0) {
211          continue;
212        }
213        albumInfo.setCount(count); // TODO album.count不为0时,在构造函数里直接获取
214        // 相册的视频数量
215        let videoCount = await this.getItemsCount(album.albumUri, AlbumDefine.FILTER_MEDIA_TYPE_VIDEO);
216        albumInfo.setVideoCount(videoCount);
217        let albumName: string = await UserFileManagerAccess.getInstance().getAlbumName(album);
218        albumInfo.setAlbumName(albumName);
219        albumInfo.setFilterMediaType(filterMediaType);
220        if (!album.coverUri) {
221          await UserFileManagerAccess.getInstance().getAlbumFirstObject(album).then((obj) => {
222            if (obj) {
223              let mediaItem = new MediaItem(obj);
224              mediaItem.setThumbnail(this.getThumbnailSafe(obj.uri, String(obj.get(Constants.KEY_FILE_DATA))));
225              albumInfo.setMediaItem(mediaItem);
226              albumInfo.setCoverUri(this.getThumbnailSafe(obj.uri, String(obj.get(Constants.KEY_FILE_DATA))));
227            }
228          });
229        } else {
230          await UserFileManagerAccess.getInstance().getFirstObject(AlbumDefine.getFileFetchOptByUri(album.coverUri)).then((obj) => {
231            if (obj) {
232              let mediaItem = new MediaItem(obj.obj);
233              mediaItem.setThumbnail(this.getThumbnailSafe(obj.obj.uri, String(obj.obj.get(Constants.KEY_FILE_DATA))));
234              albumInfo.setMediaItem(mediaItem);
235              albumInfo.setCoverUri(this.getThumbnailSafe(obj.obj.uri, String(obj.obj.get(Constants.KEY_FILE_DATA))));
236            }
237          });
238        }
239        Log.debug(TAG, `getSystemAlbumsInfo albumInfo is : ${albumInfo}`);
240        albumArray.push(albumInfo);
241        Log.debug(TAG, `getSystemAlbumsInfo albumArray length is : ${albumArray.length}`);
242      }
243    } else {
244      Log.error(TAG, 'Failed getSystemAlbumsInfo');
245    }
246
247    Log.debug(TAG, 'getSystemAlbumsInfo done');
248  }
249
250  private async getTrashAlbumInfo(albumArray: Array<AlbumInfo>, filterMediaType?: string): Promise<void> {
251    Log.info(TAG, 'getTrashAlbumInfo start');
252    let album: Album = await UserFileManagerAccess.getInstance().getTrashAlbum() as Album;
253    if (!album) {
254      Log.error(TAG, 'getTrashAlbumInfo, get album undefined');
255    }
256    let albumInfo: AlbumInfo = new AlbumInfo(album);
257    let count = albumInfo.count;
258    // 系统相册为空时不展示
259    if (count === 0) {
260      Log.warn(TAG, 'getTrashAlbumInfo count is 0');
261      return;
262    }
263    albumInfo.setCount(count);
264    let albumName: string = await UserFileManagerAccess.getInstance().getAlbumName(album) as string;
265    albumInfo.setAlbumName(albumName);
266    albumInfo.setFilterMediaType(filterMediaType as string);
267    albumArray.push(albumInfo);
268    Log.info(TAG, `getTrashAlbumInfo done, albumInfo : ${JSON.stringify(albumInfo)}, albumArray length: ${albumArray.length}`);
269  }
270}