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