• 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 MediaLibrary from '@ohos.multimedia.mediaLibrary'
17import { MILLISECOND } from '../../base/constants/Constant'
18import { formatSuffix, getResourceString } from '../../base/utils/Tools'
19import DateTimeUtil from '../../base/utils/DateTimeUtil'
20import { FileMimeTypeUtil } from '../../base/utils/FileMimeTypeUtil'
21import LanguageUtil from '../../base/utils/LanguageUtil'
22import ErrorCodeConst from '../../base/constants/ErrorCodeConst'
23import { MimeType } from './MimeType'
24import { THUMBNAIL_SIZE } from '../../base/constants/UiConstant'
25import { BasicDataSource } from './BasicDataSource'
26import Logger from '../../base/log/Logger'
27import AbilityCommonUtil from '../../base/utils/AbilityCommonUtil'
28
29const TAG = 'FileAssetModel'
30
31export class FileAssetLazyModel extends BasicDataSource {
32  private dataArray: FileAssetModel[] = []
33  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): 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, 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  id: number
96  uri: string
97  mimeType: string
98  mediaType: number
99  displayName: string
100  title: string
101  relativePath: string
102  parent: number
103  size: number
104  dateAdded: number
105  dateModified: number
106  dateTaken: number
107  artist: string
108  audioAlbum: string
109  width: number
110  height: number
111  orientation: number
112  duration: number
113  albumId: number
114  albumUri: string
115  albumName: string
116  // MediaLibrary.FileAsset对象外的属性
117  fileName: string
118  fullPath: string
119  isChecked: boolean = false
120  suffix: string
121  icon: Resource | PixelMap
122  gridIcon: Resource | PixelMap
123  localGridIcon: Resource | PixelMap
124  lastModifiedDate: string | Resource
125  thumbUri: string
126  sortLabel: string = ''
127  mimeTypeObj: MimeType
128
129  constructor(file) {
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    this.suffix = formatSuffix(file.fileName)
156    this.icon = this.mimeTypeObj.getResID()
157    this.gridIcon = this.mimeTypeObj.getGridResID()
158    this.localGridIcon = this.mimeTypeObj.getLocalGridResID()
159    this.lastModifiedDate = DateTimeUtil.getDateStringForCategory(this.dateModified)
160    this.sortLabel = file.sortLabel
161    if (this.mimeTypeObj.isMedia()) {
162      this.thumbUri = `${this.uri}/thumbnail/${THUMBNAIL_SIZE.WIDTH}/${THUMBNAIL_SIZE.HEIGHT}`
163    }
164  }
165
166  setFileName(fileName: string): void {
167    this.fileName = fileName
168    this.mimeTypeObj = FileMimeTypeUtil.getFileMimeType(this.fileName)
169    this.fullPath = getFullPath(this)
170    this.icon = this.mimeTypeObj.getResID()
171    this.gridIcon = this.mimeTypeObj.getGridResID()
172    this.localGridIcon = this.mimeTypeObj.getLocalGridResID()
173    if (this.mimeTypeObj.isMedia()) {
174      this.thumbUri = `${this.uri}/thumbnail/${THUMBNAIL_SIZE.WIDTH}/${THUMBNAIL_SIZE.HEIGHT}`
175    }
176  }
177
178  pickFile(): void {
179    AbilityCommonUtil.terminateFilePicker([this.uri], [this.fileName])
180  }
181}
182
183/**
184 * 对媒体文件进行排序
185 * @param dataList 待排序数组
186 * @param order 排序规则
187 * @param isDesc 是否倒序
188 * @return 排序后的数组
189 */
190function sortFileAssetList(dataList) {
191  const language = LanguageUtil.getSystemLanguage()
192  return dataList.sort((a, b) => {
193    if (b.dateModified !== a.dateModified) {
194      return b.dateModified - a.dateModified
195    } else {
196      return b.displayName.localeCompare(a.displayName, language)
197    }
198  })
199}
200
201/**
202 * 媒体库查询条件类
203 */
204export class MediaFetchOptions {
205  selections: string = MediaLibrary.FileKey.MEDIA_TYPE + '=?'
206  selectionArgs: Array<string> = []
207  order: string = MediaLibrary.FileKey.DATE_MODIFIED + " DESC"
208  uri: string
209  networkId: string
210  extendArgs: string
211
212  constructor(mediaTypeArg: string = '') {
213    if (!mediaTypeArg) {
214      this.selections = ''
215    } else {
216      this.selectionArgs.push(mediaTypeArg)
217    }
218  }
219
220  /**
221   * 设置要查询文件的uri
222   */
223  setUri(uri: string): void {
224    this.uri = uri
225  }
226
227  /**
228   * 追加其他查询条件
229   * @param selection 要查询的关键字
230   * @param selectionArg 要查询的值
231   */
232  addSelection(selection: MediaLibrary.FileKey, selectionArg: string) {
233    if (this.selections.length) {
234      this.selections += ` AND ${selection} = ? `
235    } else {
236      this.selections = `${selection} = ?`
237    }
238    this.selectionArgs.push(selectionArg)
239  }
240}
241
242/**
243 * 查询媒体库内指定类型的文件
244 * @param mediaFetchOptions 媒体库查询条件
245 * @return 文件列表
246 */
247export function getMediaFileAssets(mediaFetchOptions: MediaFetchOptions): Promise<FileAssetModel[]> {
248  const mediaLibrary = AbilityCommonUtil.getMediaLibrary()
249  if (!mediaLibrary) {
250    return Promise.resolve([])
251  }
252  return mediaLibrary.getFileAssets(mediaFetchOptions).then((fetchFileResult: MediaLibrary.FetchFileResult) => {
253    return fetchFileResult.getAllObject().then((fileAssetList: Array<MediaLibrary.FileAsset>) => {
254      let newFileAssetList = []
255      fileAssetList.forEach(fileAsset => {
256        newFileAssetList.push(new FileAssetModel(fileAsset))
257      })
258      newFileAssetList = addSortLabel(newFileAssetList)
259      newFileAssetList = sortFileAssetList(newFileAssetList)
260      return newFileAssetList
261    }).catch((err) => {
262      // 媒体库查询为空code返回3
263      if (err.code === ErrorCodeConst.FILE_ACCESS.GET_MEDIAFILE_NULL) {
264        Logger.e(TAG, 'no media file')
265        return []
266      }
267      return Promise.reject(err)
268    }).finally(() => {
269      fetchFileResult.close()
270    })
271  }).catch((err) => {
272    return Promise.reject(err)
273  })
274}
275
276/**
277 * 根据文件名(后缀)判断媒体类型
278 * @param fileName 文件名
279 * @return 媒体类型MediaLibrary.MediaType
280 */
281export function getMediaType(fileName: string): MediaLibrary.MediaType {
282  const mimeType = FileMimeTypeUtil.getFileMimeType(fileName)
283  if (mimeType.isImage()) {
284    return MediaLibrary.MediaType.IMAGE
285  } else if (mimeType.isVideo()) {
286    return MediaLibrary.MediaType.VIDEO
287  } else if (mimeType.isAudio()) {
288    return MediaLibrary.MediaType.AUDIO
289  } else {
290    return MediaLibrary.MediaType.FILE
291  }
292}
293
294export function getDurationByUri(mediaType: MediaLibrary.MediaType, uri: string): Promise<number> {
295  const option = new MediaFetchOptions(mediaType.toString())
296  option.setUri(uri)
297  return getMediaFileAssets(option).then((res) => {
298    if (res && res.length) {
299      return res[0].duration
300    } else {
301      return 0
302    }
303  }).catch(() => {
304    return 0
305  })
306}
307
308/**
309 * 获取文件的完整路径
310 * @param file 文件信息
311 * @return 完整路径
312 */
313export function getFullPath(file: FileAssetModel): string {
314  return getResourceString($r('app.string.myPhone')) + '/' + file.relativePath + file.fileName
315}
316
317/**
318 * 设置文件列表排序后需要显示的label
319 * @param fileAssetList 文件列表
320 * @param order 排序规则
321 * @return 设置了label的文件数组
322 */
323export function addSortLabel(fileAssetList): FileAssetModel[] {
324  fileAssetList.forEach((fileAsset: FileAssetModel) => {
325    fileAsset.sortLabel = DateTimeUtil.getDateStringForCategory(fileAsset.dateModified)
326  })
327  return fileAssetList
328}
329
330
331