• 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 { toast } from '../../base/utils/Common';
17import { FileMimeTypeUtil } from '../../base/utils/FileMimeTypeUtil';
18import { FILE_SUFFIX, SELECT_MODE } from '../constants/Constant';
19import ObjectUtil from './ObjectUtil';
20import { ability, Want } from '@kit.AbilityKit';
21import Logger from '../log/Logger';
22import { PickerWindowType } from '../constants/FilePickerItems';
23import { StartModeOptions } from '../model/StartModeOptions';
24import AbilityCommonUtil from './AbilityCommonUtil';
25import ctx from '@ohos.app.ability.common';
26
27interface abilityResultInterface {
28  want: Want,
29  resultCode: number
30};
31
32const TAG = 'FilePickerUtil';
33
34export namespace FilePickerUtil {
35  export function returnAbilityResult(want: Want, resultCode: number, options: StartModeOptions) {
36    Logger.i(TAG, 'returnPicker start');
37    let context = getContext() as ctx.UIAbilityContext;
38    if (options.windowType === PickerWindowType.ABILITY) {
39      let abilityResult: abilityResultInterface = {
40        want: want,
41        resultCode: resultCode
42      };
43      Logger.i(TAG, 'terminateSelfWithResult start');
44      context.terminateSelfWithResult(abilityResult, (error) => {
45        Logger.e(TAG, 'terminateSelfWithResult is called = ' + error.code);
46      });
47    } else {
48      let abilityResult: ability.AbilityResult = {
49        resultCode: resultCode,
50        want: want
51      };
52      options.session?.terminateSelfWithResult(abilityResult, (error) => {
53        Logger.e(TAG, 'closeUIExtFilePicker terminateSelfWithResult is called = ' + error?.code);
54      });
55    }
56  }
57
58  export function getStartModeOptions(want: Want): StartModeOptions {
59    let options = new StartModeOptions();
60    if (!want) {
61      Logger.e(TAG, 'getDocumentSelectOptions want is undefined')
62      return options;
63    }
64    options.action = want.action as string || '';
65    options.callerAbilityName = want.parameters?.['ohos.aafwk.param.callerAbilityName'] as string || '';
66    options.callerBundleName = want.parameters?.['ohos.aafwk.param.callerBundleName'] as string || '';
67    options.callerUid = want?.parameters?.[AbilityCommonUtil.CALLER_UID] as number || 0;
68    options.defaultFilePathUri = want.parameters?.key_pick_dir_path as string || '';
69    options.extType = want.parameters?.extType as string || '';
70    options.pickerType = want.parameters?.pickerType as string || '';
71    if (options.isOpenFileMode()) {
72      options.fileSuffixFilters = want.parameters?.key_file_suffix_filter as string[] || [];
73      options.maxSelectNumber = want.parameters?.key_pick_num as number || 1;
74      options.setSelectMode(want.parameters?.key_select_mode as number);
75      options.isAuthMode = want.parameters?.key_auth_mode as boolean || false;
76    } else if (options.isCreateFileMode()) {
77      options.setNewFileNames(want.parameters?.key_pick_file_name as string[]);
78      options.fileSuffixChoices = want.parameters?.key_file_suffix_choices as string[] || [];
79    } else {
80      Logger.e(TAG, 'getDocumentSelectOptions mode is error')
81    }
82    Logger.i(TAG, 'getDocumentOptions : ' + JSON.stringify(options));
83    return options;
84  }
85
86  export function getStartOptionsFromStorage(): StartModeOptions {
87    let storage: LocalStorage = LocalStorage.getShared();
88    if (!storage) {
89      Logger.i(TAG, `Storage is null`)
90      return new StartModeOptions();
91    }
92    let options: StartModeOptions | undefined = storage.get<StartModeOptions>('startModeOptions');
93    if (options === undefined) {
94      options = new StartModeOptions();
95      storage.setOrCreate('startModeOptions', options);
96    }
97    return options;
98  }
99}
100
101/**
102 * 文件选择器文件状态
103 *
104 * @param item 文件对象
105 * @param checkedNum 选中数量
106 * @return 是否超限  选择类型是否不匹配
107 */
108export function pickerStatus(item, checkedNum, startModeOptions:StartModeOptions) {
109  return {
110    // 选择是否超限
111    exceedLimit: checkedNum >= globalThis.filePickNum && !item.isChecked,
112    // 选择类型是否不匹配
113    differentTypes: !checkFileSelectable(item, startModeOptions)
114  };
115}
116
117/**
118 * 根据文件后缀判断文件是否可选
119 * @param item
120 */
121function checkFileSelectable(item, startModeOptions: StartModeOptions): boolean {
122  // selectMode检查
123  let selectMode: number = startModeOptions.selectMode;
124  let isFolder = false;
125  if (ObjectUtil.hasKey(item, 'isFolder')) {
126    isFolder = item.isFolder;
127  }
128  // 文件夹模式,直接返回
129  if (selectMode === SELECT_MODE.FOLDER) {
130    return isFolder;
131  }
132
133  if (isFolder) {
134    // 混选模式下,文件夹直接返回
135    if (selectMode === SELECT_MODE.MIX) {
136      return true;
137    }
138    // 文件模式下,文件夹直接返回false
139    return false;
140  }
141  // 后缀检查
142  let keyFileSuffixFilter: string[] = startModeOptions.fileSuffixFilters;
143  if (Array.isArray(keyFileSuffixFilter) && keyFileSuffixFilter.length > 0) {
144    return checkFileSuffix(item.fileName, keyFileSuffixFilter);
145  }
146
147  // mimeType检查
148  return checkFileMimetype(item.fileName, startModeOptions);
149}
150
151/**
152 * 校验选中的文件后缀
153 *
154 * @param fileName 文件名称
155 * @param keyFileSuffixFilter 指定后缀
156 * @return 如果文件后缀满足三方指定,则返回true
157 */
158function checkFileSuffix(fileName: string, keyFileSuffixFilter: Array<string>): boolean {
159  if (keyFileSuffixFilter) {
160    if (fileName) {
161      const suffix = FILE_SUFFIX.SUFFIX_START + FileMimeTypeUtil.getFileSuffix(fileName);
162      if (keyFileSuffixFilter.includes(suffix)) {
163        return true;
164      }
165    }
166    return false;
167  }
168  return true;
169}
170
171/**
172 * 校验选中的文件mimetype
173 *
174 * @param fileName 文件名称
175 * @return 条件满足返回true
176 */
177function checkFileMimetype(fileName: string, startModeOptions: StartModeOptions): boolean {
178  if (!fileName) {
179    return false;
180  }
181  let keyPickTypeList: string[] = startModeOptions.phonePickerTypeList;
182  // 输入的类型全转换成小写,避免大小敏感问题
183  keyPickTypeList.forEach(item => item.toLowerCase());
184  // 类型列表为空或包含*或*/*时,可选择所有文件
185  if (!keyPickTypeList || keyPickTypeList.length === 0 ||
186  keyPickTypeList.includes('*') || keyPickTypeList.includes('*/*')) {
187    return true;
188  }
189
190  const mimeTypeObj = FileMimeTypeUtil.getFileMimeType(fileName);
191  const mimeType = mimeTypeObj.getMimeType();
192
193  // mimeType未知不可选
194  if (!mimeType) {
195    return false;
196  }
197
198  // mimeType完全匹配
199  if (keyPickTypeList.includes(mimeType)) {
200    return true;
201  }
202
203  let fileCategory = mimeType;
204  const index = mimeType.indexOf('/');
205  if (index > 0) {
206    fileCategory = mimeType.substring(0, index);
207  }
208  // 某一类文件
209  if (keyPickTypeList.includes(fileCategory) || keyPickTypeList.includes(`${fileCategory}/*`)) {
210    return true;
211  }
212
213  return false;
214}
215
216/**
217 * 文件选择器 选择超限提示
218 *
219 * @param isImmersion 是否沉浸式
220 */
221export const filePickerTip = (startModeOptions: StartModeOptions) => {
222  globalThis.abilityContext.resourceManager.getPluralString($r('app.plural.filePickerTip').id,
223    startModeOptions.maxSelectNumber)
224    .then((value) => {
225      toast(value)
226    })
227}
228
229
230