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