• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-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 { MILLISECOND } from '../../base/constants/Constant';
17import { formatSuffix, getResourceString } from '../../base/utils/Tools';
18import DateTimeUtil from '../../base/utils/DateTimeUtil';
19import { FileMimeTypeUtil } from '../../base/utils/FileMimeTypeUtil';
20import LanguageUtil from '../../base/utils/LanguageUtil';
21import { MimeType } from './MimeType';
22import { ThumbnailSize } from '../../base/constants/UiConstant';
23import { BasicDataSource } from './BasicDataSource';
24import AbilityCommonUtil, { ResultCodePicker } from '../../base/utils/AbilityCommonUtil';
25import { StartModeOptions } from '../../base/model/StartModeOptions';
26import { photoAccessHelper } from '@kit.MediaLibraryKit';
27import { dataSharePredicates } from '@kit.ArkData';
28
29const TAG = 'FileAssetModel';
30
31export class FileAssetLazyModel extends BasicDataSource {
32  private dataArray: FileAssetModel[] = [];
33  public dataCount: number = 0;
34
35  public totalCount(): number {
36    return this.dataArray.length;
37  }
38
39  public getDataArray(): FileAssetModel[] {
40    return this.dataArray;
41  }
42
43  public setData(data: FileAssetModel[]): void {
44    this.dataArray = [...data];
45    this.dataCount = this.dataArray.length;
46    this.notifyDataReload();
47  }
48
49  public getData(index: number): FileAssetModel {
50    return this.dataArray[index];
51  }
52
53  public selectAll(isSelected: boolean): void {
54    this.dataArray.forEach(item => {
55      item.isChecked = isSelected;
56    });
57  }
58
59  public getIndex(uri: string): number {
60    return this.dataArray.findIndex(item => item.uri === uri);
61  }
62
63  public getSelectedFileList(): FileAssetModel[] {
64    return this.dataArray.filter(item => item.isChecked);
65  }
66
67  public replaceData(index: number, data: FileAssetModel): void {
68    this.dataArray.splice(index, 1, data);
69    this.notifyDataChange(index);
70  }
71
72  public addData(index: number, data: FileAssetModel): void {
73    this.dataArray.splice(index, 0, data);
74    this.dataCount = this.dataArray.length;
75    this.notifyDataAdd(index);
76  }
77
78  public pushData(data: FileAssetModel): void {
79    this.dataArray.push(data);
80    this.dataCount = this.dataArray.length;
81    this.notifyDataAdd(this.dataArray.length - 1);
82  }
83
84  public deleteData(index: number): void {
85    this.dataArray.splice(index, 1);
86    this.dataCount = this.dataArray.length;
87    this.notifyDataDelete(index);
88  }
89}
90
91/**
92 * 媒体文件信息类
93 */
94export class FileAssetModel {
95  public id: number;
96  public uri: string;
97  public mimeType: string;
98  public mediaType: number;
99  public displayName: string;
100  public title: string;
101  public relativePath: string;
102  public parent: number;
103  public size: number;
104  public dateAdded: number;
105  public dateModified: number;
106  public dateTaken: number;
107  public artist: string;
108  public audioAlbum: string;
109  public width: number;
110  public height: number;
111  public orientation: number;
112  public duration: number;
113  public albumId: number;
114  public albumUri: string;
115  public albumName: string;
116  // MediaLibrary.FileAsset对象外的属性
117  public fileName: string;
118  public fullPath: string;
119  public isChecked: boolean = false;
120  public suffix: string = '';
121  public icon: Resource | PixelMap;
122  public gridIcon: Resource | PixelMap;
123  public localGridIcon: Resource | PixelMap;
124  public lastModifiedDate: string | Resource;
125  public thumbUri: string = '';
126  public sortLabel: string = '';
127  public mimeTypeObj: MimeType;
128
129  constructor(file: FileAssetModel) {
130    this.id = file.id;
131    this.uri = file.uri;
132    this.mimeType = file.mimeType;
133    this.mediaType = file.mediaType;
134    this.displayName = file.displayName;
135    this.title = file.title;
136    this.relativePath = file.relativePath;
137    this.parent = file.parent;
138    this.size = file.size;
139    this.dateAdded = file.dateAdded;
140    this.dateModified = file.dateModified * MILLISECOND.ONE_SECOND;
141    this.dateTaken = file.dateTaken;
142    this.artist = file.artist;
143    this.audioAlbum = file.audioAlbum;
144    this.width = file.width;
145    this.height = file.height;
146    this.orientation = file.orientation;
147    this.duration = file.duration;
148    this.albumId = file.albumId;
149    this.albumUri = file.albumUri;
150    this.albumName = file.albumName;
151
152    this.fileName = file.displayName;
153    this.mimeTypeObj = FileMimeTypeUtil.getFileMimeType(this.fileName);
154    this.fullPath = getFullPath(this);
155
156    let suffix = formatSuffix(this.fileName);
157    if (suffix !== undefined) {
158      this.suffix = suffix;
159    }
160    this.icon = this.mimeTypeObj.getResID();
161    this.gridIcon = this.mimeTypeObj.getGridResID();
162    this.localGridIcon = this.mimeTypeObj.getLocalGridResID();
163    this.lastModifiedDate = DateTimeUtil.getDateStringForCategory(this.dateModified);
164    this.sortLabel = file.sortLabel;
165    if (this.mimeTypeObj.isMedia()) {
166      this.thumbUri = `${this.uri}/thumbnail/${ThumbnailSize.WIDTH}/${ThumbnailSize.HEIGHT}`;
167    }
168  }
169
170  setFileName(fileName: string): void {
171    this.fileName = fileName;
172    this.mimeTypeObj = FileMimeTypeUtil.getFileMimeType(this.fileName);
173    this.fullPath = getFullPath(this);
174    this.icon = this.mimeTypeObj.getResID();
175    this.gridIcon = this.mimeTypeObj.getGridResID();
176    this.localGridIcon = this.mimeTypeObj.getLocalGridResID();
177    if (this.mimeTypeObj.isMedia()) {
178      this.thumbUri = `${this.uri}/thumbnail/${ThumbnailSize.WIDTH}/${ThumbnailSize.HEIGHT}`;
179    }
180  }
181
182  pickFile(startModeOptions: StartModeOptions): void {
183    AbilityCommonUtil.terminateFilePicker([this.uri], ResultCodePicker.SUCCESS, startModeOptions);
184  }
185}
186
187/**
188 * 对媒体文件进行排序
189 * @param dataList 待排序数组
190 * @param order 排序规则
191 * @param isDesc 是否倒序
192 * @return 排序后的数组
193 */
194function sortFileAssetList(dataList: FileAssetModel[]): FileAssetModel[] {
195  const language = LanguageUtil.getSystemLanguage();
196  return dataList.sort((a: FileAssetModel, b: FileAssetModel) => {
197    if (b.dateModified !== a.dateModified) {
198      return b.dateModified - a.dateModified;
199    } else {
200      return b.displayName.localeCompare(a.displayName, language);
201    }
202  })
203}
204
205/**
206 * 媒体库查询条件类
207 */
208export class MediaFetchOptions {
209  public selections: string = photoAccessHelper.PhotoKeys.PHOTO_TYPE + '=?';
210  public selectionArgs: string[] = [];
211  public order: string = photoAccessHelper.PhotoKeys.DATE_MODIFIED + ' DESC';
212  public uri: string = '';
213  public networkId: string = '';
214  public extendArgs: string = '';
215
216  constructor(mediaTypeArg: string = '') {
217    if (!mediaTypeArg) {
218      this.selections = '';
219    } else {
220      this.selectionArgs.push(mediaTypeArg);
221    }
222  }
223
224  /**
225   * 设置要查询文件的uri
226   */
227  setUri(uri: string): void {
228    this.uri = uri;
229  }
230
231  /**
232   * 追加其他查询条件
233   * @param selection 要查询的关键字
234   * @param selectionArg 要查询的值
235   */
236  addSelection(selection: photoAccessHelper.PhotoKeys, selectionArg: string) {
237    if (this.selections.length) {
238      this.selections += ` AND ${selection} = ? `;
239    } else {
240      this.selections = `${selection} = ?`;
241    }
242    this.selectionArgs.push(selectionArg);
243  }
244}
245
246/**
247 * 查询媒体库内指定类型的文件
248 * @param mediaFetchOptions 媒体库查询条件
249 * @return 文件列表
250 */
251export async function getMediaFileDuration(mediaFetchOptions: MediaFetchOptions): Promise<number> {
252  const photoManageHelper: photoAccessHelper.PhotoAccessHelper = AbilityCommonUtil.getPhotoManageHelper();
253  let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();
254  let fetchOptions: photoAccessHelper.FetchOptions = {
255    fetchColumns: mediaFetchOptions.selectionArgs,
256    predicates: predicates
257  };
258  if (!photoManageHelper) {
259    return 0;
260  }
261
262  let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> =
263    await photoManageHelper.getAssets(fetchOptions);
264  let photoAsset: photoAccessHelper.PhotoAsset = await fetchResult.getFirstObject();
265  let duration: photoAccessHelper.MemberType = photoAsset.get(photoAccessHelper.PhotoKeys.DURATION);
266  return Number(duration) ?? 0;
267}
268
269export function getDurationByUri(mediaType: photoAccessHelper.PhotoType, uri: string): Promise<number> {
270  const option = new MediaFetchOptions(mediaType.toString());
271  option.setUri(uri);
272  return getMediaFileDuration(option).then((res: number) => {
273    return res;
274  }).catch(() => {
275    return 0;
276  })
277}
278
279/**
280 * 根据文件名(后缀)判断媒体类型
281 * @param fileName 文件名
282 * @return 媒体类型photoAccessHelper.PhotoType
283 */
284export function getMediaType(fileName: string): photoAccessHelper.PhotoType {
285  const mimeType = FileMimeTypeUtil.getFileMimeType(fileName);
286  if (mimeType.isImage()) {
287    return photoAccessHelper.PhotoType.IMAGE;
288  } else if (mimeType.isVideo()) {
289    return photoAccessHelper.PhotoType.VIDEO;
290  } else {
291    return 0;
292  }
293}
294
295/**
296 * 获取文件的完整路径
297 * @param file 文件信息
298 * @return 完整路径
299 */
300export function getFullPath(file: FileAssetModel): string {
301  return getResourceString($r('app.string.myPhone')) + '/' + file.relativePath + file.fileName;
302}
303
304/**
305 * 设置文件列表排序后需要显示的label
306 * @param fileAssetList 文件列表
307 * @param order 排序规则
308 * @return 设置了label的文件数组
309 */
310export function addSortLabel(fileAssetList: FileAssetModel[]): FileAssetModel[] {
311  fileAssetList.forEach((fileAsset: FileAssetModel) => {
312    fileAsset.sortLabel = DateTimeUtil.getDateStringForCategory(fileAsset.dateModified);
313  });
314  return fileAssetList;
315}
316
317
318