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 { FilesData } from '../../databases/model/FileData';
17bea4f105Sopenharmony_ciimport { on } from '../../base/utils/EventBus';
18bea4f105Sopenharmony_ciimport FileAccessExec from '../../base/utils/FileAccessExec';
19bea4f105Sopenharmony_ciimport { TREE_LAYER } from '../../base/constants/UiConstant';
20bea4f105Sopenharmony_ciimport { FOLDER_LEVEL } from '../../base/constants/Constant';
21bea4f105Sopenharmony_ciimport { FileUtil } from '../../base/utils/FileUtil';
22bea4f105Sopenharmony_ciimport { ArrayUtil } from '../../base/utils/ArrayUtil';
23bea4f105Sopenharmony_ciimport { FileBase } from '../../databases/model/base/FileBase';
24bea4f105Sopenharmony_ciimport Logger from '../../base/log/Logger';
25bea4f105Sopenharmony_ciimport fileAccess from '@ohos.file.fileAccess';
26bea4f105Sopenharmony_ciimport ObjectUtil from '../../base/utils/ObjectUtil';
27bea4f105Sopenharmony_ci
28bea4f105Sopenharmony_ci@Styles
29bea4f105Sopenharmony_cifunction pressedStyles() {
30bea4f105Sopenharmony_ci  .backgroundColor($r('app.color.hicloud_hmos_bg'))
31bea4f105Sopenharmony_ci}
32bea4f105Sopenharmony_ci
33bea4f105Sopenharmony_ciconst TAG = 'TreeItem';
34bea4f105Sopenharmony_ci
35bea4f105Sopenharmony_ci@Component
36bea4f105Sopenharmony_ciexport struct TreeItem {
37bea4f105Sopenharmony_ci  fileItem: FilesData = new FilesData({});
38bea4f105Sopenharmony_ci  loadPath?: string = '';
39bea4f105Sopenharmony_ci  isNeedExpand: boolean = false;
40bea4f105Sopenharmony_ci  @State iconRotate: boolean = false;
41bea4f105Sopenharmony_ci  @State subFolderList: FilesData[] = [];
42bea4f105Sopenharmony_ci  @Link chooseItem: FilesData;
43bea4f105Sopenharmony_ci  @Link selectUri: string;
44bea4f105Sopenharmony_ci  @Link selectName: string;
45bea4f105Sopenharmony_ci  @Link fileList: FilesData[];
46bea4f105Sopenharmony_ci  @Link folderList: FilesData[];
47bea4f105Sopenharmony_ci  @State isShowArrow: boolean = true;
48bea4f105Sopenharmony_ci  @Prop layer: number;
49bea4f105Sopenharmony_ci  @State isLoading: boolean = false;
50bea4f105Sopenharmony_ci  @Link @Watch('clickExpandChange') isClickExpand: boolean;
51bea4f105Sopenharmony_ci
52bea4f105Sopenharmony_ci  private changeSelectItem(selectedItem: FilesData, autoShow: boolean) {
53bea4f105Sopenharmony_ci    if (selectedItem) {
54bea4f105Sopenharmony_ci      selectedItem.autoShow = autoShow;
55bea4f105Sopenharmony_ci      this.chooseItem = selectedItem;
56bea4f105Sopenharmony_ci      this.selectUri = this.chooseItem.uri;
57bea4f105Sopenharmony_ci      this.selectName = this.chooseItem.fileName;
58bea4f105Sopenharmony_ci    }
59bea4f105Sopenharmony_ci  }
60bea4f105Sopenharmony_ci
61bea4f105Sopenharmony_ci  private async executeQuery(dirUri: string, defaultExpandPath: string, call: Function) {
62bea4f105Sopenharmony_ci    this.isLoading = true;
63bea4f105Sopenharmony_ci    if (!this.isNeedExpand || (this.isNeedExpand && !this.isClickExpand)) {
64bea4f105Sopenharmony_ci      this.changeSelectItem(this.fileItem, false);
65bea4f105Sopenharmony_ci    }
66bea4f105Sopenharmony_ci
67bea4f105Sopenharmony_ci    let queryRes = await this.getPickPathListFiles(dirUri, defaultExpandPath, this.fileItem.layer);
68bea4f105Sopenharmony_ci    this.isLoading = false;
69bea4f105Sopenharmony_ci    let subList: FilesData[] = this.fileBaseToFileData(queryRes);
70bea4f105Sopenharmony_ci    let { folderList, fileList } = this.transfer(subList);
71bea4f105Sopenharmony_ci    this.fileList = fileList
72bea4f105Sopenharmony_ci    call(folderList);
73bea4f105Sopenharmony_ci  }
74bea4f105Sopenharmony_ci
75bea4f105Sopenharmony_ci  private async getPickPathListFiles(dirUri: string, expandPath: string, level: number): Promise<FileBase[]> {
76bea4f105Sopenharmony_ci    let fileHelper = await FileUtil.getFileAccessHelperAsync(getContext());
77bea4f105Sopenharmony_ci    let fileInfo: fileAccess.FileInfo = await FileUtil.getFileInfoByUri(dirUri, fileHelper);
78bea4f105Sopenharmony_ci    if (ObjectUtil.isNullOrUndefined(fileInfo) || !FileUtil.isFolder(fileInfo.mode)) {
79bea4f105Sopenharmony_ci      Logger.e(TAG, 'uri is not folder');
80bea4f105Sopenharmony_ci      return;
81bea4f105Sopenharmony_ci    }
82bea4f105Sopenharmony_ci    let queryRes = FileAccessExec.getPathPickSubFiles(fileInfo, expandPath, level);
83bea4f105Sopenharmony_ci    if (ObjectUtil.isNull(queryRes)) {
84bea4f105Sopenharmony_ci      Logger.e(TAG, 'files is null');
85bea4f105Sopenharmony_ci      return;
86bea4f105Sopenharmony_ci    }
87bea4f105Sopenharmony_ci    return queryRes;
88bea4f105Sopenharmony_ci  }
89bea4f105Sopenharmony_ci
90bea4f105Sopenharmony_ci  transfer(list: FilesData[]) {
91bea4f105Sopenharmony_ci    let folderList: FilesData[] = [];
92bea4f105Sopenharmony_ci    let fileList: FilesData[] = [];
93bea4f105Sopenharmony_ci    if (ArrayUtil.isEmpty(list)) {
94bea4f105Sopenharmony_ci      return { folderList, fileList };
95bea4f105Sopenharmony_ci    }
96bea4f105Sopenharmony_ci    for (let i = 0; i < list.length; i++) {
97bea4f105Sopenharmony_ci      let fileData = list[i];
98bea4f105Sopenharmony_ci      if (fileData.isFolder) {
99bea4f105Sopenharmony_ci        folderList.push(fileData);
100bea4f105Sopenharmony_ci      } else {
101bea4f105Sopenharmony_ci        fileList.push(fileData);
102bea4f105Sopenharmony_ci      }
103bea4f105Sopenharmony_ci    }
104bea4f105Sopenharmony_ci    return { folderList, fileList };
105bea4f105Sopenharmony_ci  }
106bea4f105Sopenharmony_ci
107bea4f105Sopenharmony_ci  fileBaseToFileData(list: FileBase[]): FilesData[] {
108bea4f105Sopenharmony_ci    let fileArray: FilesData[] = [];
109bea4f105Sopenharmony_ci    if (ArrayUtil.isEmpty(list)) {
110bea4f105Sopenharmony_ci      return fileArray;
111bea4f105Sopenharmony_ci    }
112bea4f105Sopenharmony_ci    for (let i = 0; i < list.length; i++) {
113bea4f105Sopenharmony_ci      let data = list[i];
114bea4f105Sopenharmony_ci      let fileData = new FilesData([]);
115bea4f105Sopenharmony_ci      fileData.uri = data.uri;
116bea4f105Sopenharmony_ci      fileData.fileName = data.fileName;
117bea4f105Sopenharmony_ci      fileData.isFolder = data.isFolder;
118bea4f105Sopenharmony_ci      fileData.size = data.fileSize;
119bea4f105Sopenharmony_ci      fileData.mtime = data.modifyTime;
120bea4f105Sopenharmony_ci      fileData.path = data.relativePath;
121bea4f105Sopenharmony_ci      fileData.currentDir = data.currentDir;
122bea4f105Sopenharmony_ci      if (data.isFolder) {
123bea4f105Sopenharmony_ci        if (!ArrayUtil.isEmpty(data.subList)) {
124bea4f105Sopenharmony_ci          fileData.setSubList(this.fileBaseToFileData(data.subList));
125bea4f105Sopenharmony_ci        }
126bea4f105Sopenharmony_ci      }
127bea4f105Sopenharmony_ci      fileArray.push(fileData);
128bea4f105Sopenharmony_ci    }
129bea4f105Sopenharmony_ci    return fileArray;
130bea4f105Sopenharmony_ci  }
131bea4f105Sopenharmony_ci
132bea4f105Sopenharmony_ci  /**
133bea4f105Sopenharmony_ci   * 是否需要展开目录,如果最近保存的目录不为空,需要展开到最近保存的目录
134bea4f105Sopenharmony_ci   *
135bea4f105Sopenharmony_ci   * @returns true:需要展开目录
136bea4f105Sopenharmony_ci   */
137bea4f105Sopenharmony_ci  needExpandPath(): boolean {
138bea4f105Sopenharmony_ci    if (!this.canExpandPath() || this.isClickExpand) {
139bea4f105Sopenharmony_ci      return false;
140bea4f105Sopenharmony_ci    }
141bea4f105Sopenharmony_ci    return FileUtil.hasSubFolder(this.loadPath, this.fileItem.currentDir);
142bea4f105Sopenharmony_ci  }
143bea4f105Sopenharmony_ci
144bea4f105Sopenharmony_ci  clickExpandChange() {
145bea4f105Sopenharmony_ci    this.isNeedExpand = false;
146bea4f105Sopenharmony_ci    this.loadPath = '';
147bea4f105Sopenharmony_ci  }
148bea4f105Sopenharmony_ci
149bea4f105Sopenharmony_ci  canExpandPath(): boolean {
150bea4f105Sopenharmony_ci    return this.layer <= FOLDER_LEVEL.MAX_LEVEL;
151bea4f105Sopenharmony_ci  }
152bea4f105Sopenharmony_ci
153bea4f105Sopenharmony_ci  loadSubFolder(subFolderList: FilesData[]) {
154bea4f105Sopenharmony_ci    this.subFolderList = subFolderList;
155bea4f105Sopenharmony_ci    this.folderList = this.subFolderList;
156bea4f105Sopenharmony_ci    this.fileItem.setSubFolderList(subFolderList);
157bea4f105Sopenharmony_ci    Logger.i(TAG, 'loadSubFolder:selectUri = ' + this.selectUri +
158bea4f105Sopenharmony_ci      ' ; subFolderListSize = ' + this.subFolderList.length +
159bea4f105Sopenharmony_ci      ' ; iconRotate = ' + this.iconRotate);
160bea4f105Sopenharmony_ci  }
161bea4f105Sopenharmony_ci
162bea4f105Sopenharmony_ci  aboutToAppear() {
163bea4f105Sopenharmony_ci    on('fileMkdir', async (e) => {
164bea4f105Sopenharmony_ci      if (this.selectUri === this.fileItem.uri) {
165bea4f105Sopenharmony_ci        // 获取当前选中文件夹下的所有子文件
166bea4f105Sopenharmony_ci        let queryArray = await this.getPickPathListFiles(this.fileItem.uri, '', this.fileItem.layer);
167bea4f105Sopenharmony_ci        let subList: FilesData[] = this.fileBaseToFileData(queryArray);
168bea4f105Sopenharmony_ci        let { folderList, fileList } = this.transfer(subList);
169bea4f105Sopenharmony_ci        this.fileList = fileList;
170bea4f105Sopenharmony_ci        // 获取当前选中文件夹下的所有子文件
171bea4f105Sopenharmony_ci        this.subFolderList = folderList;
172bea4f105Sopenharmony_ci        this.expandSubFolderCall(folderList);
173bea4f105Sopenharmony_ci        // 查找刚刚新建的文件夹index
174bea4f105Sopenharmony_ci        const index = this.subFolderList.findIndex(item => item.fileName === e.mkdirName);
175bea4f105Sopenharmony_ci        if (index !== -1 && this.canExpandPath()) {
176bea4f105Sopenharmony_ci          // 默认选中刚刚新建的文件夹
177bea4f105Sopenharmony_ci          this.changeSelectItem(this.subFolderList[index], true);
178bea4f105Sopenharmony_ci          this.iconRotate = true;
179bea4f105Sopenharmony_ci          this.fileList = [];
180bea4f105Sopenharmony_ci          this.folderList = [];
181bea4f105Sopenharmony_ci        }
182bea4f105Sopenharmony_ci      }
183bea4f105Sopenharmony_ci    })
184bea4f105Sopenharmony_ci
185bea4f105Sopenharmony_ci    this.fileItem.setLayer(this.layer);
186bea4f105Sopenharmony_ci    this.isNeedExpand = this.needExpandPath();
187bea4f105Sopenharmony_ci    if (this.isNeedExpand) {
188bea4f105Sopenharmony_ci      Logger.i(TAG, 'NeedExpand:loadPath = ' + this.loadPath +
189bea4f105Sopenharmony_ci        ' ; path = ' + this.fileItem.currentDir);
190bea4f105Sopenharmony_ci      this.clickExpand(false);
191bea4f105Sopenharmony_ci    }
192bea4f105Sopenharmony_ci  }
193bea4f105Sopenharmony_ci
194bea4f105Sopenharmony_ci  clickExpand(forceLoading: boolean) {
195bea4f105Sopenharmony_ci    if (!this.isLoading) {
196bea4f105Sopenharmony_ci      if (this.iconRotate) {
197bea4f105Sopenharmony_ci        this.iconRotate = !this.iconRotate;
198bea4f105Sopenharmony_ci        this.changeSelectItem(this.fileItem, false);
199bea4f105Sopenharmony_ci        this.fileItem.subFileList = null;
200bea4f105Sopenharmony_ci        this.folderList = this.fileItem.subFolderList;
201bea4f105Sopenharmony_ci      } else {
202bea4f105Sopenharmony_ci        if (this.canExpandPath()) {
203bea4f105Sopenharmony_ci          if (this.fileItem.hasSubFolderList() && !forceLoading) {
204bea4f105Sopenharmony_ci            this.changeSelectItem(this.fileItem, false);
205bea4f105Sopenharmony_ci            this.fileList = this.fileItem.subFileList;
206bea4f105Sopenharmony_ci            this.expandSubFolderCall(this.fileItem.getSubFolderList());
207bea4f105Sopenharmony_ci          } else {
208bea4f105Sopenharmony_ci            this.executeQuery(this.fileItem.uri, this.loadPath, this.expandSubFolderCall.bind(this));
209bea4f105Sopenharmony_ci          }
210bea4f105Sopenharmony_ci        }
211bea4f105Sopenharmony_ci      }
212bea4f105Sopenharmony_ci    }
213bea4f105Sopenharmony_ci  }
214bea4f105Sopenharmony_ci
215bea4f105Sopenharmony_ci  private expandSubFolderCall(subFolderList: FilesData[]) {
216bea4f105Sopenharmony_ci    this.iconRotate = !this.iconRotate;
217bea4f105Sopenharmony_ci    this.loadSubFolder(subFolderList);
218bea4f105Sopenharmony_ci    this.isShowArrow = this.subFolderList.length !== 0;
219bea4f105Sopenharmony_ci  }
220bea4f105Sopenharmony_ci
221bea4f105Sopenharmony_ci  build() {
222bea4f105Sopenharmony_ci    Column() {
223bea4f105Sopenharmony_ci      Row() {
224bea4f105Sopenharmony_ci        Image($r('app.media.hidisk_ic_list_empty_folder'))
225bea4f105Sopenharmony_ci          .objectFit(ImageFit.Contain)
226bea4f105Sopenharmony_ci          .renderMode(ImageRenderMode.Original)
227bea4f105Sopenharmony_ci          .aspectRatio(1)
228bea4f105Sopenharmony_ci          .width($r('app.float.common_size24'))
229bea4f105Sopenharmony_ci          .alignSelf(ItemAlign.Center)
230bea4f105Sopenharmony_ci          .margin({ right: $r('app.float.common_margin16') })
231bea4f105Sopenharmony_ci        Text(this.fileItem.fileName)
232bea4f105Sopenharmony_ci          .fontSize($r('app.float.common_font_size16'))
233bea4f105Sopenharmony_ci          .layoutWeight(1)
234bea4f105Sopenharmony_ci          .maxLines(1)
235bea4f105Sopenharmony_ci          .textOverflow({ overflow: TextOverflow.Ellipsis })
236bea4f105Sopenharmony_ci        if (this.isLoading) {
237bea4f105Sopenharmony_ci          LoadingProgress()
238bea4f105Sopenharmony_ci            .width($r('app.float.common_size24'))
239bea4f105Sopenharmony_ci            .height($r('app.float.common_size24'))
240bea4f105Sopenharmony_ci            .color($r('sys.color.ohos_id_color_text_secondary'))
241bea4f105Sopenharmony_ci        } else {
242bea4f105Sopenharmony_ci          Image($r('app.media.ic_arrow_right'))
243bea4f105Sopenharmony_ci            .objectFit(ImageFit.Contain)
244bea4f105Sopenharmony_ci            .autoResize(true)
245bea4f105Sopenharmony_ci            .height($r('app.float.common_size12'))
246bea4f105Sopenharmony_ci            .width($r('app.float.common_size12'))
247bea4f105Sopenharmony_ci            .interpolation(ImageInterpolation.Medium)
248bea4f105Sopenharmony_ci            .rotate({ z: 90, angle: this.iconRotate ? 90 : 0 })
249bea4f105Sopenharmony_ci            .visibility(this.isShowArrow ? Visibility.Visible : Visibility.None)
250bea4f105Sopenharmony_ci        }
251bea4f105Sopenharmony_ci      }
252bea4f105Sopenharmony_ci      .width('100%')
253bea4f105Sopenharmony_ci      .padding({
254bea4f105Sopenharmony_ci        top: $r('app.float.common_padding16'),
255bea4f105Sopenharmony_ci        bottom: $r('app.float.common_padding16'),
256bea4f105Sopenharmony_ci        right: $r('app.float.common_padding24'),
257bea4f105Sopenharmony_ci        left: this.layer * TREE_LAYER + 'vp'
258bea4f105Sopenharmony_ci      })
259bea4f105Sopenharmony_ci      .backgroundColor(this.selectUri === this.fileItem.uri ? $r('app.color.move_dialog_background') : '')
260bea4f105Sopenharmony_ci      .stateStyles({
261bea4f105Sopenharmony_ci        pressed: pressedStyles
262bea4f105Sopenharmony_ci      })
263bea4f105Sopenharmony_ci      .onClick(() => {
264bea4f105Sopenharmony_ci        this.isClickExpand = true;
265bea4f105Sopenharmony_ci        this.clickExpand(true);
266bea4f105Sopenharmony_ci      })
267bea4f105Sopenharmony_ci
268bea4f105Sopenharmony_ci      if (this.subFolderList.length && this.iconRotate) {
269bea4f105Sopenharmony_ci        ForEach(this.subFolderList, (item) => {
270bea4f105Sopenharmony_ci          TreeItem({
271bea4f105Sopenharmony_ci            fileItem: item,
272bea4f105Sopenharmony_ci            loadPath: this.loadPath,
273bea4f105Sopenharmony_ci            chooseItem: $chooseItem,
274bea4f105Sopenharmony_ci            selectUri: $selectUri,
275bea4f105Sopenharmony_ci            selectName: $selectName,
276bea4f105Sopenharmony_ci            layer: this.layer + 1,
277bea4f105Sopenharmony_ci            folderList: $folderList,
278bea4f105Sopenharmony_ci            fileList: $fileList,
279bea4f105Sopenharmony_ci            isClickExpand: $isClickExpand
280bea4f105Sopenharmony_ci          })
281bea4f105Sopenharmony_ci        })
282bea4f105Sopenharmony_ci      }
283bea4f105Sopenharmony_ci    }
284bea4f105Sopenharmony_ci  }
285bea4f105Sopenharmony_ci}