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 { fileTree } from './component/dialog/FileMoveDialog'; 17bea4f105Sopenharmony_ciimport Logger from '../base/log/Logger'; 18bea4f105Sopenharmony_ciimport ErrorCodeConst from '../base//constants/ErrorCodeConst'; 19bea4f105Sopenharmony_ciimport { toast } from '../base/utils/Common'; 20bea4f105Sopenharmony_ciimport AbilityCommonUtil, { ResultCodePicker } from '../base/utils/AbilityCommonUtil'; 21bea4f105Sopenharmony_ciimport { SYSTEM_BAR_COLOR } from '../base/constants/UiConstant'; 22bea4f105Sopenharmony_ciimport StringUtil from '../base/utils/StringUtil'; 23bea4f105Sopenharmony_ciimport { FileUtil } from '../base/utils/FileUtil'; 24bea4f105Sopenharmony_ciimport ObjectUtil from '../base/utils/ObjectUtil'; 25bea4f105Sopenharmony_ciimport fileAccess from '@ohos.file.fileAccess'; 26bea4f105Sopenharmony_ciimport { ArrayUtil } from '../base/utils/ArrayUtil'; 27bea4f105Sopenharmony_ciimport { UiUtil } from '../base/utils/UiUtil'; 28bea4f105Sopenharmony_ciimport { StartModeOptions } from '../base/model/StartModeOptions'; 29bea4f105Sopenharmony_ciimport { FilePickerUtil } from '../base/utils/FilePickerUtil'; 30bea4f105Sopenharmony_ciimport { photoAccessHelper } from '@kit.MediaLibraryKit'; 31bea4f105Sopenharmony_ci 32bea4f105Sopenharmony_ciconst TAG = 'PathSelector'; 33bea4f105Sopenharmony_cilet storage = LocalStorage.getShared(); 34bea4f105Sopenharmony_ci 35bea4f105Sopenharmony_ci@Entry(storage) 36bea4f105Sopenharmony_ci@Component 37bea4f105Sopenharmony_cistruct PathSelector { 38bea4f105Sopenharmony_ci private startModeOptions: StartModeOptions = FilePickerUtil.getStartOptionsFromStorage(); 39bea4f105Sopenharmony_ci @State createResultType: number = ErrorCodeConst.PICKER.NORMAL; 40bea4f105Sopenharmony_ci 41bea4f105Sopenharmony_ci aboutToAppear() { 42bea4f105Sopenharmony_ci UiUtil.setWindowBackground(SYSTEM_BAR_COLOR.LIGHT_GRAY); 43bea4f105Sopenharmony_ci } 44bea4f105Sopenharmony_ci 45bea4f105Sopenharmony_ci async saveFileCallback(res, startModeOptions: StartModeOptions): Promise<void> { 46bea4f105Sopenharmony_ci if (res?.cancel) { 47bea4f105Sopenharmony_ci AbilityCommonUtil.terminatePathPicker([], ResultCodePicker.CANCEL, startModeOptions); 48bea4f105Sopenharmony_ci return; 49bea4f105Sopenharmony_ci } else { 50bea4f105Sopenharmony_ci let fileNameList = this.startModeOptions.newFileNames; 51bea4f105Sopenharmony_ci // 保存单个文件时文件名可修改,需使用修改后的文件名来创建文件 52bea4f105Sopenharmony_ci if (fileNameList.length <= 1) { 53bea4f105Sopenharmony_ci fileNameList = [res.fileName]; 54bea4f105Sopenharmony_ci } 55bea4f105Sopenharmony_ci this.saveFiles(res.selectUri, fileNameList).then((createdFileList) => { 56bea4f105Sopenharmony_ci AbilityCommonUtil.terminatePathPicker(createdFileList, ResultCodePicker.SUCCESS, startModeOptions); 57bea4f105Sopenharmony_ci }).catch((err) => { 58bea4f105Sopenharmony_ci let errorMessage = ''; 59bea4f105Sopenharmony_ci let errorCode = 0; 60bea4f105Sopenharmony_ci Logger.e(TAG, JSON.stringify(err)); 61bea4f105Sopenharmony_ci if (err.code) { 62bea4f105Sopenharmony_ci if (err.code === ErrorCodeConst.FILE_ACCESS.FILE_NAME_EXIST) { 63bea4f105Sopenharmony_ci errorMessage = 'Same name file already exists'; 64bea4f105Sopenharmony_ci errorCode = ErrorCodeConst.PICKER.FILE_NAME_EXIST; 65bea4f105Sopenharmony_ci this.createResultType = errorCode; 66bea4f105Sopenharmony_ci const pathName = startModeOptions.newFileNames; 67bea4f105Sopenharmony_ci let listLength: number = pathName.length; 68bea4f105Sopenharmony_ci if (listLength == 1) { 69bea4f105Sopenharmony_ci return; 70bea4f105Sopenharmony_ci } 71bea4f105Sopenharmony_ci } else if (err.code === ErrorCodeConst.FILE_ACCESS.FILE_NAME_INVALID) { 72bea4f105Sopenharmony_ci errorMessage = 'Invalid display name'; 73bea4f105Sopenharmony_ci errorCode = ErrorCodeConst.PICKER.FILE_NAME_INVALID; 74bea4f105Sopenharmony_ci } else { 75bea4f105Sopenharmony_ci errorMessage = 'File create failed'; 76bea4f105Sopenharmony_ci errorCode = ErrorCodeConst.PICKER.OTHER_ERROR; 77bea4f105Sopenharmony_ci } 78bea4f105Sopenharmony_ci } else { 79bea4f105Sopenharmony_ci errorMessage = err.message ? err.message : err; 80bea4f105Sopenharmony_ci errorCode = ErrorCodeConst.PICKER.OTHER_ERROR; 81bea4f105Sopenharmony_ci } 82bea4f105Sopenharmony_ci AbilityCommonUtil.terminatePathPicker([], errorCode, startModeOptions); 83bea4f105Sopenharmony_ci toast($r('app.string.save_file_fail')); 84bea4f105Sopenharmony_ci Logger.e(TAG, `path select error, errorCode: ${errorCode}, errorMessage: ${errorMessage}`); 85bea4f105Sopenharmony_ci }) 86bea4f105Sopenharmony_ci } 87bea4f105Sopenharmony_ci } 88bea4f105Sopenharmony_ci 89bea4f105Sopenharmony_ci /** 90bea4f105Sopenharmony_ci * PathPicker保存文件 91bea4f105Sopenharmony_ci * @param data SaveFilesParam 92bea4f105Sopenharmony_ci */ 93bea4f105Sopenharmony_ci async saveFiles(path: string, nameList: string[]): Promise<string[]> { 94bea4f105Sopenharmony_ci return new Promise(async (resolve, reject) => { 95bea4f105Sopenharmony_ci let fileAccessHelper = await FileUtil.getFileAccessHelperAsync(globalThis.abilityContext); 96bea4f105Sopenharmony_ci let dirPath = path; 97bea4f105Sopenharmony_ci if (StringUtil.isEmpty(dirPath)) { 98bea4f105Sopenharmony_ci dirPath = (await FileUtil.getFileInfoByRelativePath('Documents/', fileAccessHelper)).uri; 99bea4f105Sopenharmony_ci } 100bea4f105Sopenharmony_ci let fileNameArr = nameList; 101bea4f105Sopenharmony_ci let successArr: string[] = []; 102bea4f105Sopenharmony_ci let resultErr: any; 103bea4f105Sopenharmony_ci let len: number = fileNameArr.length; 104bea4f105Sopenharmony_ci let fileNameList: string[] = []; 105bea4f105Sopenharmony_ci if (len > 1) { 106bea4f105Sopenharmony_ci fileNameList = await this.getPickPathListFiles(dirPath, fileAccessHelper); 107bea4f105Sopenharmony_ci } 108bea4f105Sopenharmony_ci Logger.i(TAG, 'saveFiles createName: ' + JSON.stringify(fileNameArr) + ' ; '); 109bea4f105Sopenharmony_ci Logger.i(TAG, 'saveFiles subList: ' + JSON.stringify(fileNameList) + ' ; '); 110bea4f105Sopenharmony_ci for (let i = 0; i < len; i++) { 111bea4f105Sopenharmony_ci const currName = fileNameArr[i]; 112bea4f105Sopenharmony_ci let result; 113bea4f105Sopenharmony_ci if (len === 1) { 114bea4f105Sopenharmony_ci result = await FileUtil.createFile(fileAccessHelper, dirPath, currName); 115bea4f105Sopenharmony_ci } else { 116bea4f105Sopenharmony_ci result = await this.tryRenameFileOperate(fileAccessHelper, currName, dirPath, 0, fileNameList); 117bea4f105Sopenharmony_ci } 118bea4f105Sopenharmony_ci if (ObjectUtil.isUndefined(result.err)) { 119bea4f105Sopenharmony_ci Logger.i(TAG, 'saveFiles createOK: ' + result.uri); 120bea4f105Sopenharmony_ci successArr.push(result.uri); 121bea4f105Sopenharmony_ci continue; 122bea4f105Sopenharmony_ci } 123bea4f105Sopenharmony_ci Logger.i(TAG, 'saveFiles err: ' + result.err.code); 124bea4f105Sopenharmony_ci // 失败 125bea4f105Sopenharmony_ci resultErr = { code: result.err.code, message: result.err.message }; 126bea4f105Sopenharmony_ci let photoManageHelper: photoAccessHelper.PhotoAccessHelper = AbilityCommonUtil.getPhotoManageHelper(); 127bea4f105Sopenharmony_ci if (ObjectUtil.isNullOrUndefined(photoManageHelper)) { 128bea4f105Sopenharmony_ci break; 129bea4f105Sopenharmony_ci } 130bea4f105Sopenharmony_ci for (let i = 0; i < successArr.length; i++) { 131bea4f105Sopenharmony_ci await FileUtil.hardDelete(successArr[i]); 132bea4f105Sopenharmony_ci } 133bea4f105Sopenharmony_ci try { 134bea4f105Sopenharmony_ci photoManageHelper.release(); 135bea4f105Sopenharmony_ci } catch (e) { 136bea4f105Sopenharmony_ci Logger.e(TAG, 'mediaLibrary close error'); 137bea4f105Sopenharmony_ci } 138bea4f105Sopenharmony_ci successArr = []; 139bea4f105Sopenharmony_ci break; 140bea4f105Sopenharmony_ci } 141bea4f105Sopenharmony_ci 142bea4f105Sopenharmony_ci Logger.i(TAG, 'saveFiles end: ' + JSON.stringify(successArr)); 143bea4f105Sopenharmony_ci if (!ArrayUtil.isEmpty(successArr)) { 144bea4f105Sopenharmony_ci resolve(successArr); 145bea4f105Sopenharmony_ci } else { 146bea4f105Sopenharmony_ci reject(resultErr); 147bea4f105Sopenharmony_ci } 148bea4f105Sopenharmony_ci }) 149bea4f105Sopenharmony_ci } 150bea4f105Sopenharmony_ci 151bea4f105Sopenharmony_ci private async getPickPathListFiles(dirUri: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<string[]> { 152bea4f105Sopenharmony_ci let fileInfo: fileAccess.FileInfo = await FileUtil.getFileInfoByUri(dirUri, fileAccessHelper); 153bea4f105Sopenharmony_ci if (ObjectUtil.isNullOrUndefined(fileInfo) || !FileUtil.isFolder(fileInfo.mode)) { 154bea4f105Sopenharmony_ci return []; 155bea4f105Sopenharmony_ci } 156bea4f105Sopenharmony_ci return this.getFilesByIterator(fileInfo.listFile()); 157bea4f105Sopenharmony_ci } 158bea4f105Sopenharmony_ci 159bea4f105Sopenharmony_ci private getFilesByIterator(fileIterator: fileAccess.FileIterator): string[] { 160bea4f105Sopenharmony_ci if (ObjectUtil.isNull(fileIterator)) { 161bea4f105Sopenharmony_ci return null; 162bea4f105Sopenharmony_ci } 163bea4f105Sopenharmony_ci let result: string[] = []; 164bea4f105Sopenharmony_ci let isDone = false; 165bea4f105Sopenharmony_ci while (!isDone) { 166bea4f105Sopenharmony_ci try { 167bea4f105Sopenharmony_ci let nextFileInfo = fileIterator.next(); 168bea4f105Sopenharmony_ci isDone = nextFileInfo.done; 169bea4f105Sopenharmony_ci if (isDone) { 170bea4f105Sopenharmony_ci break; 171bea4f105Sopenharmony_ci } 172bea4f105Sopenharmony_ci let currFile = nextFileInfo.value; 173bea4f105Sopenharmony_ci if (!FileUtil.isFolder(currFile.mode)) { 174bea4f105Sopenharmony_ci result.push(currFile.fileName); 175bea4f105Sopenharmony_ci } 176bea4f105Sopenharmony_ci } catch (err) { 177bea4f105Sopenharmony_ci Logger.e(TAG, 'current File err: ' + JSON.stringify(err) + ', ' + err.toString()); 178bea4f105Sopenharmony_ci } 179bea4f105Sopenharmony_ci } 180bea4f105Sopenharmony_ci return result; 181bea4f105Sopenharmony_ci } 182bea4f105Sopenharmony_ci 183bea4f105Sopenharmony_ci private async tryRenameFileOperate(fileAccessHelper: fileAccess.FileAccessHelper, fileName: string, 184bea4f105Sopenharmony_ci dirUri: string, renameCount: number, fileNameList: string[] = []): Promise<{ 185bea4f105Sopenharmony_ci err, 186bea4f105Sopenharmony_ci uri 187bea4f105Sopenharmony_ci }> { 188bea4f105Sopenharmony_ci let index = fileName.lastIndexOf('.'); 189bea4f105Sopenharmony_ci let name = fileName; 190bea4f105Sopenharmony_ci let suffix = ''; 191bea4f105Sopenharmony_ci if (index !== -1) { 192bea4f105Sopenharmony_ci suffix = fileName.substring(index, fileName.length); 193bea4f105Sopenharmony_ci name = fileName.substring(0, index); 194bea4f105Sopenharmony_ci } 195bea4f105Sopenharmony_ci let hasReNameCount = FileUtil.getFileNameReName(name); 196bea4f105Sopenharmony_ci if (!ObjectUtil.isNullOrUndefined(hasReNameCount)) { 197bea4f105Sopenharmony_ci let num = Number(hasReNameCount[1]); 198bea4f105Sopenharmony_ci if (!isNaN(num)) { 199bea4f105Sopenharmony_ci name = hasReNameCount[0]; 200bea4f105Sopenharmony_ci renameCount = num; 201bea4f105Sopenharmony_ci } 202bea4f105Sopenharmony_ci } 203bea4f105Sopenharmony_ci 204bea4f105Sopenharmony_ci let newName = fileName; 205bea4f105Sopenharmony_ci while (true) { 206bea4f105Sopenharmony_ci newName = FileUtil.renameFile(name, renameCount++, suffix); 207bea4f105Sopenharmony_ci let index = this.getIndex(newName, fileNameList); 208bea4f105Sopenharmony_ci Logger.i(TAG, 'tryRenameFileOperate : ' + newName + ' ; index = ' + index); 209bea4f105Sopenharmony_ci if (index === -1) { 210bea4f105Sopenharmony_ci const result = await FileUtil.createFile(fileAccessHelper, dirUri, newName); 211bea4f105Sopenharmony_ci if (ObjectUtil.isUndefined(result.err)) { 212bea4f105Sopenharmony_ci Logger.i(TAG, 'tryRenameFileOperate createOK: ' + result.uri); 213bea4f105Sopenharmony_ci return result; 214bea4f105Sopenharmony_ci } else { 215bea4f105Sopenharmony_ci Logger.i(TAG, 'tryRenameFileOperate createFail: ' + JSON.stringify(result) + ' ; ' + newName); 216bea4f105Sopenharmony_ci if (result.err.code === ErrorCodeConst.FILE_ACCESS.FILE_NAME_EXIST) { 217bea4f105Sopenharmony_ci fileNameList.push(newName); 218bea4f105Sopenharmony_ci } else { 219bea4f105Sopenharmony_ci return result; 220bea4f105Sopenharmony_ci } 221bea4f105Sopenharmony_ci } 222bea4f105Sopenharmony_ci } 223bea4f105Sopenharmony_ci } 224bea4f105Sopenharmony_ci } 225bea4f105Sopenharmony_ci 226bea4f105Sopenharmony_ci private getIndex(fileName: string, fileNameList: string[] = []) { 227bea4f105Sopenharmony_ci return fileNameList.findIndex(value => value === fileName); 228bea4f105Sopenharmony_ci } 229bea4f105Sopenharmony_ci 230bea4f105Sopenharmony_ci build() { 231bea4f105Sopenharmony_ci if (this.startModeOptions.isUxt()) { 232bea4f105Sopenharmony_ci Column() { 233bea4f105Sopenharmony_ci }.bindSheet(true, this.mainContent(), { 234bea4f105Sopenharmony_ci height: '95%', 235bea4f105Sopenharmony_ci dragBar: false, 236bea4f105Sopenharmony_ci showClose: false, 237bea4f105Sopenharmony_ci preferType: SheetType.CENTER, 238bea4f105Sopenharmony_ci onAppear: () => { 239bea4f105Sopenharmony_ci }, 240bea4f105Sopenharmony_ci shouldDismiss: () => { 241bea4f105Sopenharmony_ci this.startModeOptions.session.terminateSelf(); 242bea4f105Sopenharmony_ci } 243bea4f105Sopenharmony_ci }) 244bea4f105Sopenharmony_ci } else { 245bea4f105Sopenharmony_ci this.mainContent() 246bea4f105Sopenharmony_ci } 247bea4f105Sopenharmony_ci } 248bea4f105Sopenharmony_ci 249bea4f105Sopenharmony_ci @Builder 250bea4f105Sopenharmony_ci mainContent() { 251bea4f105Sopenharmony_ci Row() { 252bea4f105Sopenharmony_ci fileTree({ 253bea4f105Sopenharmony_ci startModeOptions: this.startModeOptions, 254bea4f105Sopenharmony_ci createFileFailType: $createResultType, 255bea4f105Sopenharmony_ci moveCallback: (e) => { 256bea4f105Sopenharmony_ci this.saveFileCallback(e, this.startModeOptions); 257bea4f105Sopenharmony_ci } 258bea4f105Sopenharmony_ci }) 259bea4f105Sopenharmony_ci } 260bea4f105Sopenharmony_ci } 261bea4f105Sopenharmony_ci} 262