mirror of
https://github.com/openharmony/applications_filepicker.git
synced 2026-07-01 00:17:55 -04:00
+8
-6
@@ -1,6 +1,8 @@
|
||||
/.hvigor
|
||||
/node_modules
|
||||
/local.properties
|
||||
/.idea
|
||||
**/build
|
||||
/tsconfig.json
|
||||
/.hvigor
|
||||
/node_modules
|
||||
/local.properties
|
||||
/.idea
|
||||
**/build
|
||||
/tsconfig.json
|
||||
/oh_modules/
|
||||
oh-package-lock.json5
|
||||
+1
-2
@@ -5,7 +5,6 @@
|
||||
"versionCode": 10100300,
|
||||
"versionName": "1.1.0.300",
|
||||
"icon": "$media:app_icon",
|
||||
"label": "$string:app_name",
|
||||
"distributedNotificationEnabled": true
|
||||
"label": "$string:app_name"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
|
||||
|
||||
<filefilter name="copyrightPolicyFilter" desc="Filters for copyright header policies">
|
||||
<filteritem type="filename" name="README|README_zh|.*.log|.*.json5|.*.json" desc=""/>
|
||||
<filteritem type="filename" name="README|README_zh|hvigorw|.*.bat|.*.log|.*.json5|.*.json" desc=""/>
|
||||
</filefilter>
|
||||
<filefilter name="defaultPolicyFilter" desc="Filters for LICENSE file policies">
|
||||
<filteritem type="filename" name="README|README_zh|*.log|*.json5|*.json" desc="json file"/>
|
||||
<filteritem type="filename" name="README|README_zh|hvigorw|*.bat|*.log|*.json5|*.json" desc="json file"/>
|
||||
</filefilter>
|
||||
</filefilterlist>
|
||||
</oatconfig>
|
||||
|
||||
+26
-25
@@ -1,26 +1,27 @@
|
||||
{
|
||||
"app": {
|
||||
"compileSdkVersion": 10,
|
||||
"compatibleSdkVersion": 9,
|
||||
"products": [
|
||||
{
|
||||
"name": "default",
|
||||
"signingConfig": "default",
|
||||
}
|
||||
]
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"name": "entry",
|
||||
"srcPath": "./entry",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
{
|
||||
"app": {
|
||||
"products": [
|
||||
{
|
||||
"name": "default",
|
||||
"signingConfig": "default",
|
||||
"compileSdkVersion": 10,
|
||||
"compatibleSdkVersion": 10,
|
||||
"runtimeOS": "OpenHarmony"
|
||||
}
|
||||
]
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"name": "entry",
|
||||
"srcPath": "./entry",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
/node_modules
|
||||
/.preview
|
||||
/build
|
||||
/.cxx
|
||||
/.cxx
|
||||
/oh_modules
|
||||
@@ -2,13 +2,8 @@
|
||||
"license": "ISC",
|
||||
"devDependencies": {},
|
||||
"name": "entry",
|
||||
"ohos": {
|
||||
"org": "huawei",
|
||||
"directoryLevel": "module",
|
||||
"buildTool": "hvigor"
|
||||
},
|
||||
"description": "example description",
|
||||
"repository": {},
|
||||
"version": "1.0.0",
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
Generated
-5
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "entry",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const MILLISECOND = {
|
||||
ONE_MILLISECOND: 1,
|
||||
ONE_SECOND: 1000,
|
||||
ONE_MINUTE: 60 * 1000,
|
||||
ONE_HOUR: 60 * 60 * 1000,
|
||||
ONE_DAY: 24 * 60 * 60 * 1000,
|
||||
ONE_MONTH: 30 * 24 * 60 * 60 * 1000
|
||||
}
|
||||
|
||||
export const BYTE = {
|
||||
ONE_KB: 1024,
|
||||
ONE_MB: 1024 * 1024,
|
||||
ONE_GB: 1024 * 1024 * 1024,
|
||||
ONE_TB: 1024 * 1024 * 1024 * 1024
|
||||
}
|
||||
|
||||
export const FILENAME_REGEXP = /^[^\\/:*?<>\"|]+$/
|
||||
|
||||
export const FILENAME_MAX_LENGTH = 225
|
||||
|
||||
/**
|
||||
* 重命名连接符
|
||||
*/
|
||||
export const RENAME_CONNECT_CHARACTER = ' ';
|
||||
|
||||
export const DOCS_FOLDER = 'Docs'
|
||||
|
||||
export const DESKTOP_FOLDER = 'Desktop'
|
||||
|
||||
export const DOCUMENTS_FOLDER = 'Documents'
|
||||
|
||||
/**
|
||||
* 内部存储根目录Uri
|
||||
*/
|
||||
export const INTERNAL_STORAGE_ROOT_URI: string = 'file://media/root';
|
||||
|
||||
/**
|
||||
* picker支持的文件选择模式
|
||||
*/
|
||||
export const SELECT_MODE = {
|
||||
FILE: 0,
|
||||
FOLDER: 1,
|
||||
MIX: 2
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件后缀相关常量定义
|
||||
*/
|
||||
export const FILE_SUFFIX = {
|
||||
SUFFIX_SPLIT: ',',
|
||||
SUFFIX_START: '.'
|
||||
}
|
||||
|
||||
/**
|
||||
* 目录层级定义
|
||||
*/
|
||||
export const FOLDER_LEVEL = {
|
||||
MIN_LEVEL: 1,
|
||||
MAX_LEVEL: 21
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面类型
|
||||
*/
|
||||
export const PAGE_TYPE = {
|
||||
MY_PHONE : 'myPhone'
|
||||
}
|
||||
|
||||
export const FILE_MANAGER_PREFERENCES = {
|
||||
name: 'FileManagerPreferences',
|
||||
lastSelectPath: {
|
||||
key: 'lastSelectPath',
|
||||
defaultValue: ''
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,11 @@ namespace ErrorCodeConst {
|
||||
/**
|
||||
* 其他未知错误
|
||||
*/
|
||||
OTHER_ERROR = 9001
|
||||
OTHER_ERROR = 9001,
|
||||
/**
|
||||
* 创建正常
|
||||
*/
|
||||
NORMAL = 1000
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,14 @@ import fileAccess from '@ohos.file.fileAccess'
|
||||
import Logger from '../log/Logger'
|
||||
import abilityAccessCtrl from '@ohos.abilityAccessCtrl'
|
||||
import { Permissions } from '@ohos.abilityAccessCtrl'
|
||||
import BundleManager from '@ohos.bundle.bundleManager'
|
||||
import FileShare from '@ohos.fileshare'
|
||||
import wantConstant from '@ohos.app.ability.wantConstant'
|
||||
import ErrorCodeConst from '../constants/ErrorCodeConst'
|
||||
import MediaLibrary from '@ohos.multimedia.mediaLibrary'
|
||||
import { FILE_MANAGER_PREFERENCES, FILE_SUFFIX, SELECT_MODE } from '../constants/Constant'
|
||||
import StringUtil from './StringUtil'
|
||||
import { ArrayUtil } from './ArrayUtil'
|
||||
import { getPreferences } from './PreferencesUtil'
|
||||
|
||||
const TAG = 'AbilityCommonUtil'
|
||||
|
||||
@@ -46,11 +49,23 @@ namespace AbilityCommonUtil {
|
||||
*/
|
||||
export const CALLER_UID = 'ohos.aafwk.param.callerUid'
|
||||
|
||||
export const CALLER_BUNDLE_NAME = 'ohos.aafwk.param.callerBundleName'
|
||||
|
||||
/**
|
||||
* 最大选择文件的个数
|
||||
*/
|
||||
export const MAX_FILE_PICK_NUM = 500
|
||||
|
||||
/**
|
||||
* 后缀最大长度,包括'.'
|
||||
*/
|
||||
export const SUFFIX_MAX_LENGTH: number = 255;
|
||||
|
||||
/**
|
||||
* 三方传入的后缀数组长度最大100
|
||||
*/
|
||||
export const SUFFIX_LIST_MAX_LENGTH: number = 100;
|
||||
|
||||
/**
|
||||
* picker对外返回的响应码
|
||||
*/
|
||||
@@ -68,10 +83,11 @@ namespace AbilityCommonUtil {
|
||||
* 拉起Ability时必要的初始化操作
|
||||
*/
|
||||
export function init(): Promise<void[]> {
|
||||
const fileAccessHelperPromise = createFileAccessHelper()
|
||||
getMediaLibrary()
|
||||
const getRequestPermission = requestPermission()
|
||||
return Promise.all([fileAccessHelperPromise, getRequestPermission])
|
||||
const fileAccessHelperPromise = createFileAccessHelper();
|
||||
getMediaLibrary();
|
||||
const getRequestPermission = requestPermission();
|
||||
const initData = initLastSelectPath();
|
||||
return Promise.all([fileAccessHelperPromise, getRequestPermission, initData]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +108,7 @@ namespace AbilityCommonUtil {
|
||||
let isDone = result.done
|
||||
while (!isDone) {
|
||||
const rootInfo: fileAccess.RootInfo = result.value
|
||||
Logger.i(TAG, 'RootInfo: ' + rootInfo.uri + ', ' + rootInfo.deviceType + ', ' + rootInfo.deviceFlags + ', ' + rootInfo.displayName)
|
||||
Logger.i(TAG, 'RootInfo: ' + rootInfo.uri + ', ' + rootInfo.deviceType + ', ' + rootInfo.deviceFlags + ', ' + rootInfo.displayName+','+rootInfo.relativePath)
|
||||
rootInfoArr.push(rootInfo)
|
||||
result = rootIterator.next()
|
||||
isDone = result.done
|
||||
@@ -106,6 +122,31 @@ namespace AbilityCommonUtil {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Ability初始化时,加载最新保存的路径Uri
|
||||
*/
|
||||
export function initLastSelectPath(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const defaultValue = FILE_MANAGER_PREFERENCES.lastSelectPath.defaultValue;
|
||||
const lastSelectPathKey = FILE_MANAGER_PREFERENCES.lastSelectPath.key;
|
||||
getPreferences(FILE_MANAGER_PREFERENCES.name).then(preferences => {
|
||||
preferences.get(lastSelectPathKey, defaultValue).then((result: string) => {
|
||||
AppStorage.SetOrCreate<string>(lastSelectPathKey, result);
|
||||
resolve();
|
||||
Logger.i(TAG, 'initLastSelectPath result: ' + result);
|
||||
}).catch((error) => {
|
||||
AppStorage.SetOrCreate<string>(lastSelectPathKey, defaultValue);
|
||||
Logger.e(TAG, 'initLastSelectPath preferences.get fail, error:' + JSON.stringify(error));
|
||||
resolve();
|
||||
})
|
||||
}).catch(err => {
|
||||
AppStorage.SetOrCreate<string>(lastSelectPathKey, defaultValue);
|
||||
Logger.e(TAG, 'initLastSelectPath getPreferences fail, error: ' + JSON.stringify(err));
|
||||
resolve();
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请文件管理器需用户授权的权限
|
||||
*/
|
||||
@@ -126,27 +167,6 @@ namespace AbilityCommonUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给定的uid获取对应的bundleName
|
||||
*/
|
||||
export function getBundleNameByUid(uid: number): Promise<string> {
|
||||
if (!uid && uid !== 0) {
|
||||
Logger.e(TAG, `getBundleNameByUid fail, uid is null`)
|
||||
return Promise.resolve('')
|
||||
}
|
||||
try {
|
||||
return BundleManager.getBundleNameByUid(uid).then((bundleName) => {
|
||||
Logger.i(TAG, `getBundleNameByUid success, uid: ${uid}, bundleName: ${bundleName}`)
|
||||
return bundleName
|
||||
}).catch(error => {
|
||||
Logger.e(TAG, `getBundleNameByUid fail, uid: ${uid}, error: ${JSON.stringify(error)}`)
|
||||
return Promise.reject(error)
|
||||
})
|
||||
} catch (error) {
|
||||
Logger.e(TAG, `getBundleNameByUid error, uid: ${uid}, error: ${JSON.stringify(error)}`)
|
||||
return Promise.resolve('')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* uri授权
|
||||
* @param uriList 待授权的uri列表
|
||||
@@ -155,19 +175,23 @@ namespace AbilityCommonUtil {
|
||||
*/
|
||||
export function grantUriPermission(uriList: Array<string>, bundleName: string, flag: wantConstant.Flags): Promise<boolean> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
Logger.i(TAG, "grantUriPermission start,grantSize = " + uriList?.length);
|
||||
let grantSuccessCount: number = 0;
|
||||
for (let uri of uriList) {
|
||||
try {
|
||||
await FileShare.grantUriPermission(uri, bundleName, flag)
|
||||
if (flag === wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION) {
|
||||
await FileShare.grantUriPermission(uri, bundleName, wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION)
|
||||
await FileShare.grantUriPermission(uri, bundleName, flag | wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION)
|
||||
} else {
|
||||
await FileShare.grantUriPermission(uri, bundleName, flag)
|
||||
}
|
||||
Logger.d(TAG, `grantUriPermission success, uri: ${uri}`)
|
||||
grantSuccessCount++;
|
||||
} catch (error) {
|
||||
resolve(false)
|
||||
Logger.e(TAG, `grantUriPermission fail, uri: ${uri}, error: ${JSON.stringify(error)}`)
|
||||
Logger.e(TAG, `grantUriPermission fail,grantSuccessCount:${grantSuccessCount}}, uri: ${uri}, error: ${JSON.stringify(error)}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger.i(TAG, "grantUriPermission end,grantSuccessCount = " + grantSuccessCount);
|
||||
resolve(true)
|
||||
})
|
||||
|
||||
@@ -180,7 +204,7 @@ namespace AbilityCommonUtil {
|
||||
* @param message
|
||||
*/
|
||||
export async function terminateFilePicker(result: Array<string> = [], displayNames: Array<string> = [], resultCode: number = RESULT_CODE.SUCCESS, message: string = ''): Promise<void> {
|
||||
const bundleName = await AbilityCommonUtil.getBundleNameByUid(globalThis.pickerCallerUid)
|
||||
const bundleName = globalThis.pickerCallerBundleName
|
||||
if (result.length && bundleName) {
|
||||
// uri授权
|
||||
const isSuccess = await grantUriPermission(result, bundleName, wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION)
|
||||
@@ -201,16 +225,16 @@ namespace AbilityCommonUtil {
|
||||
'select_item_list': result,
|
||||
'file_name_list': displayNames,
|
||||
message: message,
|
||||
'result': result[0],
|
||||
'result': result[0],
|
||||
}
|
||||
}
|
||||
}
|
||||
globalThis.abilityContext.terminateSelfWithResult(abilityResult, (error) => {
|
||||
if (error.code) {
|
||||
Logger.e(TAG, 'Operation failed. Cause: ' + JSON.stringify(error))
|
||||
Logger.e(TAG, 'terminateFilePicker failed. Cause: ' + JSON.stringify(error))
|
||||
return
|
||||
}
|
||||
Logger.d(TAG, 'Operation failed. Cause: ' + JSON.stringify(abilityResult))
|
||||
Logger.d(TAG, 'terminateFilePicker success. result: ' + JSON.stringify(abilityResult))
|
||||
})
|
||||
}
|
||||
/**
|
||||
@@ -220,10 +244,11 @@ namespace AbilityCommonUtil {
|
||||
* @param message
|
||||
*/
|
||||
export async function terminatePathPicker(result: Array<string>, resultCode: number = RESULT_CODE.SUCCESS, message: string = ''): Promise<void> {
|
||||
const bundleName = await AbilityCommonUtil.getBundleNameByUid(globalThis.pathCallerUid)
|
||||
const bundleName = globalThis.pathCallerBundleName
|
||||
if (result.length && bundleName) {
|
||||
// uri授权
|
||||
const isSuccess = await grantUriPermission(result, bundleName, wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION)
|
||||
const flag = wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION | wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION
|
||||
const isSuccess = await grantUriPermission(result, bundleName, flag)
|
||||
if (!isSuccess) {
|
||||
resultCode = ErrorCodeConst.PICKER.GRANT_URI_PERMISSION_FAIL,
|
||||
result = []
|
||||
@@ -246,10 +271,10 @@ namespace AbilityCommonUtil {
|
||||
}
|
||||
globalThis.pathAbilityContext.terminateSelfWithResult(abilityResult, (error) => {
|
||||
if (error.code) {
|
||||
Logger.e(TAG, 'Operation failed. Cause: ' + JSON.stringify(error))
|
||||
Logger.e(TAG, 'terminatePathPicker failed. Cause: ' + JSON.stringify(error))
|
||||
return
|
||||
}
|
||||
Logger.d(TAG, 'Operation failed. Cause: ' + JSON.stringify(abilityResult))
|
||||
Logger.d(TAG, 'terminatePathPicker success. result: ' + JSON.stringify(abilityResult))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -257,11 +282,13 @@ namespace AbilityCommonUtil {
|
||||
* 获取选择文件的最大个数
|
||||
* @param num 调用方传入的个数
|
||||
*/
|
||||
export function getPickFileNum(num: number): number {
|
||||
if(!num || num > MAX_FILE_PICK_NUM){
|
||||
return MAX_FILE_PICK_NUM
|
||||
export function getPickFileNum(num: any): number {
|
||||
if (typeof num === 'number') {
|
||||
if (num > 0 && num <= MAX_FILE_PICK_NUM) {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
return num
|
||||
return MAX_FILE_PICK_NUM;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,6 +307,76 @@ namespace AbilityCommonUtil {
|
||||
return typeList.filter(item => item)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选择文件Mode,默认选择文件
|
||||
* @param keySelectMode 调用方传入文件mode
|
||||
*/
|
||||
export function getKeySelectMode(keySelectMode: any): number {
|
||||
if (typeof keySelectMode === 'number') {
|
||||
if (keySelectMode === SELECT_MODE.FILE
|
||||
|| keySelectMode === SELECT_MODE.FOLDER
|
||||
|| keySelectMode === SELECT_MODE.MIX) {
|
||||
return keySelectMode;
|
||||
}
|
||||
}
|
||||
return SELECT_MODE.FILE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支持的文件后缀列表
|
||||
* @param keyFileSuffixFilter 调用方传入文件后缀列表
|
||||
*/
|
||||
export function getKeyFileSuffixFilter(keyFileSuffixFilter: string[]): Array<string> {
|
||||
let suffixList = [];
|
||||
if (!ArrayUtil.isEmpty(keyFileSuffixFilter)) {
|
||||
let len = keyFileSuffixFilter.length;
|
||||
let size = len > SUFFIX_LIST_MAX_LENGTH ? SUFFIX_LIST_MAX_LENGTH : len;
|
||||
for (let index = 0; index < size; index++) {
|
||||
const suffixStr = keyFileSuffixFilter[index];
|
||||
if (typeof suffixStr === 'string') {
|
||||
const suffixArray = suffixStr.split(FILE_SUFFIX.SUFFIX_SPLIT);
|
||||
for (let index = 0; index < suffixArray.length; index++) {
|
||||
const suffix = suffixArray[index];
|
||||
if (checkFileSuffix(suffix)) {
|
||||
suffixList.push(suffix.toUpperCase())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return suffixList.filter((item, index, array) => {
|
||||
return array.indexOf(item) === index;
|
||||
});
|
||||
}
|
||||
|
||||
export function checkFileSuffix(fileSuffix: String): boolean {
|
||||
return fileSuffix && fileSuffix.length <= SUFFIX_MAX_LENGTH && fileSuffix.startsWith(FILE_SUFFIX.SUFFIX_START);
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径选择器获取支持的文件后缀,只支持获取第一个文件后缀
|
||||
* @param keyFileSuffixChoices 调用方传入文件后缀列表
|
||||
*/
|
||||
export function getKeyFileSuffixChoices(keyFileSuffixChoices: string[]): string {
|
||||
if (!ArrayUtil.isEmpty(keyFileSuffixChoices)) {
|
||||
let len = keyFileSuffixChoices.length;
|
||||
let size = len > SUFFIX_LIST_MAX_LENGTH ? SUFFIX_LIST_MAX_LENGTH : len;
|
||||
for (let index = 0; index < size; index++) {
|
||||
const suffixStr = keyFileSuffixChoices[index];
|
||||
if (typeof suffixStr === 'string') {
|
||||
const suffixArray = suffixStr.split(FILE_SUFFIX.SUFFIX_SPLIT);
|
||||
for (let index = 0; index < suffixArray.length; index++) {
|
||||
const suffix = suffixArray[index];
|
||||
if (checkFileSuffix(suffix)) {
|
||||
return suffix;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取媒体库对象实例的统一接口
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
|
||||
*/
|
||||
|
||||
import ObjectUtil from "./ObjectUtil"
|
||||
|
||||
/**
|
||||
* 字符串工具类
|
||||
*/
|
||||
export class ArrayUtil {
|
||||
public static readonly INDEX_INVALID: number = -1;
|
||||
|
||||
/**
|
||||
* 判断array是否为空
|
||||
*
|
||||
* @param collection collection
|
||||
* @return boolean
|
||||
*/
|
||||
public static isEmpty<T>(array: T[]): boolean {
|
||||
if (ObjectUtil.isNullOrUndefined(array)) {
|
||||
return true;
|
||||
}
|
||||
return array.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断array是否包含item
|
||||
*
|
||||
* @param array
|
||||
* @param item
|
||||
*/
|
||||
public static contains<T>(array: T[], item: T): boolean {
|
||||
if (this.isEmpty(array) || ObjectUtil.isNullOrUndefined(item)) {
|
||||
return false;
|
||||
}
|
||||
return array.indexOf(item) !== this.INDEX_INVALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找 array 中最大值
|
||||
* @param array
|
||||
*/
|
||||
public static max(array: number[]): number {
|
||||
return Math.max.apply(null, array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找 array 中最小值
|
||||
* @param array
|
||||
*/
|
||||
public static min(array: number[]): number {
|
||||
return Math.min.apply(null, array);
|
||||
}
|
||||
}
|
||||
@@ -18,16 +18,20 @@
|
||||
*/
|
||||
import Logger from '../log/Logger'
|
||||
import { FilesData } from '../../databases/model/FileData'
|
||||
import { DOCUMENTS_FOLDER } from '../constants/Constant'
|
||||
import { sortDataByTime, randomId } from './Tools'
|
||||
import { FOLDER_LEVEL, DOCS_FOLDER, DESKTOP_FOLDER } from '../constants/Constant'
|
||||
import { sortDataByTime, randomId, sortBaseDataByOrderTime } from './Tools'
|
||||
import fileAccess from '@ohos.file.fileAccess'
|
||||
import fileExtensionInfo from '@ohos.file.fileExtensionInfo'
|
||||
import { FileBase } from '../../databases/model/base/FileBase'
|
||||
import ObjectUtil from './ObjectUtil'
|
||||
import { FileUtil } from './FileUtil'
|
||||
import fs from '@ohos.file.fs'
|
||||
|
||||
const TAG = 'FileAccessExec'
|
||||
|
||||
namespace FileAccessExec {
|
||||
|
||||
// 创建文件夹
|
||||
// 创建文件夹
|
||||
export function createFolder(sourceUri: string, folderName: string): any {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
@@ -65,26 +69,6 @@ namespace FileAccessExec {
|
||||
})
|
||||
}
|
||||
|
||||
// 打开文件
|
||||
export function openFile(sourceUri: string): any {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
// - 0o0:只读打开 0o1:只写打开 0o2:读写打开
|
||||
globalThis.fileAcsHelper.openFile(sourceUri, 0o2, (ret, data) => {
|
||||
if (ret && ret.code !== '0') {
|
||||
reject(ret)
|
||||
Logger.e(TAG, 'openFile fail:' + JSON.stringify(ret))
|
||||
} else {
|
||||
resolve(data)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
Logger.e(TAG, 'openFile error occurred:' + error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getFileData(): any {
|
||||
let folderList = new Array<FilesData>()
|
||||
let fileList = new Array<FilesData>()
|
||||
@@ -100,24 +84,26 @@ namespace FileAccessExec {
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
return { folderList, fileList }
|
||||
}
|
||||
|
||||
export function getFileByCurIterator(fileInfo: fileAccess.FileInfo, isRoot: boolean = false): Array<FilesData> {
|
||||
let fileArr = []
|
||||
let fileIterator = fileInfo.listFile()
|
||||
let documentsFolder: fileAccess.FileInfo = null
|
||||
if (!fileIterator) {
|
||||
return
|
||||
}
|
||||
let result = fileIterator.next()
|
||||
let isDone = result.done
|
||||
while (!isDone) {
|
||||
try {
|
||||
const {fileName, uri, mode, size, mtime, mimeType} = result.value
|
||||
export function getFileByCurIterator(fileInfo: fileAccess.FileInfo | fileAccess.RootInfo): Array<FilesData> {
|
||||
let fileList: Array<FilesData> = []
|
||||
try {
|
||||
let fileIterator = fileInfo.listFile()
|
||||
if (!fileIterator) {
|
||||
Logger.w(TAG, 'getFileByCurIterator fail, fileIterator is null')
|
||||
return fileList
|
||||
}
|
||||
let result = fileIterator.next()
|
||||
let isDone = result.done
|
||||
while (!isDone) {
|
||||
const {fileName, relativePath,uri, mode, size, mtime, mimeType} = result.value
|
||||
let tempFile = new FilesData({
|
||||
id: randomId(),
|
||||
fileName,
|
||||
relativePath,
|
||||
uri,
|
||||
mode,
|
||||
size,
|
||||
@@ -125,72 +111,71 @@ namespace FileAccessExec {
|
||||
mimeType,
|
||||
fileIterator: result.value
|
||||
})
|
||||
// 根目录下不显示Documents文件夹
|
||||
if (isRoot && result.value.fileName === DOCUMENTS_FOLDER) {
|
||||
globalThis.documentInfo = tempFile
|
||||
documentsFolder = result.value
|
||||
} else {
|
||||
fileArr.push(tempFile)
|
||||
}
|
||||
fileList.push(tempFile)
|
||||
result = fileIterator.next()
|
||||
isDone = result.done
|
||||
}
|
||||
fileList = sortDataByTime(fileList)
|
||||
} catch (error) {
|
||||
fileList = []
|
||||
Logger.e(TAG, 'getFileByCurIterator fail, error:' + JSON.stringify(error) + error)
|
||||
}
|
||||
return fileList
|
||||
}
|
||||
|
||||
export function getPathPickSubFiles(fileInfo: fileAccess.FileInfo, defaultPathPick: string, level: number): Array<FileBase> {
|
||||
let fileArr: Array<FileBase> = [];
|
||||
let fileIterator = fileInfo.listFile();
|
||||
if (!fileIterator) {
|
||||
return fileArr;
|
||||
}
|
||||
let result = fileIterator.next();
|
||||
let isDone = result.done;
|
||||
while (!isDone) {
|
||||
try {
|
||||
let fileInfo: fileAccess.FileInfo = result.value;
|
||||
if (!ObjectUtil.isNullOrUndefined(fileInfo)) {
|
||||
let tempFile = new FileBase(result.value, false);
|
||||
if (tempFile.isFolder) {
|
||||
if (FileUtil.hasSubFolder(defaultPathPick, tempFile.currentDir) && level <= FOLDER_LEVEL.MAX_LEVEL) {
|
||||
tempFile.subList = getPathPickSubFiles(fileInfo, defaultPathPick, level + 1);
|
||||
}
|
||||
}
|
||||
// 根目录下不显示Documents文件夹
|
||||
fileArr.push(tempFile);
|
||||
}
|
||||
result = fileIterator.next();
|
||||
isDone = result.done;
|
||||
} catch (e) {
|
||||
Logger.e(TAG, 'getFileByCurIterator error: ' + e.toString())
|
||||
isDone = true
|
||||
Logger.e(TAG, 'getSubFileByIterator error: ' + e.toString());
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
// 处理Documents目录
|
||||
if (documentsFolder) {
|
||||
// 获取Documents目录下的文件列表
|
||||
const documentFileList = getFileByCurIterator(documentsFolder)
|
||||
// 将Documents目录下的文件合并入根目录
|
||||
fileArr = fileArr.concat(documentFileList)
|
||||
} else if (isRoot) {
|
||||
Logger.e(TAG, 'not found Documents folder in root path')
|
||||
}
|
||||
|
||||
fileArr = sortDataByTime(fileArr)
|
||||
return fileArr
|
||||
fileArr = sortBaseDataByOrderTime(fileArr, true);
|
||||
return fileArr;
|
||||
}
|
||||
|
||||
|
||||
export function getRootFolder(): Array<FilesData> {
|
||||
let fileList: Array<FilesData> = []
|
||||
if (!globalThis.rootInfoArr) {
|
||||
Logger.e(TAG, 'globalThis.rootInfoArr is null ')
|
||||
return []
|
||||
Logger.e(TAG, 'getRootFolder fail, rootInfoArr is null')
|
||||
return fileList
|
||||
}
|
||||
// 过滤本地磁盘
|
||||
const rootInfo: fileAccess.RootInfo = globalThis.rootInfoArr.find(item => item.deviceType === fileExtensionInfo.DeviceType.DEVICE_LOCAL_DISK)
|
||||
|
||||
if (!rootInfo) {
|
||||
Logger.e(TAG, 'getRootFolder rootInfo is null ')
|
||||
return []
|
||||
}
|
||||
const fileIterator: fileAccess.FileIterator = rootInfo.listFile()
|
||||
if (!fileIterator) {
|
||||
Logger.e(TAG, 'getRootFolder fileIterator is null ')
|
||||
return []
|
||||
}
|
||||
let isDone = false
|
||||
let tempFileIterator = null
|
||||
while (!isDone) {
|
||||
const nextFileRes: {
|
||||
value: fileAccess.FileInfo,
|
||||
done: boolean
|
||||
} = fileIterator.next()
|
||||
const nextFileName = nextFileRes.value.fileName
|
||||
if (nextFileName.indexOf('FILE') !== -1) {
|
||||
tempFileIterator = nextFileRes.value
|
||||
isDone = true
|
||||
try {
|
||||
const rootFolder: fileAccess.RootInfo = globalThis.rootInfoArr.find((item: fileAccess.RootInfo) => item.deviceType === fileExtensionInfo.DeviceType.DEVICE_LOCAL_DISK)
|
||||
if (rootFolder) {
|
||||
globalThis.documentInfo = rootFolder
|
||||
fileList = getFileByCurIterator(rootFolder)
|
||||
fileList = fileList.filter(item => item.fileName !== DESKTOP_FOLDER)
|
||||
} else {
|
||||
isDone = nextFileRes.done
|
||||
Logger.e(TAG, 'rootFolder is null')
|
||||
}
|
||||
} catch (error) {
|
||||
fileList = []
|
||||
Logger.e(TAG, 'getRootFolder fail, error:' + JSON.stringify(error) + error)
|
||||
}
|
||||
if (!tempFileIterator) {
|
||||
Logger.e(TAG, 'getRootFolder tempFileIterator is null ')
|
||||
return []
|
||||
}
|
||||
return getFileByCurIterator(tempFileIterator, true)
|
||||
return fileList
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -551,6 +551,28 @@ export class FileMimeTypeUtil {
|
||||
return mimeType
|
||||
}
|
||||
|
||||
public static getFileSuffix(fileName: string): String {
|
||||
const unKnown: string = '';
|
||||
if (StringUtil.isEmpty(fileName)) {
|
||||
return unKnown;
|
||||
}
|
||||
|
||||
const splitList = fileName.split('.')
|
||||
if (splitList.length < 2) {
|
||||
return unKnown;
|
||||
}
|
||||
|
||||
let suffix = splitList[splitList.length-1].toUpperCase()
|
||||
// 判断DLP加密文件
|
||||
if (suffix === FileMimeTypeUtil.SUFFIX_DLP) {
|
||||
if (splitList.length === 2) {
|
||||
return unKnown;
|
||||
}
|
||||
suffix = splitList[splitList.length-2].toUpperCase()
|
||||
}
|
||||
return suffix
|
||||
}
|
||||
|
||||
public static getFileTypeOrder(fileName: string): number {
|
||||
const mimeType = this.getFileMimeType(fileName)
|
||||
return mimeType.getFileTypeSort()
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
|
||||
import { toast } from '../../base/utils/Common'
|
||||
import { FileMimeTypeUtil } from '../../base/utils/FileMimeTypeUtil'
|
||||
import { FILE_SUFFIX, SELECT_MODE } from '../constants/Constant';
|
||||
import Logger from '../log/Logger';
|
||||
import ObjectUtil from './ObjectUtil';
|
||||
|
||||
/**
|
||||
* 文件选择器文件状态
|
||||
@@ -28,21 +31,78 @@ export function pickerStatus(item, checkedNum) {
|
||||
// 选择是否超限
|
||||
exceedLimit: globalThis.filePickerViewFlag && (checkedNum >= globalThis.filePickNum && !item.isChecked),
|
||||
// 选择类型是否不匹配
|
||||
differentTypes: !checkFileSelectable(item.fileName)
|
||||
differentTypes: !checkFileSelectable(item)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件后缀判断文件是否可选
|
||||
* @param fileName
|
||||
* @param item
|
||||
*/
|
||||
function checkFileSelectable(fileName){
|
||||
if (!fileName) {
|
||||
return false
|
||||
}
|
||||
function checkFileSelectable(item): boolean {
|
||||
// 非文件选择器场景
|
||||
if (!globalThis.filePickerViewFlag) {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
// selectMode检查
|
||||
let selectMode: number = globalThis.keySelectMode;
|
||||
let isFolder = false;
|
||||
if (ObjectUtil.hasKey(item, 'isFolder')) {
|
||||
isFolder = item.isFolder;
|
||||
}
|
||||
// 文件夹模式,直接返回
|
||||
if(selectMode === SELECT_MODE.FOLDER){
|
||||
return isFolder;
|
||||
}
|
||||
|
||||
if (isFolder) {
|
||||
// 混选模式下,文件夹直接返回
|
||||
if (selectMode === SELECT_MODE.MIX) {
|
||||
return true;
|
||||
}
|
||||
// 文件模式下,文件夹直接返回false
|
||||
return false;
|
||||
}
|
||||
// 后缀检查
|
||||
let keyFileSuffixFilter: Array<string> = globalThis.keyFileSuffixFilter;
|
||||
if (Array.isArray(keyFileSuffixFilter) && keyFileSuffixFilter.length > 0) {
|
||||
return checkFileSuffix(item.fileName, keyFileSuffixFilter);
|
||||
}
|
||||
|
||||
// mimeType检查
|
||||
return checkFileMimetype(item.fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验选中的文件后缀
|
||||
*
|
||||
* @param fileName 文件名称
|
||||
* @param keyFileSuffixFilter 指定后缀
|
||||
* @return 如果文件后缀满足三方指定,则返回true
|
||||
*/
|
||||
function checkFileSuffix(fileName: string, keyFileSuffixFilter: Array<string>): boolean {
|
||||
if (keyFileSuffixFilter) {
|
||||
if (fileName) {
|
||||
const suffix = FILE_SUFFIX.SUFFIX_START + FileMimeTypeUtil.getFileSuffix(fileName);
|
||||
if (keyFileSuffixFilter.includes(suffix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验选中的文件mimetype
|
||||
*
|
||||
* @param fileName 文件名称
|
||||
* @return 条件满足返回true
|
||||
*/
|
||||
function checkFileMimetype(fileName: string): boolean {
|
||||
if (!fileName) {
|
||||
return false
|
||||
}
|
||||
let keyPickTypeList: Array<string> = globalThis.keyPickTypeList
|
||||
// 输入的类型全转换成小写,避免大小敏感问题
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
|
||||
*/
|
||||
import fileExtensionInfo from '@ohos.file.fileExtensionInfo';
|
||||
import fileAccess from '@ohos.file.fileAccess';
|
||||
import ObjectUtil from './ObjectUtil';
|
||||
import Logger from '../log/Logger';
|
||||
import StringUtil from './StringUtil';
|
||||
import { FILENAME_MAX_LENGTH,
|
||||
RENAME_CONNECT_CHARACTER } from '../constants/Constant';
|
||||
import MediaLibrary from '@ohos.multimedia.mediaLibrary';
|
||||
|
||||
const TAG = 'FileUtil';
|
||||
|
||||
export class FileUtil {
|
||||
|
||||
/**
|
||||
* uri 格式开头
|
||||
*/
|
||||
static readonly URI_START = 'file://';
|
||||
|
||||
/**
|
||||
* 根据fileAccess.FileInfo中的mode匹配是否是文件夹
|
||||
* @param mode number
|
||||
* @returns boolean
|
||||
*/
|
||||
public static isFolder(mode: number): boolean {
|
||||
return (mode & fileExtensionInfo.DocumentFlag.REPRESENTS_DIR) === fileExtensionInfo.DocumentFlag.REPRESENTS_DIR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算文件夹子文件个数
|
||||
* @param fileIterator fileAccess.FileIterator
|
||||
* @returns number
|
||||
*/
|
||||
public static getChildCountOfFolder(fileIterator: fileAccess.FileIterator): number {
|
||||
let count = 0;
|
||||
if (ObjectUtil.isNullOrUndefined(fileIterator)) {
|
||||
return count;
|
||||
}
|
||||
let isDone: boolean = false;
|
||||
while (!isDone) {
|
||||
let currItem = fileIterator.next();
|
||||
isDone = currItem.done;
|
||||
if (isDone) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
* @param uri 文件uri
|
||||
* @param fileAccessHelper fileAccess.FileAccessHelper
|
||||
* @returns fileAccess.FileInfo
|
||||
*/
|
||||
public static async getFileInfoByUri(uri: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
|
||||
try {
|
||||
return await fileAccessHelper.getFileInfoFromUri(uri);
|
||||
} catch (err) {
|
||||
Logger.e(TAG, 'getFileInfoByUri err: ' + JSON.stringify(err));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
* @param relativePath 文件relativePath
|
||||
* @param fileAccessHelper fileAccess.FileAccessHelper
|
||||
* @returns fileAccess.FileInfo
|
||||
*/
|
||||
public static async getFileInfoByRelativePath(relativePath: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
|
||||
try {
|
||||
return await fileAccessHelper.getFileInfoFromRelativePath(relativePath);
|
||||
} catch (err) {
|
||||
Logger.e(TAG, 'getFileInfoByRelativePath err: ' + JSON.stringify(err));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据uri获取文件夹子文件列表Iterator
|
||||
* @param uri
|
||||
* @param fileAccessHelper
|
||||
* @returns FileIterator
|
||||
*/
|
||||
public static async getFileIteratorByUri(uri: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileIterator> {
|
||||
try {
|
||||
let fileInfo = await fileAccessHelper.getFileInfoFromUri(uri);
|
||||
return fileInfo.listFile();
|
||||
} catch (err) {
|
||||
Logger.e(TAG, 'getFileIteratorByUri err: ' + JSON.stringify(err));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static getFileAccessHelper(context, wants): fileAccess.FileAccessHelper {
|
||||
try {
|
||||
return fileAccess.createFileAccessHelper(context, wants);
|
||||
} catch (err) {
|
||||
Logger.i(TAG, 'getFileAccessHelper err: ' + JSON.stringify(err));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async getFileAccessHelperAsync(context): Promise<fileAccess.FileAccessHelper> {
|
||||
try {
|
||||
let wants = await fileAccess.getFileAccessAbilityInfo();
|
||||
return fileAccess.createFileAccessHelper(context, wants);
|
||||
} catch (err) {
|
||||
Logger.i(TAG, 'getFileAccessHelperAsync err: ' + JSON.stringify(err));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static getParentRelativePath(relativePath: string): string {
|
||||
let curPath = relativePath;
|
||||
if (StringUtil.isEmpty(relativePath)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let index: number = curPath.lastIndexOf('/');
|
||||
// 去掉最后一个'/'
|
||||
if (index === curPath.length - 1) {
|
||||
curPath = curPath.substr(0, index);
|
||||
}
|
||||
index = curPath.lastIndexOf('/');
|
||||
if (index <= 0) {
|
||||
return '';
|
||||
}
|
||||
return curPath.substr(0, index + 1);
|
||||
}
|
||||
|
||||
public static getUsageHabitsKey(prefix: string, suffix: string): string {
|
||||
return prefix + suffix.charAt(0).toLocaleUpperCase() + suffix.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是uri路径
|
||||
* @param path 路径
|
||||
* @returns 结果
|
||||
*/
|
||||
public static isUriPath(path: string): boolean {
|
||||
if (ObjectUtil.isNullOrUndefined(path)) {
|
||||
return false;
|
||||
}
|
||||
return path.startsWith(this.URI_START);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从目录下获取某个文件名的文件
|
||||
* @param foldrUri 目录uri
|
||||
* @param fileName 文件名
|
||||
* return 结果
|
||||
*/
|
||||
public static async getFileFromFolder(foldrUri: string, fileName, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
|
||||
// 先将目录的信息查询出来
|
||||
let fileInfo: fileAccess.FileInfo = await this.getFileInfoByUri(foldrUri, fileAccessHelper);
|
||||
if (ObjectUtil.isNullOrUndefined(fileInfo)) {
|
||||
return null;
|
||||
}
|
||||
// 构建目标目录下的同名文件的相对路径
|
||||
const destFileRelativePath = fileInfo.relativePath + fileInfo.fileName + '/' + fileName;
|
||||
// 根据相对路径查询相应的文件
|
||||
return await this.getFileInfoByRelativePath(destFileRelativePath, fileAccessHelper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据FileInfo获取当前文件的文件夹
|
||||
*
|
||||
* @param fileInfo 文件对象
|
||||
* @returns 返回当前文件的文件夹
|
||||
*/
|
||||
public static getCurrentFolderByFileInfo(fileInfo: fileAccess.FileInfo): string {
|
||||
if (fileInfo !== null) {
|
||||
let path = fileInfo.relativePath;
|
||||
return FileUtil.getCurrentDir(path, FileUtil.isFolder(fileInfo.mode));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static async createFolder(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string, name: string): Promise<{code, uri}> {
|
||||
let uri: string = '';
|
||||
let code: any;
|
||||
try {
|
||||
uri = await fileAccessHelper.mkDir(parentUri, name);
|
||||
} catch (error) {
|
||||
code = error.code;
|
||||
Logger.e(TAG, 'createFolder error occurred:' + error.code + ', ' + error.message);
|
||||
}
|
||||
return {code: code, uri: uri};
|
||||
}
|
||||
|
||||
public static async hardDelete(uri: string, mediaLibrary: MediaLibrary.MediaLibrary): Promise<boolean> {
|
||||
if (ObjectUtil.isNullOrUndefined(mediaLibrary)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await mediaLibrary.deleteAsset(uri);
|
||||
return true;
|
||||
} catch (e) {
|
||||
Logger.e(TAG, 'hardDelete error: ' + JSON.stringify(e));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重命名
|
||||
* @param fileAccessHelper FileAccessHelper
|
||||
* @param oldUri oldUri
|
||||
* @param newName newName
|
||||
* @returns {err, uri}
|
||||
*/
|
||||
public static async rename(fileAccessHelper: fileAccess.FileAccessHelper, oldUri: string, newName: string): Promise<{err, uri}> {
|
||||
let uri: string = '';
|
||||
let err: any;
|
||||
try {
|
||||
uri = await fileAccessHelper.rename(oldUri, newName);
|
||||
} catch (error) {
|
||||
err = {code: error.code, message: error.message};
|
||||
Logger.e(TAG, 'rename error occurred:' + error.code + ', ' + error.message);
|
||||
}
|
||||
return {err: err, uri: uri};
|
||||
}
|
||||
|
||||
public static async createFile(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string, fileName: string): Promise<{err, uri}> {
|
||||
let retUri: string = '';
|
||||
let err: any;
|
||||
try {
|
||||
Logger.i(TAG, 'createFile ' + fileAccessHelper + '; ' + parentUri + " ; " + fileName);
|
||||
retUri = await fileAccessHelper.createFile(parentUri, fileName);
|
||||
} catch (e) {
|
||||
Logger.e(TAG, 'createFile error: ' + e.code + ', ' + e.message);
|
||||
err = {code: e.code, message: e.message};
|
||||
}
|
||||
return {err: err, uri: retUri};
|
||||
}
|
||||
|
||||
public static hasSubFolder(loadPath: string, curFolderPath: string): boolean {
|
||||
if (!StringUtil.isEmpty(loadPath)) {
|
||||
if (!StringUtil.isEmpty(curFolderPath)) {
|
||||
loadPath = FileUtil.getPathWithFileSplit(loadPath);
|
||||
curFolderPath = FileUtil.getPathWithFileSplit(curFolderPath);
|
||||
if (loadPath.startsWith(curFolderPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static getPathWithFileSplit(path: string): string {
|
||||
let fileSplit: string = '/';
|
||||
if (path && !path.endsWith(fileSplit)) {
|
||||
path = path + fileSplit;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static loadSubFinish(loadPath: string, curFolderPath: string, maxLevel: number): boolean {
|
||||
let fileSplit: string = '/';
|
||||
if (!StringUtil.isEmpty(loadPath)) {
|
||||
if (!loadPath.endsWith(fileSplit)) {
|
||||
loadPath = loadPath + fileSplit;
|
||||
}
|
||||
|
||||
let folders = curFolderPath.split(fileSplit);
|
||||
|
||||
if ((curFolderPath + fileSplit) === loadPath || folders.length >= maxLevel) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static renameFile(fileName: string, renameCount: number, suffix: string): string {
|
||||
if (ObjectUtil.isNullOrUndefined(fileName)) {
|
||||
return fileName;
|
||||
}
|
||||
let newName = fileName;
|
||||
if (renameCount > 0) {
|
||||
newName = fileName + RENAME_CONNECT_CHARACTER + renameCount;
|
||||
let strLen = newName.length + suffix.length;
|
||||
// 字符长度大于最大长度
|
||||
if (strLen > FILENAME_MAX_LENGTH) {
|
||||
// 计算需要裁剪的长度
|
||||
let subLen = strLen - FILENAME_MAX_LENGTH + 1;
|
||||
newName = fileName.substring(0, fileName.length - subLen) + RENAME_CONNECT_CHARACTER + renameCount;
|
||||
}
|
||||
}
|
||||
return newName + suffix;
|
||||
}
|
||||
|
||||
public static getFileNameReName(fileName: string): string[] {
|
||||
if (StringUtil.isEmpty(fileName)) {
|
||||
return null;
|
||||
}
|
||||
let index = fileName.lastIndexOf(RENAME_CONNECT_CHARACTER);
|
||||
if (index === -1) {
|
||||
return null;
|
||||
}
|
||||
let str = fileName.substring(index + 1, fileName.length);
|
||||
let name = fileName.substring(0, index);
|
||||
return [name, str];
|
||||
}
|
||||
|
||||
public static getCurrentDir(path: string, isFolder: boolean): string {
|
||||
if (isFolder) {
|
||||
return path;
|
||||
}
|
||||
if (path) {
|
||||
let index: number = path.lastIndexOf('/');
|
||||
let len: number = path.length;
|
||||
if (len > 1 && index > 1) {
|
||||
return path.substring(0, index);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static getUriPath(path: string): string {
|
||||
if (path && FileUtil.isUriPath(path)) {
|
||||
return path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Object工具类
|
||||
*/
|
||||
namespace ObjectUtil {
|
||||
|
||||
/**
|
||||
* 判断是否为null
|
||||
*/
|
||||
export function isNull(obj: any): boolean {
|
||||
return obj === null;
|
||||
}
|
||||
/**
|
||||
* 判断是否为undefined
|
||||
* @param obj
|
||||
*/
|
||||
export function isUndefined(obj: any): boolean {
|
||||
return obj === undefined;
|
||||
}
|
||||
/**
|
||||
* 判断是否为null 或者 undefined
|
||||
* @param obj
|
||||
*/
|
||||
export function isNullOrUndefined(obj: any): boolean {
|
||||
return isNull(obj) || isUndefined(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回string,如果是null or undefined返回defaultValue
|
||||
*/
|
||||
export function toString(obj: any, defaultValue: string = ''): string {
|
||||
if (this.isNullOrUndefined(obj)) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return obj.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断对象中是否有某个属性
|
||||
* @param obj 校验对象
|
||||
* @param key 校验属性
|
||||
*/
|
||||
export function hasKey(obj: object, key: string): boolean {
|
||||
return Object.prototype.hasOwnProperty.call(obj, key);
|
||||
}
|
||||
}
|
||||
|
||||
export default ObjectUtil;
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) Huawei Technologies Co., Ltd. 2015-2022. All rights reserved.
|
||||
*/
|
||||
|
||||
import dataPreferences from '@ohos.data.preferences'
|
||||
import Logger from '../log/Logger'
|
||||
|
||||
const TAG = 'PreferencesUtil'
|
||||
|
||||
export const getPreferences = (preferenceName: string) => {
|
||||
return dataPreferences.getPreferences(globalThis.abilityContext, preferenceName)
|
||||
}
|
||||
|
||||
export const deletePreferences = (preferenceName: string) => {
|
||||
return dataPreferences.deletePreferences(globalThis.abilityContext, preferenceName)
|
||||
}
|
||||
|
||||
export const removePreferencesFromCache = (preferenceName: string) => {
|
||||
return dataPreferences.removePreferencesFromCache(globalThis.abilityContext, preferenceName)
|
||||
}
|
||||
|
||||
export const setPreferencesValue = (name: string, key: string, newVal) => {
|
||||
return getPreferences(name).then(async preferences => {
|
||||
await preferences.put(key, newVal)
|
||||
await preferences.flush()
|
||||
}).catch(err => {
|
||||
Logger.e(TAG, 'setPreferencesValue error: ' + JSON.stringify(err))
|
||||
})
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import LanguageUtil from './LanguageUtil'
|
||||
import { FileMimeTypeUtil } from './FileMimeTypeUtil'
|
||||
import { MimeType } from '../../databases/model/MimeType'
|
||||
import Logger from '../log/Logger'
|
||||
import { FileBase } from '../../databases/model/base/FileBase'
|
||||
|
||||
const TAG = 'Tools'
|
||||
|
||||
@@ -148,40 +149,6 @@ function compareStr(str1: string, str2: string) {
|
||||
return str2.localeCompare(str1, language)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 文件夹名/文件名自动+1
|
||||
* @param fileItems: 当前列表/目标列表
|
||||
* @param filename: 需要+1的字符串
|
||||
* @param name: filename如果有后缀
|
||||
*/
|
||||
export const createName = (fileItems: any[], filename: string, name?: string): string => {
|
||||
try {
|
||||
const fileNameList = fileItems.map(({ fileName }) => fileName)
|
||||
name = name ?? ''
|
||||
let copyReg = /[()]*/g // 复制文件重名时格式化文件名
|
||||
let lastNum = /([0-9]*)$/ // 获取末尾数字
|
||||
while (fileNameList.includes(name ? filename + ' ' + name : filename)) {
|
||||
if (name) {
|
||||
filename = filename.replace(copyReg, '').replace(lastNum, res => {
|
||||
res = res < '1' ? '1' : res
|
||||
const len = res.length
|
||||
const num = '(' + (+res + 1) + ')'
|
||||
return num.padStart(len, '0')
|
||||
})
|
||||
} else {
|
||||
filename = filename.replace(lastNum, res => {
|
||||
const len = res.length
|
||||
const num = +res + 1 + ''
|
||||
return num.padStart(len, '0')
|
||||
})
|
||||
}
|
||||
}
|
||||
return filename
|
||||
} catch (err) {
|
||||
return filename
|
||||
}
|
||||
}
|
||||
|
||||
export const gridName = (fileName) => {
|
||||
// 文件名超长是中间部分'...'显示
|
||||
const MAX_LENGTH = 11
|
||||
@@ -203,4 +170,18 @@ export const isDlpFile = (value): boolean => {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
export const sortBaseDataByOrderTime = (dataList: Array<FileBase>, isDesc: boolean = false) => {
|
||||
// 规避@State修饰的数组变量执行sort方法不生效问题
|
||||
const fileList = dataList.filter(item => item);
|
||||
return fileList.sort((a, b) => {
|
||||
if (b.modifyTime !== a.modifyTime) {
|
||||
return isDesc ? b.modifyTime - a.modifyTime : a.modifyTime - b.modifyTime;
|
||||
} else {
|
||||
const language = LanguageUtil.getSystemLanguage();
|
||||
return isDesc ? b.fileName.localeCompare(a.fileName, language) : a.fileName.localeCompare(b.fileName, language);
|
||||
}
|
||||
})
|
||||
}
|
||||
+16
-18
@@ -13,24 +13,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const MILLISECOND = {
|
||||
ONE_MILLISECOND: 1,
|
||||
ONE_SECOND: 1000,
|
||||
ONE_MINUTE: 60 * 1000,
|
||||
ONE_HOUR: 60 * 60 * 1000,
|
||||
ONE_DAY: 24 * 60 * 60 * 1000,
|
||||
ONE_MONTH: 30 * 24 * 60 * 60 * 1000
|
||||
}
|
||||
import window from '@ohos.window';
|
||||
import Logger from '../log/Logger';
|
||||
import ObjectUtil from './ObjectUtil';
|
||||
|
||||
export const BYTE = {
|
||||
ONE_KB: 1024,
|
||||
ONE_MB: 1024 * 1024,
|
||||
ONE_GB: 1024 * 1024 * 1024,
|
||||
ONE_TB: 1024 * 1024 * 1024 * 1024
|
||||
}
|
||||
const TAG = 'UiUtil';
|
||||
|
||||
export const FILENAME_REGEXP = /^[^\\/:*?<>\"|]+$/
|
||||
export class UiUtil {
|
||||
|
||||
export const FILENAME_MAX_LENGTH = 250
|
||||
|
||||
export const DOCUMENTS_FOLDER = 'Documents'
|
||||
public static setWindowBackground(color: string): void {
|
||||
let windowClass: window.Window = globalThis.windowClass;
|
||||
if (!ObjectUtil.isNullOrUndefined(windowClass)) {
|
||||
try {
|
||||
windowClass.setWindowBackgroundColor(color);
|
||||
} catch (err) {
|
||||
Logger.e(TAG, 'setWindowBackgroundColor error: ' + JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@ import { MimeType } from './MimeType'
|
||||
import { BasicDataSource } from './BasicDataSource'
|
||||
import fileExtensionInfo from '@ohos.file.fileExtensionInfo'
|
||||
import AbilityCommonUtil from '../../base/utils/AbilityCommonUtil'
|
||||
import { FileUtil } from '../../base/utils/FileUtil'
|
||||
import { ArrayUtil } from '../../base/utils/ArrayUtil'
|
||||
|
||||
export class BreadData {
|
||||
title: string
|
||||
@@ -133,9 +135,14 @@ export class FilesData {
|
||||
isFolder: boolean = false
|
||||
duration: number
|
||||
mimeTypeObj: MimeType
|
||||
subFolderList: Array<FilesData>;
|
||||
subFileList: Array<FilesData>;
|
||||
layer:number;
|
||||
autoShow: boolean = false;
|
||||
currentDir?: string;
|
||||
|
||||
constructor(obj) {
|
||||
this.isFolder = !!(obj.mode & fileExtensionInfo.DocumentFlag.REPRESENTS_DIR)
|
||||
this.isFolder = obj.isFolder || FileUtil.isFolder(obj.mode);
|
||||
this.id = obj.id || randomId()
|
||||
this.uri = obj.uri || ''
|
||||
this.deviceId = obj.deviceId || ''
|
||||
@@ -148,7 +155,7 @@ export class FilesData {
|
||||
this.mtime = obj.mtime * MILLISECOND.ONE_SECOND || 0
|
||||
this.mimeType = obj.mimeType || ''
|
||||
this.isChecked = false
|
||||
this.path = obj.path || ''
|
||||
this.path = obj.path || obj.relativePath || ''
|
||||
this.sub = obj.sub || 0
|
||||
this.scale = obj.scale || 1
|
||||
this.angle = obj.angle || 0
|
||||
@@ -163,11 +170,12 @@ export class FilesData {
|
||||
this.gridIcon = this.mimeTypeObj.getGridResID()
|
||||
this.localGridIcon = this.mimeTypeObj.getLocalGridResID()
|
||||
if (this.mimeTypeObj.isMedia()) {
|
||||
this.thumbUri = `${this.uri}/thumbnail/${THUMBNAIL_SIZE.WIDTH}/${THUMBNAIL_SIZE.HEIGHT}`
|
||||
this.thumbUri = this.uri
|
||||
}
|
||||
if (this.isFolder) {
|
||||
this.sub = getSubFileNum(this.fileIterator)
|
||||
}
|
||||
this.currentDir = FileUtil.getCurrentDir(this.path, this.isFolder);
|
||||
}
|
||||
|
||||
setFileName(fileName: string): void {
|
||||
@@ -184,6 +192,49 @@ export class FilesData {
|
||||
pickFile(): void {
|
||||
AbilityCommonUtil.terminateFilePicker([this.uri], [this.fileName])
|
||||
}
|
||||
|
||||
setSubFolderList(subFolderList: Array<FilesData>) {
|
||||
this.subFolderList = subFolderList;
|
||||
}
|
||||
|
||||
setSubList(subList: Array<FilesData>) {
|
||||
if (!ArrayUtil.isEmpty(subList)) {
|
||||
let folderList = new Array<FilesData>();
|
||||
let fileList = new Array<FilesData>();
|
||||
for (let i = 0; i < subList.length; i++) {
|
||||
let fileData: FilesData = subList[i];
|
||||
if (fileData.isFolder) {
|
||||
folderList.push(fileData);
|
||||
} else {
|
||||
fileList.push(fileData);
|
||||
}
|
||||
}
|
||||
this.subFolderList = folderList;
|
||||
this.subFileList = fileList;
|
||||
}
|
||||
}
|
||||
|
||||
hasSubFolderList(): boolean {
|
||||
if (ArrayUtil.isEmpty(this.subFolderList)) {
|
||||
return false;
|
||||
}
|
||||
return this.subFolderList.length > 0;
|
||||
}
|
||||
|
||||
getSubFolderList(): Array<FilesData> {
|
||||
return this.subFolderList;
|
||||
}
|
||||
|
||||
setLayer(layer: number) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
getLayer(): number {
|
||||
if (this.layer) {
|
||||
return this.layer;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fileAccess from '@ohos.file.fileAccess';
|
||||
import { MILLISECOND } from '../../../base/constants/Constant';
|
||||
import { FileUtil } from '../../../base/utils/FileUtil';
|
||||
import ObjectUtil from '../../../base/utils/ObjectUtil';
|
||||
import Logger from '../../../base/log/Logger';
|
||||
|
||||
const TAG: string = 'FileBase';
|
||||
|
||||
export class FileBase {
|
||||
uri: string;
|
||||
relativePath: string;
|
||||
fileName: string;
|
||||
mode: number;
|
||||
isFolder: boolean;
|
||||
fileSize: number;
|
||||
modifyTime: number;
|
||||
mimeType: string;
|
||||
childCount: number;
|
||||
firstUri: string;
|
||||
subList: Array<FileBase>;
|
||||
currentDir?: string;
|
||||
|
||||
constructor(fileInfo: fileAccess.FileInfo, needChildCount: boolean = true) {
|
||||
if (ObjectUtil.isNullOrUndefined(fileInfo)) {
|
||||
return;
|
||||
}
|
||||
this.uri = fileInfo.uri;
|
||||
this.relativePath = fileInfo.relativePath;
|
||||
this.fileName = fileInfo.fileName;
|
||||
this.fileSize = fileInfo.size;
|
||||
this.mode = fileInfo.mode;
|
||||
this.isFolder = FileUtil.isFolder(this.mode);
|
||||
this.modifyTime = fileInfo.mtime * MILLISECOND.ONE_SECOND;
|
||||
if (this.modifyTime <= 0) {
|
||||
Logger.w(TAG, "The modification time of " + this.fileName + " is " + this.modifyTime);
|
||||
}
|
||||
this.mimeType = fileInfo.mimeType;
|
||||
if (this.isFolder && needChildCount) {
|
||||
this.childCount = FileUtil.getChildCountOfFolder(fileInfo.listFile());
|
||||
}
|
||||
this.currentDir = FileUtil.getCurrentDir(this.relativePath, this.isFolder);
|
||||
}
|
||||
}
|
||||
@@ -17,30 +17,38 @@ import UIAbility from '@ohos.app.ability.UIAbility'
|
||||
import window from '@ohos.window'
|
||||
import AbilityCommonUtil from '../base/utils/AbilityCommonUtil'
|
||||
import Logger from '../base/log/Logger'
|
||||
import { FileUtil } from '../base/utils/FileUtil'
|
||||
|
||||
const TAG = 'MainAbility'
|
||||
|
||||
export default class MainAbility extends UIAbility {
|
||||
onCreate(want, launchParam) {
|
||||
Logger.i(TAG, 'onCreate')
|
||||
globalThis.action = want.action
|
||||
globalThis.abilityContext = this.context
|
||||
globalThis.startMode = want.parameters.startMode
|
||||
globalThis.saveFile = want.parameters.saveFile ? [want.parameters.saveFile] : []
|
||||
Logger.i(TAG, 'globalThis.startMode: ' + globalThis.startMode + ', ' + (globalThis.startMode == 'choose'))
|
||||
globalThis.action = want.action;
|
||||
globalThis.abilityContext = this.context;
|
||||
globalThis.startMode = want.parameters.startMode;
|
||||
globalThis.saveFile = want.parameters.saveFile ? [want.parameters.saveFile] : [];
|
||||
Logger.i(TAG, 'globalThis.startMode: ' + globalThis.startMode + ', ' + (globalThis.startMode == 'choose'));
|
||||
const parameters = want.parameters
|
||||
if (globalThis.action == 'ohos.want.action.OPEN_FILE' || globalThis.startMode == 'choose') {
|
||||
// 文件选择器
|
||||
// 选择文件的类型列表
|
||||
globalThis.keyPickTypeList = AbilityCommonUtil.getKeyPickTypeList(parameters.key_pick_type, parameters.key_pick_type_list)
|
||||
globalThis.keyPickTypeList = AbilityCommonUtil.getKeyPickTypeList(parameters.key_pick_type, parameters.key_pick_type_list);
|
||||
// 选择文件个数
|
||||
globalThis.filePickNum = AbilityCommonUtil.getPickFileNum(parameters.key_pick_num)
|
||||
globalThis.filePickNum = AbilityCommonUtil.getPickFileNum(parameters.key_pick_num);
|
||||
// 文件选择范围:0-本地 1-云盘 不传则默认展示全部路径(未实现)
|
||||
globalThis.filePickLocation = parameters.key_pick_location
|
||||
// 选择指定目录下的文件(未实现)
|
||||
globalThis.keyPickDirPath = parameters.key_pick_dir_path
|
||||
globalThis.pickerCallerUid = parameters[AbilityCommonUtil.CALLER_UID]
|
||||
globalThis.filePickerViewFlag = true
|
||||
globalThis.filePickLocation = parameters.key_pick_location;
|
||||
// 选择指定目录下的文件
|
||||
globalThis.keyFileDefaultPickPath = FileUtil.getUriPath(parameters.key_pick_dir_path);
|
||||
// 选择文件模式,默认只支持文件选择
|
||||
globalThis.keySelectMode = AbilityCommonUtil.getKeySelectMode(parameters.key_select_mode);
|
||||
// 指定文件后缀,string[]
|
||||
if (parameters.key_file_suffix_filter instanceof Array) {
|
||||
globalThis.keyFileSuffixFilter = AbilityCommonUtil.getKeyFileSuffixFilter(parameters.key_file_suffix_filter);
|
||||
}
|
||||
globalThis.pickerCallerUid = parameters[AbilityCommonUtil.CALLER_UID];
|
||||
globalThis.pickerCallerBundleName = parameters[AbilityCommonUtil.CALLER_BUNDLE_NAME]
|
||||
globalThis.filePickerViewFlag = true;
|
||||
} else {
|
||||
// 路径选择器
|
||||
globalThis.pathAbilityContext = this.context
|
||||
@@ -50,7 +58,13 @@ export default class MainAbility extends UIAbility {
|
||||
globalThis.keyPickFileLocation = parameters.key_pick_file_location
|
||||
// 保存云盘文件到本地时云盘文件的uri列表(未实现)
|
||||
globalThis.keyPickFilePaths = parameters.key_pick_file_paths
|
||||
globalThis.keyPathDefaultPickDir = FileUtil.getUriPath(parameters.key_pick_dir_path);
|
||||
// 指定文件后缀,只获取第一个有效的后缀
|
||||
if (parameters.key_file_suffix_choices instanceof Array) {
|
||||
globalThis.keyFileSuffixChoices = AbilityCommonUtil.getKeyFileSuffixChoices(parameters.key_file_suffix_choices);
|
||||
}
|
||||
globalThis.pathCallerUid = parameters[AbilityCommonUtil.CALLER_UID]
|
||||
globalThis.pathCallerBundleName = parameters[AbilityCommonUtil.CALLER_BUNDLE_NAME]
|
||||
}
|
||||
Logger.i(TAG, ' onCreate, parameters: ' + JSON.stringify(want.parameters))
|
||||
}
|
||||
|
||||
@@ -14,12 +14,18 @@
|
||||
*/
|
||||
|
||||
import { fileTree } from './component/dialog/FileMoveDialog'
|
||||
import FileAccessExec from '../base/utils/FileAccessExec'
|
||||
import Logger from '../base/log/Logger'
|
||||
import ErrorCodeConst from '../base//constants/ErrorCodeConst'
|
||||
import { toast, setSystemBar, setImmersion } from '../base/utils/Common'
|
||||
import AbilityCommonUtil from '../base/utils/AbilityCommonUtil'
|
||||
import { SYSTEM_BAR_COLOR } from '../base/constants/UiConstant'
|
||||
import StringUtil from '../base/utils/StringUtil'
|
||||
import { FileUtil } from '../base/utils/FileUtil'
|
||||
import ObjectUtil from '../base/utils/ObjectUtil'
|
||||
import MediaLibrary from '@ohos.multimedia.mediaLibrary';
|
||||
import fileAccess from '@ohos.file.fileAccess'
|
||||
import { ArrayUtil } from '../base/utils/ArrayUtil'
|
||||
import { UiUtil } from '../base/utils/UiUtil'
|
||||
|
||||
const TAG = 'PathSelector'
|
||||
|
||||
@@ -27,9 +33,10 @@ const TAG = 'PathSelector'
|
||||
@Component
|
||||
struct PathSelector {
|
||||
|
||||
@State createResultType:number = ErrorCodeConst.PICKER.NORMAL;
|
||||
|
||||
aboutToAppear(){
|
||||
setImmersion(false)
|
||||
setSystemBar(SYSTEM_BAR_COLOR.WHITE, SYSTEM_BAR_COLOR.WHITE, SYSTEM_BAR_COLOR.BLACK, SYSTEM_BAR_COLOR.BLACK)
|
||||
UiUtil.setWindowBackground(SYSTEM_BAR_COLOR.LIGHT_GRAY);
|
||||
}
|
||||
|
||||
async saveFileCallback(res): Promise<void> {
|
||||
@@ -42,15 +49,22 @@ struct PathSelector {
|
||||
if (fileNameList.length <= 1) {
|
||||
fileNameList = [res.fileName]
|
||||
}
|
||||
this.createFile(res.selectUri, fileNameList).then((createdFileList) => {
|
||||
this.saveFiles(res.selectUri, fileNameList).then((createdFileList) => {
|
||||
AbilityCommonUtil.terminatePathPicker(createdFileList)
|
||||
}).catch((err) => {
|
||||
let errorMessage = ''
|
||||
let errorCode = 0
|
||||
Logger.e(TAG, JSON.stringify(err));
|
||||
if (err.code) {
|
||||
if (err.code === ErrorCodeConst.FILE_ACCESS.FILE_NAME_EXIST) {
|
||||
errorMessage = 'Same name file already exists'
|
||||
errorCode = ErrorCodeConst.PICKER.FILE_NAME_EXIST
|
||||
this.createResultType = errorCode;
|
||||
const pathName = globalThis.keyPickFileName;
|
||||
let listLength:number = pathName.length;
|
||||
if(listLength == 1){
|
||||
return;
|
||||
}
|
||||
} else if (err.code === ErrorCodeConst.FILE_ACCESS.FILE_NAME_INVALID) {
|
||||
errorMessage = 'Invalid display name'
|
||||
errorCode = ErrorCodeConst.PICKER.FILE_NAME_INVALID
|
||||
@@ -69,27 +83,152 @@ struct PathSelector {
|
||||
}
|
||||
}
|
||||
|
||||
async createFile(folderUri: string, fileNameList: Array<string>): Promise<Array<string>> {
|
||||
let createdFileUriList = []
|
||||
/**
|
||||
* PathPicker保存文件
|
||||
* @param data SaveFilesParam
|
||||
*/
|
||||
async saveFiles(path: string, nameList: Array<string>): Promise<Array<string>> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let resolveFileName = ''
|
||||
try {
|
||||
for (let i = 0; i < fileNameList.length; i++) {
|
||||
resolveFileName = fileNameList[i]
|
||||
const newFileUri = await FileAccessExec.createFile(folderUri, resolveFileName)
|
||||
createdFileUriList.push(newFileUri)
|
||||
let fileAccessHelper = await FileUtil.getFileAccessHelperAsync(globalThis.abilityContext);
|
||||
let dirPath = path;
|
||||
if (StringUtil.isEmpty(dirPath)) {
|
||||
dirPath = (await FileUtil.getFileInfoByRelativePath('Documents/', fileAccessHelper)).uri;
|
||||
}
|
||||
let fileNameArr = nameList;
|
||||
let successArr: Array<string> = [];
|
||||
let resultErr: any;
|
||||
let len: number = fileNameArr.length;
|
||||
let fileNameList: string[] = [];
|
||||
if (len > 1) {
|
||||
fileNameList = await this.getPickPathListFiles(dirPath, fileAccessHelper);
|
||||
}
|
||||
Logger.i(TAG, 'saveFiles createName: ' + JSON.stringify(fileNameArr)+" ; ");
|
||||
Logger.i(TAG, 'saveFiles subList: ' + JSON.stringify(fileNameList)+" ; ");
|
||||
for (let i = 0; i < len; i++) {
|
||||
const currName = fileNameArr[i];
|
||||
let result
|
||||
if (len === 1) {
|
||||
result = await FileUtil.createFile(fileAccessHelper, dirPath, currName);
|
||||
} else {
|
||||
result = await this.tryRenameFileOperate(fileAccessHelper, currName, dirPath, 0, fileNameList);
|
||||
}
|
||||
resolve(createdFileUriList)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
Logger.e(TAG, `createFile error, fileName: ${resolveFileName}, massage: ${err.message ? err.message : err}`)
|
||||
if (ObjectUtil.isUndefined(result.err)) {
|
||||
Logger.i(TAG, "saveFiles createOK: " + result.uri);
|
||||
successArr.push(result.uri);
|
||||
continue;
|
||||
}
|
||||
Logger.i(TAG, 'saveFiles err: ' + result.err.code);
|
||||
// 失败
|
||||
resultErr = { code: result.err.code, message: result.err.message };
|
||||
let mediaLibrary;
|
||||
try {
|
||||
mediaLibrary = MediaLibrary.getMediaLibrary(globalThis.abilityContext);
|
||||
} catch (error) {
|
||||
Logger.e(TAG, 'getMediaLibrary fail, error:' + JSON.stringify(error))
|
||||
}
|
||||
if (ObjectUtil.isNullOrUndefined(mediaLibrary)) {
|
||||
break;
|
||||
}
|
||||
for (let i = 0; i < successArr.length; i++) {
|
||||
await FileUtil.hardDelete(successArr[i], mediaLibrary);
|
||||
}
|
||||
try {
|
||||
mediaLibrary.release();
|
||||
} catch (e) {
|
||||
Logger.e(TAG, 'mediaLibrary close error')
|
||||
}
|
||||
successArr = [];
|
||||
break;
|
||||
}
|
||||
|
||||
Logger.i(TAG, 'saveFiles end: ' + JSON.stringify(successArr));
|
||||
if (!ArrayUtil.isEmpty(successArr)) {
|
||||
resolve(successArr);
|
||||
} else {
|
||||
reject(resultErr);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private async getPickPathListFiles(dirUri: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<string[]> {
|
||||
let fileInfo: fileAccess.FileInfo = await FileUtil.getFileInfoByUri(dirUri, fileAccessHelper);
|
||||
if (ObjectUtil.isNullOrUndefined(fileInfo) || !FileUtil.isFolder(fileInfo.mode)) {
|
||||
return [];
|
||||
}
|
||||
return this.getFilesByIterator(fileInfo.listFile());
|
||||
}
|
||||
|
||||
private getFilesByIterator(fileIterator: fileAccess.FileIterator): string[] {
|
||||
if (ObjectUtil.isNull(fileIterator)) {
|
||||
return null;
|
||||
}
|
||||
let result: Array<string> = new Array();
|
||||
let isDone = false;
|
||||
while (!isDone) {
|
||||
try {
|
||||
let nextFileInfo = fileIterator.next();
|
||||
isDone = nextFileInfo.done;
|
||||
if (isDone) {
|
||||
break;
|
||||
}
|
||||
let currFile = nextFileInfo.value;
|
||||
if (!FileUtil.isFolder(currFile.mode)) {
|
||||
result.push(currFile.fileName);
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.e(TAG, 'current File err: ' + JSON.stringify(err) + ', ' + err.toString());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private async tryRenameFileOperate(fileAccessHelper: fileAccess.FileAccessHelper, fileName: string, dirUri: string, renameCount: number, fileNameList: string[] = []): Promise<{ err,uri }> {
|
||||
let index = fileName.lastIndexOf('.');
|
||||
let name = fileName;
|
||||
let suffix = '';
|
||||
if (index !== -1) {
|
||||
suffix = fileName.substring(index, fileName.length);
|
||||
name = fileName.substring(0, index);
|
||||
}
|
||||
let hasReNameCount = FileUtil.getFileNameReName(name);
|
||||
if (!ObjectUtil.isNullOrUndefined(hasReNameCount)) {
|
||||
let num = Number(hasReNameCount[1]);
|
||||
if (!isNaN(num)) {
|
||||
name = hasReNameCount[0];
|
||||
renameCount = num;
|
||||
}
|
||||
}
|
||||
|
||||
let newName = fileName;
|
||||
while (true) {
|
||||
newName = FileUtil.renameFile(name, renameCount++, suffix);
|
||||
let index = this.getIndex(newName, fileNameList);
|
||||
Logger.i(TAG, "tryRenameFileOperate : " + newName + " ; index = " + index);
|
||||
if (index === -1) {
|
||||
const result = await FileUtil.createFile(fileAccessHelper, dirUri, newName);
|
||||
if (ObjectUtil.isUndefined(result.err)) {
|
||||
Logger.i(TAG, "tryRenameFileOperate createOK: " + result.uri);
|
||||
return result;
|
||||
} else {
|
||||
Logger.i(TAG, "tryRenameFileOperate createFail: " + JSON.stringify(result) + " ; " + newName);
|
||||
if (result.err.code === ErrorCodeConst.FILE_ACCESS.FILE_NAME_EXIST) {
|
||||
fileNameList.push(newName);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getIndex(fileName: string, fileNameList: string[] = []) {
|
||||
return fileNameList.findIndex(value => value === fileName);
|
||||
}
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
fileTree({
|
||||
createFileFailType: $createResultType,
|
||||
moveCallback: (e) => {
|
||||
this.saveFileCallback(e)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ import { getMediaType, getDurationByUri } from '../../../databases/model/FileAss
|
||||
import Logger from '../../../base/log/Logger'
|
||||
import multimedia_image from '@ohos.multimedia.image'
|
||||
import AbilityCommonUtil from '../../../base/utils/AbilityCommonUtil'
|
||||
import ObjectUtil from '../../../base/utils/ObjectUtil'
|
||||
import StringUtil from '../../../base/utils/StringUtil'
|
||||
import { FileUtil } from '../../../base/utils/FileUtil'
|
||||
import fileAccess from '@ohos.file.fileAccess'
|
||||
|
||||
const TAG = 'myPhone'
|
||||
|
||||
@@ -89,41 +93,59 @@ struct MyPhone {
|
||||
}
|
||||
|
||||
async getBreadCrumb(data: string): Promise<void> {
|
||||
if (data.startsWith('Documents/')) {
|
||||
data = data.replace('Documents/', '')
|
||||
if (!data) {
|
||||
data = "";
|
||||
}
|
||||
let arr = data.split('/')
|
||||
arr.pop()
|
||||
if (arr.length == 0) {
|
||||
this.getRootListFile()
|
||||
return
|
||||
}
|
||||
const lastItem = arr[arr.length-1]
|
||||
if (lastItem.indexOf('.') > -1) {
|
||||
arr.pop()
|
||||
if (FileUtil.isUriPath(data)) {
|
||||
let fileHelper = await FileUtil.getFileAccessHelperAsync(globalThis.abilityContext);
|
||||
// 将uri转换成相对路径
|
||||
let curFileInfo: fileAccess.FileInfo = await FileUtil.getFileInfoByUri(data, fileHelper);
|
||||
if (!ObjectUtil.isNullOrUndefined(curFileInfo)) {
|
||||
data = FileUtil.getCurrentDir(curFileInfo.relativePath, FileUtil.isFolder(curFileInfo.mode));
|
||||
}
|
||||
}
|
||||
data = FileUtil.getPathWithFileSplit(data);
|
||||
|
||||
let fileIterator
|
||||
let fileData
|
||||
for (let j = 0;j < arr.length; j++) {
|
||||
const e = arr[j]
|
||||
if (j === 0) {
|
||||
let isContinue:boolean = true;
|
||||
let isRoot: boolean = true;
|
||||
while (isContinue) {
|
||||
isContinue = false;
|
||||
if (!fileIterator) {
|
||||
fileData = FileAccessExec.getRootFolder()
|
||||
isRoot = true;
|
||||
} else {
|
||||
fileData = FileAccessExec.getFileByCurIterator(fileIterator, false)
|
||||
fileData = FileAccessExec.getFileByCurIterator(fileIterator)
|
||||
isRoot = false;
|
||||
}
|
||||
if (Array.isArray(fileData)) {
|
||||
isContinue = true;
|
||||
for (let i = 0;i < fileData.length; i++) {
|
||||
if (fileData[i].fileName == e) {
|
||||
this.direList.push({ title: e, url: fileData[i].uri, fileIterator: fileData[i].fileIterator })
|
||||
fileIterator = fileData[i].fileIterator
|
||||
break
|
||||
let fileName:string = fileData[i].fileName;
|
||||
let currentDir:string = FileUtil.getPathWithFileSplit(fileData[i].currentDir);
|
||||
if (data.startsWith(currentDir)) {
|
||||
if (fileData[i].isFolder) {
|
||||
this.direList.push({ title: fileName, url: fileData[i].uri, fileIterator: fileData[i].fileIterator })
|
||||
fileIterator = fileData[i].fileIterator
|
||||
if (data === currentDir) {
|
||||
isContinue = false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isRoot && !fileIterator) {
|
||||
isContinue = false;
|
||||
}
|
||||
}
|
||||
if (arr.length >= 1) {
|
||||
fileData = FileAccessExec.getFileByCurIterator(fileIterator, false)
|
||||
if (fileIterator) {
|
||||
fileData = FileAccessExec.getFileByCurIterator(fileIterator)
|
||||
this.fileListSource.setData(fileData)
|
||||
} else {
|
||||
this.getRootListFile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +165,7 @@ struct MyPhone {
|
||||
}
|
||||
|
||||
getListFile(fileInfo) {
|
||||
let fileList = FileAccessExec.getFileByCurIterator(fileInfo, false)
|
||||
let fileList = FileAccessExec.getFileByCurIterator(fileInfo)
|
||||
this.fileListSource.setData(fileList)
|
||||
this.getVideoAudioDuration(fileList)
|
||||
}
|
||||
@@ -208,12 +230,28 @@ struct MyPhone {
|
||||
multimedia_image.createPixelMap(new ArrayBuffer(4096), { size: { height: 1, width: 2 } }).then((pixelMap) => {
|
||||
})
|
||||
this.setShowLoading(true)
|
||||
if (!router.getParams()) {
|
||||
this.getRootListFile()
|
||||
let pickPath = this.getParams();
|
||||
if (StringUtil.isEmpty(pickPath)) {
|
||||
this.getRootListFile();
|
||||
} else {
|
||||
this.getBreadCrumb(router.getParams()['path'])
|
||||
this.getBreadCrumb(pickPath);
|
||||
}
|
||||
this.setShowLoading(false)
|
||||
this.setShowLoading(false);
|
||||
}
|
||||
|
||||
getParams(): string {
|
||||
let defaultPickPath = globalThis.keyFileDefaultPickPath;
|
||||
if (!ObjectUtil.isNullOrUndefined(defaultPickPath)) {
|
||||
return defaultPickPath;
|
||||
}
|
||||
let params = router.getParams();
|
||||
if (!ObjectUtil.isNullOrUndefined(params)) {
|
||||
defaultPickPath = params['path'];
|
||||
if (!ObjectUtil.isNullOrUndefined(defaultPickPath)) {
|
||||
return defaultPickPath;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
onDireListChange(): void {
|
||||
|
||||
@@ -17,15 +17,25 @@ import { FilesData } from '../../databases/model/FileData'
|
||||
import { on } from '../../base/utils/EventBus'
|
||||
import FileAccessExec from '../../base/utils/FileAccessExec'
|
||||
import { TREE_LAYER } from '../../base/constants/UiConstant'
|
||||
import { FOLDER_LEVEL } from '../../base/constants/Constant'
|
||||
import { FileUtil } from '../../base/utils/FileUtil'
|
||||
import { ArrayUtil } from '../../base/utils/ArrayUtil'
|
||||
import { FileBase } from '../../databases/model/base/FileBase'
|
||||
import Logger from '../../base/log/Logger'
|
||||
import fileAccess from '@ohos.file.fileAccess'
|
||||
import ObjectUtil from '../../base/utils/ObjectUtil'
|
||||
|
||||
@Styles function pressedStyles() {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.hicloud_hmos_bg'))
|
||||
}
|
||||
|
||||
const TAG = 'TreeItem';
|
||||
|
||||
@Component
|
||||
export struct TreeItem {
|
||||
fileItem: FilesData = new FilesData({})
|
||||
loadPath?: string = '';
|
||||
isNeedExpand: boolean = false;
|
||||
@State iconRotate: boolean = false
|
||||
@State subFolderList: Array<FilesData> = new Array<FilesData>()
|
||||
@Link chooseItem: FilesData
|
||||
@@ -35,48 +45,176 @@ export struct TreeItem {
|
||||
@Link folderList: Array<FilesData>
|
||||
@State isShowArrow: boolean = true
|
||||
@Prop layer: number
|
||||
@State isLoading: boolean = false;
|
||||
@Link @Watch('clickExpandChange') isClickExpand: boolean;
|
||||
|
||||
getSelectItem(path: string): Array<FilesData> {
|
||||
let folderList = new Array<FilesData>()
|
||||
let fileList = new Array<FilesData>()
|
||||
let allFileList = FileAccessExec.getFileByCurIterator(this.fileItem.fileIterator)
|
||||
allFileList.forEach((item) => {
|
||||
if (item.isFolder) {
|
||||
item.path = `${path}/${item.fileName}`
|
||||
folderList.push(new FilesData({
|
||||
...item
|
||||
}))
|
||||
} else {
|
||||
fileList.push(new FilesData({
|
||||
...item
|
||||
}))
|
||||
}
|
||||
})
|
||||
private changeSelectItem(selectedItem: FilesData, autoShow: boolean) {
|
||||
if (selectedItem) {
|
||||
selectedItem.autoShow = autoShow;
|
||||
this.chooseItem = selectedItem;
|
||||
this.selectUri = this.chooseItem.uri;
|
||||
this.selectName = this.chooseItem.fileName;
|
||||
}
|
||||
}
|
||||
|
||||
private async executeQuery(dirUri: string, defaultExpandPath: string, call: Function) {
|
||||
this.isLoading = true;
|
||||
if (!this.isNeedExpand || (this.isNeedExpand && !this.isClickExpand)) {
|
||||
this.changeSelectItem(this.fileItem, false);
|
||||
}
|
||||
|
||||
let queryRes = await this.getPickPathListFiles(dirUri, defaultExpandPath, this.fileItem.layer);
|
||||
this.isLoading = false;
|
||||
let subList: Array<FilesData> = this.fileBaseToFileData(queryRes);
|
||||
let { folderList, fileList } = this.transfer(subList);
|
||||
this.fileList = fileList
|
||||
return folderList
|
||||
call(folderList);
|
||||
}
|
||||
|
||||
private async getPickPathListFiles(dirUri: string, expandPath: string, level: number): Promise<Array<FileBase>> {
|
||||
let fileHelper = await FileUtil.getFileAccessHelperAsync(globalThis.abilityContext);
|
||||
let fileInfo: fileAccess.FileInfo = await FileUtil.getFileInfoByUri(dirUri, fileHelper);
|
||||
if (ObjectUtil.isNullOrUndefined(fileInfo) || !FileUtil.isFolder(fileInfo.mode)) {
|
||||
Logger.e(TAG, 'uri is not folder');
|
||||
return;
|
||||
}
|
||||
let queryRes = FileAccessExec.getPathPickSubFiles(fileInfo, expandPath, level);
|
||||
if (ObjectUtil.isNull(queryRes)) {
|
||||
Logger.e(TAG, 'files is null');
|
||||
return;
|
||||
}
|
||||
return queryRes;
|
||||
}
|
||||
|
||||
transfer(list: FilesData[]) {
|
||||
let folderList = new Array<FilesData>();
|
||||
let fileList = new Array<FilesData>();
|
||||
if (ArrayUtil.isEmpty(list)) {
|
||||
return { folderList, fileList };
|
||||
}
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let fileData = list[i];
|
||||
if (fileData.isFolder) {
|
||||
folderList.push(fileData);
|
||||
} else {
|
||||
fileList.push(fileData);
|
||||
}
|
||||
}
|
||||
return { folderList, fileList };
|
||||
}
|
||||
|
||||
fileBaseToFileData(list: Array<FileBase>): Array<FilesData> {
|
||||
let fileArray = new Array<FilesData>();
|
||||
if (ArrayUtil.isEmpty(list)) {
|
||||
return fileArray;
|
||||
}
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let data = list[i];
|
||||
let fileData = new FilesData([]);
|
||||
fileData.uri = data.uri;
|
||||
fileData.fileName = data.fileName;
|
||||
fileData.isFolder = data.isFolder;
|
||||
fileData.size = data.fileSize;
|
||||
fileData.mtime = data.modifyTime;
|
||||
fileData.path = data.relativePath;
|
||||
fileData.currentDir = data.currentDir;
|
||||
if (data.isFolder) {
|
||||
if (!ArrayUtil.isEmpty(data.subList)) {
|
||||
fileData.setSubList(this.fileBaseToFileData(data.subList))
|
||||
}
|
||||
}
|
||||
fileArray.push(fileData);
|
||||
}
|
||||
return fileArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否需要展开目录,如果最近保存的目录不为空,需要展开到最近保存的目录
|
||||
*
|
||||
* @returns true:需要展开目录
|
||||
*/
|
||||
needExpandPath(): boolean {
|
||||
if (!this.canExpandPath() || this.isClickExpand) {
|
||||
return false;
|
||||
}
|
||||
return FileUtil.hasSubFolder(this.loadPath, this.fileItem.currentDir);
|
||||
}
|
||||
|
||||
clickExpandChange() {
|
||||
this.isNeedExpand = false;
|
||||
this.loadPath = '';
|
||||
}
|
||||
|
||||
canExpandPath(): boolean {
|
||||
return this.layer <= FOLDER_LEVEL.MAX_LEVEL;
|
||||
}
|
||||
|
||||
loadSubFolder(subFolderList: Array<FilesData>) {
|
||||
this.subFolderList = subFolderList;
|
||||
this.folderList = this.subFolderList;
|
||||
this.fileItem.setSubFolderList(subFolderList);
|
||||
Logger.i(TAG, "loadSubFolder:selectUri = " + this.selectUri +
|
||||
" ; subFolderListSize = " + this.subFolderList.length +
|
||||
" ; iconRotate = " + this.iconRotate);
|
||||
}
|
||||
|
||||
aboutToAppear() {
|
||||
on('fileMkdir', (e) => {
|
||||
on('fileMkdir', async (e) => {
|
||||
if (this.selectUri === this.fileItem.uri) {
|
||||
// 获取当前选中文件夹下的所有子文件
|
||||
this.subFolderList = this.getSelectItem(this.fileItem.path)
|
||||
let queryArray = await this.getPickPathListFiles(this.fileItem.uri, "", this.fileItem.layer);
|
||||
let subList: Array<FilesData> = this.fileBaseToFileData(queryArray);
|
||||
let { folderList, fileList } = this.transfer(subList);
|
||||
this.fileList = fileList
|
||||
// 获取当前选中文件夹下的所有子文件
|
||||
this.subFolderList = folderList;
|
||||
this.expandSubFolderCall(folderList);
|
||||
// 查找刚刚新建的文件夹index
|
||||
const index = this.subFolderList.findIndex(item => item.fileName === e.mkdirName)
|
||||
if (index !== -1) {
|
||||
const index = this.subFolderList.findIndex(item => item.fileName === e.mkdirName);
|
||||
if (index !== -1 && this.canExpandPath()) {
|
||||
// 默认选中刚刚新建的文件夹
|
||||
this.chooseItem = this.subFolderList[index]
|
||||
this.selectUri = this.subFolderList[index].uri
|
||||
this.selectName = this.subFolderList[index].fileName
|
||||
this.iconRotate = true
|
||||
this.folderList = []
|
||||
this.fileList = []
|
||||
} else {
|
||||
this.folderList = this.subFolderList
|
||||
this.changeSelectItem(this.subFolderList[index], true);
|
||||
this.iconRotate = true;
|
||||
this.fileList = [];
|
||||
this.folderList = [];
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.fileItem.setLayer(this.layer);
|
||||
this.isNeedExpand = this.needExpandPath();
|
||||
if (this.isNeedExpand) {
|
||||
Logger.i(TAG, "NeedExpand:loadPath = " + this.loadPath +
|
||||
" ; path = " + this.fileItem.currentDir);
|
||||
this.clickExpand(false);
|
||||
}
|
||||
}
|
||||
|
||||
clickExpand(forceLoading: boolean) {
|
||||
if (!this.isLoading) {
|
||||
if (this.iconRotate) {
|
||||
this.iconRotate = !this.iconRotate;
|
||||
this.changeSelectItem(this.fileItem, false);
|
||||
this.fileItem.subFileList = null;
|
||||
this.folderList = this.fileItem.subFolderList;
|
||||
} else {
|
||||
if (this.canExpandPath()) {
|
||||
if (this.fileItem.hasSubFolderList() && !forceLoading) {
|
||||
this.changeSelectItem(this.fileItem, false);
|
||||
this.fileList = this.fileItem.subFileList;
|
||||
this.expandSubFolderCall(this.fileItem.getSubFolderList());
|
||||
} else {
|
||||
this.executeQuery(this.fileItem.uri, this.loadPath, this.expandSubFolderCall.bind(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private expandSubFolderCall(subFolderList: Array<FilesData>) {
|
||||
this.iconRotate = !this.iconRotate;
|
||||
this.loadSubFolder(subFolderList);
|
||||
this.isShowArrow = this.subFolderList.length !== 0;
|
||||
}
|
||||
|
||||
build() {
|
||||
@@ -94,13 +232,21 @@ export struct TreeItem {
|
||||
.layoutWeight(1)
|
||||
.maxLines(1)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
Image($r('app.media.ic_arrow_right'))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.renderMode(ImageRenderMode.Original)
|
||||
.aspectRatio(1)
|
||||
.width($r('app.float.common_size15'))
|
||||
.rotate({ z: 90, angle: this.iconRotate ? 90 : 0 })
|
||||
.visibility(this.isShowArrow ? Visibility.Visible : Visibility.None)
|
||||
if (this.isLoading) {
|
||||
LoadingProgress()
|
||||
.width($r('app.float.common_size24'))
|
||||
.height($r('app.float.common_size24'))
|
||||
.color($r('sys.color.ohos_id_color_text_secondary'))
|
||||
} else {
|
||||
Image($r('app.media.ic_arrow_right'))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.autoResize(true)
|
||||
.height($r('app.float.common_size12'))
|
||||
.width($r('app.float.common_size12'))
|
||||
.interpolation(ImageInterpolation.Medium)
|
||||
.rotate({ z: 90, angle: this.iconRotate ? 90 : 0 })
|
||||
.visibility(this.isShowArrow ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.padding({
|
||||
@@ -114,25 +260,22 @@ export struct TreeItem {
|
||||
pressed: pressedStyles
|
||||
})
|
||||
.onClick(() => {
|
||||
this.iconRotate = !this.iconRotate
|
||||
this.selectUri = this.fileItem.uri
|
||||
this.selectName = this.fileItem.fileName
|
||||
this.chooseItem = this.fileItem
|
||||
this.subFolderList = this.getSelectItem(this.fileItem.path)
|
||||
this.folderList = this.subFolderList
|
||||
this.isShowArrow = this.subFolderList.length !== 0
|
||||
this.isClickExpand = true;
|
||||
this.clickExpand(true);
|
||||
})
|
||||
|
||||
if (this.subFolderList.length && this.iconRotate) {
|
||||
ForEach(this.subFolderList, (item) => {
|
||||
TreeItem({
|
||||
fileItem: item,
|
||||
loadPath: this.loadPath,
|
||||
chooseItem: $chooseItem,
|
||||
selectUri: $selectUri,
|
||||
selectName: $selectName,
|
||||
layer: this.layer + 1,
|
||||
folderList: $folderList,
|
||||
fileList: $fileList
|
||||
fileList: $fileList,
|
||||
isClickExpand: $isClickExpand
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
.backgroundColor($r('app.color.button_pressStyles'))
|
||||
}
|
||||
|
||||
@Styles function normalStyles () {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.transparent_color'))
|
||||
}
|
||||
|
||||
@Component
|
||||
export struct DialogTitle {
|
||||
title: Resource
|
||||
@@ -63,7 +68,8 @@ export struct DialogButton {
|
||||
.layoutWeight(1)
|
||||
.backgroundColor(this.bgColor)
|
||||
.stateStyles({
|
||||
pressed: pressStyles
|
||||
pressed: pressStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.opacity(this.isDisabled ? $r('app.float.common_opacity5') : $r('app.float.common_opacity10'))
|
||||
.borderRadius($r('app.float.common_borderRadius18'))
|
||||
|
||||
@@ -22,6 +22,11 @@ import AbilityCommonUtil from '../../../base//utils/AbilityCommonUtil'
|
||||
.backgroundColor($r('app.color.hicloud_hmos_bg'))
|
||||
}
|
||||
|
||||
@Styles function normalStyles () {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.transparent_color'))
|
||||
}
|
||||
|
||||
@Extend(Text) function subtitleStyles(fontSize: Resource) {
|
||||
.fontSize(fontSize)
|
||||
.alignSelf(ItemAlign.Start)
|
||||
@@ -90,6 +95,7 @@ export struct TopBar {
|
||||
.objectFit(ImageFit.Contain)
|
||||
.width($r('app.float.common_size24'))
|
||||
.height($r('app.float.common_size24'))
|
||||
.interpolation(ImageInterpolation.Medium)
|
||||
}.padding({
|
||||
left: $r('app.float.common_padding12'),
|
||||
right: $r('app.float.common_padding12'),
|
||||
@@ -97,7 +103,8 @@ export struct TopBar {
|
||||
bottom: $r('app.float.common_padding10')
|
||||
})
|
||||
.stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.onClick(() => {
|
||||
this.backCallback.call(this)
|
||||
@@ -132,6 +139,7 @@ export struct TopBar {
|
||||
.objectFit(ImageFit.Contain)
|
||||
.width($r('app.float.common_size24'))
|
||||
.height($r('app.float.common_size24'))
|
||||
.interpolation(ImageInterpolation.Medium)
|
||||
}.padding({
|
||||
left: $r('app.float.common_padding12'),
|
||||
right: $r('app.float.common_padding12'),
|
||||
@@ -139,7 +147,8 @@ export struct TopBar {
|
||||
bottom: $r('app.float.common_padding10')
|
||||
})
|
||||
.stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.onClick(() => {
|
||||
let abilityContext = getContext(this) as context.UIAbilityContext
|
||||
@@ -158,7 +167,8 @@ export struct TopBar {
|
||||
bottom: $r('app.float.common_padding10')
|
||||
})
|
||||
.stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.onClick(() => {
|
||||
this.terminate()
|
||||
|
||||
@@ -18,11 +18,16 @@
|
||||
.backgroundColor($r('app.color.hicloud_hmos_bg'))
|
||||
}
|
||||
|
||||
@Styles function normalStyles () {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.transparent_color'))
|
||||
}
|
||||
|
||||
@Component
|
||||
export struct TopOperateBar {
|
||||
public addFolder: () => void // 点击新建的事件回调
|
||||
// 是否可用
|
||||
isDisabled: boolean = false
|
||||
@Prop isDisabled: boolean = false
|
||||
// 列表或宫格
|
||||
@Consume isList: boolean
|
||||
|
||||
@@ -44,7 +49,8 @@ export struct TopOperateBar {
|
||||
bottom: $r('app.float.common_padding10')
|
||||
})
|
||||
.stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.onClick(() => {
|
||||
if (this.isDisabled) return
|
||||
@@ -71,7 +77,8 @@ export struct TopOperateBar {
|
||||
if (this.isDisabled) return
|
||||
this.isList = !this.isList
|
||||
}).stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import { FilesData } from '../../../databases/model/FileData'
|
||||
import FileAccessExec from '../../../base/utils/FileAccessExec'
|
||||
import { toast, isValidFileName } from '../../../base/utils/Common'
|
||||
import { createName, getResourceString } from '../../../base/utils/Tools'
|
||||
import { getResourceString } from '../../../base/utils/Tools'
|
||||
import Logger from '../../../base/log/Logger'
|
||||
import { DialogTitle, DialogButton, DialogButtonDivider } from '../common/DialogComponent'
|
||||
|
||||
@@ -29,12 +29,25 @@ export struct FileMkdirDialog {
|
||||
cancel: Function
|
||||
confirm: Function
|
||||
@State folderName: string = ''
|
||||
@State errorText: string = ''
|
||||
@State errorText: Resource = null
|
||||
fileItems: Array<FilesData>
|
||||
getCurrentDir: string = ''
|
||||
|
||||
aboutToAppear() {
|
||||
this.folderName = createName(this.fileItems, getResourceString($r('app.string.addFolder')))
|
||||
this.folderName = this.getNewFolderName()
|
||||
}
|
||||
|
||||
getNewFolderName(): string {
|
||||
const newFolderText = getResourceString($r('app.string.addFolder'));
|
||||
const regExp = new RegExp(`^${newFolderText}([ ]{1}[0-9]+)*$`);
|
||||
const tempFolderList = this.fileItems.filter(item => item.isFolder && regExp.test(item.fileName));
|
||||
let tempFolderName = newFolderText;
|
||||
let index = 0;
|
||||
while (tempFolderList.some(item => item.fileName === tempFolderName)) {
|
||||
index += 1;
|
||||
tempFolderName = newFolderText + ' ' + index.toString();
|
||||
};
|
||||
return tempFolderName;
|
||||
}
|
||||
|
||||
isSameName() {
|
||||
@@ -61,7 +74,7 @@ export struct FileMkdirDialog {
|
||||
})
|
||||
.onChange((value: string) => {
|
||||
this.folderName = value
|
||||
this.errorText = ''
|
||||
this.errorText = null
|
||||
})
|
||||
Divider().vertical(false).strokeWidth(1).color(Color.Gray)
|
||||
.margin({
|
||||
@@ -89,9 +102,9 @@ export struct FileMkdirDialog {
|
||||
isDisabled: !this.folderName.trim(),
|
||||
click: () => {
|
||||
if (!isValidFileName(this.folderName)) {
|
||||
this.errorText = getResourceString($r('app.string.illegal'))
|
||||
this.errorText = $r('app.string.illegal')
|
||||
} else if (this.isSameName()) {
|
||||
this.errorText = getResourceString($r('app.string.sameName'))
|
||||
this.errorText = $r('app.string.sameName')
|
||||
} else {
|
||||
FileAccessExec.createFolder(this.getCurrentDir, this.folderName).then(folderUri => {
|
||||
this.confirm({
|
||||
|
||||
@@ -20,14 +20,26 @@ import { TreeItem } from '../TreeItem'
|
||||
import { FileMkdirDialog } from './FileMkdirDialog'
|
||||
import { emit } from '../../../base/utils/EventBus'
|
||||
import { getResourceString } from '../../../base/utils/Tools'
|
||||
import { FILENAME_MAX_LENGTH } from '../../../base/constants/Constant'
|
||||
import { FILENAME_MAX_LENGTH, FILE_MANAGER_PREFERENCES, FOLDER_LEVEL } from '../../../base/constants/Constant'
|
||||
import StringUtil from '../../../base/utils/StringUtil'
|
||||
import { setPreferencesValue } from '../../../base/utils/PreferencesUtil'
|
||||
import { FileUtil } from '../../../base/utils/FileUtil'
|
||||
import Logger from '../../../base/log/Logger'
|
||||
import { ArrayUtil } from '../../../base/utils/ArrayUtil'
|
||||
import ErrorCodeConst from '../../../base/constants/ErrorCodeConst'
|
||||
|
||||
@Styles function pressedStyles () {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.hicloud_hmos_bg'))
|
||||
}
|
||||
|
||||
@Styles function normalStyles() {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.transparent_color'))
|
||||
}
|
||||
|
||||
const TAG = 'fileTree';
|
||||
|
||||
@Component
|
||||
export struct fileTree {
|
||||
@State listLength: number = 0
|
||||
@@ -37,7 +49,7 @@ export struct fileTree {
|
||||
@State selectUri: string = ''
|
||||
@State @Watch('nameChange') selectName: string = getResourceString($r('app.string.myPhone'))
|
||||
public moveCallback: (e) => void
|
||||
@State chooseItem: FilesData = new FilesData({})
|
||||
@State @Watch('selectChange') chooseItem: FilesData = new FilesData({})
|
||||
@State folderList: FilesData[] = new Array<FilesData>()
|
||||
@State fileList: FilesData[] = new Array<FilesData>()
|
||||
@State changeTitle: Resource = undefined
|
||||
@@ -55,6 +67,13 @@ export struct fileTree {
|
||||
})
|
||||
@State isSelectRootPath: boolean = true
|
||||
@State errorText: Resource = undefined
|
||||
@State isNeedLoadDefaultPath: boolean = false
|
||||
@State isClickExpand: boolean = false;
|
||||
@Link @Watch('createFileFailTypeChange') createFileFailType: number;
|
||||
lastSelectPath: string = AppStorage.Get<string>(FILE_MANAGER_PREFERENCES.lastSelectPath.key);
|
||||
defaultExpandPath: string = '';
|
||||
scroller: Scroller = new Scroller();
|
||||
context: Context = globalThis.abilityContext;
|
||||
|
||||
async aboutToAppear() {
|
||||
toast($r('app.string.select_location'))
|
||||
@@ -63,12 +82,16 @@ export struct fileTree {
|
||||
const fileName: string = fileNameList[0]
|
||||
if (fileName) {
|
||||
const dotIndex = fileName.lastIndexOf('.')
|
||||
if (dotIndex > 0) {
|
||||
this.fileName = fileName.substring(0, dotIndex)
|
||||
this.suffix = fileName.substring(dotIndex + 1)
|
||||
let fileSuffix = globalThis.keyFileSuffixChoices;
|
||||
if (!StringUtil.isEmpty(fileSuffix)) {
|
||||
this.suffix = fileSuffix;
|
||||
if (dotIndex > 0) {
|
||||
this.fileName = fileName.substring(0, dotIndex) + fileSuffix;
|
||||
} else {
|
||||
this.fileName = fileName + fileSuffix;
|
||||
}
|
||||
} else {
|
||||
this.fileName = fileName
|
||||
this.suffix = ''
|
||||
this.fileName = fileName;
|
||||
}
|
||||
}
|
||||
this.nameChange()
|
||||
@@ -81,6 +104,7 @@ export struct fileTree {
|
||||
if (globalThis.documentInfo) {
|
||||
this.selectUri = globalThis.documentInfo.uri
|
||||
}
|
||||
this.loadDefaultExpandPath();
|
||||
}
|
||||
|
||||
fileMkdir(e) {
|
||||
@@ -112,17 +136,102 @@ export struct fileTree {
|
||||
}
|
||||
}
|
||||
|
||||
createFileFailTypeChange() {
|
||||
if (this.createFileFailType === ErrorCodeConst.PICKER.FILE_NAME_EXIST) {
|
||||
this.errorText = $r('app.string.save_file_has_same_file');
|
||||
this.createFileFailType = ErrorCodeConst.PICKER.NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
selectChange() {
|
||||
let autoShow: boolean = false;
|
||||
if (this.chooseItem) {
|
||||
autoShow = this.chooseItem.autoShow;
|
||||
this.chooseItem.autoShow = false;
|
||||
}
|
||||
if (!this.isClickExpand || autoShow) {
|
||||
let loadSubFinish = FileUtil.loadSubFinish(this.defaultExpandPath, this.chooseItem.currentDir, FOLDER_LEVEL.MAX_LEVEL - 2);
|
||||
if (loadSubFinish || autoShow) {
|
||||
let allData: Array<FilesData> = new Array<FilesData>();
|
||||
let pos = this.getSelectItemPos(this.rootData, allData);
|
||||
let itemHeight: number = this.context.resourceManager.getNumber($r('app.float.common_size56'));
|
||||
let scrollY: number = itemHeight * (pos - 1);
|
||||
Logger.i(TAG, "selectItemPos = " + pos + ",itemHeight = " + itemHeight + " ; scrollY = " + scrollY)
|
||||
setTimeout(() => {
|
||||
if (scrollY < 0) {
|
||||
this.scroller.scrollEdge(Edge.Start);
|
||||
} else {
|
||||
this.scroller.scrollTo({ xOffset: 0, yOffset: scrollY });
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getSelectItemPos(fileList: Array<FilesData>, allData: Array<FilesData>): number {
|
||||
if (ArrayUtil.isEmpty(allData)) {
|
||||
allData = [];
|
||||
}
|
||||
if (!ArrayUtil.isEmpty(fileList)) {
|
||||
for (let index = 0; index < fileList.length; index++) {
|
||||
const fileData: FilesData = fileList[index];
|
||||
allData.push(fileData);
|
||||
if (fileData.uri === this.selectUri) {
|
||||
return allData.length;
|
||||
}
|
||||
if (fileData.hasSubFolderList()) {
|
||||
let subFolderList: Array<FilesData> = fileData.getSubFolderList();
|
||||
let result = this.getSelectItemPos(subFolderList, allData);
|
||||
if (result > 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载默认展开目录,如果是路径选择器拉起的,优先使用三方指定的目录
|
||||
*/
|
||||
async loadDefaultExpandPath() {
|
||||
let defaultPickDir = globalThis.keyPathDefaultPickDir;
|
||||
let loadUri = this.lastSelectPath;
|
||||
if (!StringUtil.isEmpty(defaultPickDir)) {
|
||||
loadUri = defaultPickDir;
|
||||
}
|
||||
if (!StringUtil.isEmpty(loadUri)) {
|
||||
let fileHelper = await FileUtil.getFileAccessHelperAsync(globalThis.abilityContext);
|
||||
let fileInfo = await FileUtil.getFileInfoByUri(loadUri, fileHelper);
|
||||
if (fileInfo) {
|
||||
this.defaultExpandPath = FileUtil.getCurrentFolderByFileInfo(fileInfo);
|
||||
Logger.i(TAG, "loadDefaultExpandPath = " + this.defaultExpandPath);
|
||||
// 值为true,说明需要刷新树布局,并且传入loadPath
|
||||
this.isNeedLoadDefaultPath = !StringUtil.isEmpty(this.defaultExpandPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private canCreateFolder(): boolean {
|
||||
if (this.chooseItem && this.chooseItem.layer) {
|
||||
return this.chooseItem.layer < FOLDER_LEVEL.MAX_LEVEL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Row() {
|
||||
Image($r("app.media.hidisk_cancel_normal"))
|
||||
.width($r('app.float.common_size46'))
|
||||
.height($r('app.float.common_size30'))
|
||||
.height($r('app.float.common_size46'))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.margin({ top: $r('app.float.common_margin10') })
|
||||
.padding($r('app.float.common_padding10'))
|
||||
.stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.interpolation(ImageInterpolation.Medium)
|
||||
.onClick(() => {
|
||||
this.moveCallback.call(this, {
|
||||
cancel: true
|
||||
@@ -131,34 +240,40 @@ export struct fileTree {
|
||||
Blank()
|
||||
Image($r('app.media.hidisk_ic_add_folder'))
|
||||
.width($r('app.float.common_size46'))
|
||||
.height($r('app.float.common_size30'))
|
||||
.height($r('app.float.common_size46'))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.margin({
|
||||
left: $r('app.float.common_margin2'),
|
||||
top: $r('app.float.common_margin10'),
|
||||
right: $r('app.float.common_margin10')
|
||||
})
|
||||
.margin({ left: $r('app.float.common_margin2') })
|
||||
.padding($r('app.float.common_padding10'))
|
||||
.stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.enabled(this.canCreateFolder())
|
||||
.opacity(this.canCreateFolder() ? $r('app.float.common_opacity10') : $r('app.float.common_opacity2'))
|
||||
.interpolation(ImageInterpolation.Medium)
|
||||
.onClick(() => {
|
||||
this.fileMkdirDialog.open()
|
||||
})
|
||||
Image($r('app.media.ic_ok'))
|
||||
.width($r('app.float.common_size46'))
|
||||
.height($r('app.float.common_size30'))
|
||||
.height($r('app.float.common_size46'))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.margin({ left: $r('app.float.common_margin2'), top: $r('app.float.common_margin10') })
|
||||
.objectFit(ImageFit.Contain)
|
||||
.margin({ left: $r('app.float.common_margin2') })
|
||||
.padding($r('app.float.common_padding10'))
|
||||
.stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.onClick(() => {
|
||||
.onClick(async () => {
|
||||
setPreferencesValue(FILE_MANAGER_PREFERENCES.name, FILE_MANAGER_PREFERENCES.lastSelectPath.key, this.selectUri);
|
||||
AppStorage.SetOrCreate<string>(FILE_MANAGER_PREFERENCES.lastSelectPath.key, this.selectUri);
|
||||
const prefix = this.fileName.trim()
|
||||
if (!prefix) {
|
||||
this.errorText = $r('app.string.input_nothing')
|
||||
return
|
||||
}
|
||||
const fileName = `${prefix}${this.suffix ? '.' : ''}${this.suffix}`
|
||||
const fileName = this.fileName.trim()
|
||||
if (StringUtil.getBytesCount(fileName) > FILENAME_MAX_LENGTH) {
|
||||
this.errorText = $r('app.string.max_input_length')
|
||||
} else if (!isValidFileName(fileName)) {
|
||||
@@ -178,7 +293,6 @@ export struct fileTree {
|
||||
bottom: $r('app.float.common_padding30'),
|
||||
left: $r('app.float.common_padding15')
|
||||
})
|
||||
.borderRadius($r('app.float.common_borderRadius10'))
|
||||
|
||||
Row() {
|
||||
if (this.listLength > 1) {
|
||||
@@ -209,6 +323,7 @@ export struct fileTree {
|
||||
if (this.listLength <= 1) {
|
||||
Column() {
|
||||
TextInput({ text: this.fileName })
|
||||
.fontSize($r('app.float.common_font_size16'))
|
||||
.backgroundColor($r('app.color.text_input_bg_color'))
|
||||
.onChange((newVal) => {
|
||||
this.fileName = newVal
|
||||
@@ -237,7 +352,7 @@ export struct fileTree {
|
||||
.margin({ bottom: $r('app.float.common_size10') })
|
||||
}
|
||||
|
||||
Row().width('100%').height($r('app.float.common_size6')).backgroundColor($r('app.color.move_dialog_divider'))
|
||||
Row().width('100%').height($r('app.float.common_size4')).opacity(0.05).backgroundColor($r('app.color.black'))
|
||||
|
||||
Row() {
|
||||
Image($r('app.media.hidisk_ic_classify_phone'))
|
||||
@@ -252,9 +367,10 @@ export struct fileTree {
|
||||
.layoutWeight(1)
|
||||
Image($r('app.media.ic_arrow_right'))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.renderMode(ImageRenderMode.Original)
|
||||
.aspectRatio(1)
|
||||
.width($r('app.float.common_size15'))
|
||||
.autoResize(true)
|
||||
.height($r('app.float.common_size12'))
|
||||
.width($r('app.float.common_size12'))
|
||||
.interpolation(ImageInterpolation.Medium)
|
||||
.rotate({ z: 90, angle: this.topRotate ? 90 : 0 })
|
||||
}
|
||||
.width('100%')
|
||||
@@ -264,7 +380,7 @@ export struct fileTree {
|
||||
left: $r('app.float.common_padding24'),
|
||||
right: $r('app.float.common_padding24')
|
||||
})
|
||||
.backgroundColor(this.isSelectRootPath ? $r('app.color.move_dialog_background') : '')
|
||||
.backgroundColor(this.isSelectRootPath ? $r('app.color.path_pick_selected_bg') : '')
|
||||
.onClick(async () => {
|
||||
this.selectName = getResourceString($r('app.string.myPhone'))
|
||||
this.selectUri = globalThis.documentInfo && globalThis.documentInfo?.uri
|
||||
@@ -274,34 +390,52 @@ export struct fileTree {
|
||||
this.fileList = fileList
|
||||
this.rootData = folderList
|
||||
this.folderList = this.rootData
|
||||
this.isClickExpand = true;
|
||||
this.defaultExpandPath = '';
|
||||
})
|
||||
|
||||
Scroll() {
|
||||
Scroll(this.scroller) {
|
||||
Column() {
|
||||
if (this.rootData.length && this.topRotate) {
|
||||
ForEach(this.rootData, (item) => {
|
||||
TreeItem({
|
||||
fileItem: item,
|
||||
selectUri: $selectUri,
|
||||
chooseItem: $chooseItem,
|
||||
selectName: $selectName,
|
||||
layer: 2,
|
||||
folderList: $folderList,
|
||||
fileList: $fileList
|
||||
})
|
||||
if (this.isNeedLoadDefaultPath) {
|
||||
TreeItem({
|
||||
fileItem: item,
|
||||
loadPath: this.defaultExpandPath,
|
||||
selectUri: $selectUri,
|
||||
chooseItem: $chooseItem,
|
||||
selectName: $selectName,
|
||||
layer: 2,
|
||||
folderList: $folderList,
|
||||
fileList: $fileList,
|
||||
isClickExpand: $isClickExpand
|
||||
})
|
||||
} else {
|
||||
TreeItem({
|
||||
fileItem: item,
|
||||
selectUri: $selectUri,
|
||||
chooseItem: $chooseItem,
|
||||
selectName: $selectName,
|
||||
layer: 2,
|
||||
folderList: $folderList,
|
||||
fileList: $fileList,
|
||||
isClickExpand: $isClickExpand
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.scrollBar(BarState.Off)
|
||||
.padding({ bottom: $r('app.float.common_padding2') })
|
||||
.layoutWeight(1)
|
||||
.padding({ bottom: $r('app.float.common_padding10') })
|
||||
.align(Alignment.TopStart)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.white'))
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.borderRadius({ topLeft: $r('app.float.common_size24'), topRight: $r('app.float.common_size24') })
|
||||
.position({ y: this.positionY })
|
||||
|
||||
.onAppear(() => {
|
||||
|
||||
@@ -20,6 +20,11 @@ import { BreadData } from '../../../databases/model/FileData'
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
}
|
||||
|
||||
@Styles function normalStyles () {
|
||||
.backgroundColor($r('app.color.transparent_color'))
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
}
|
||||
|
||||
@Component
|
||||
export struct BreadCrumb {
|
||||
@Link @Watch("onDireListUpdated") direList: BreadData[]
|
||||
@@ -27,7 +32,9 @@ export struct BreadCrumb {
|
||||
|
||||
// 监听面包屑变化,滚动到指定位置
|
||||
onDireListUpdated(): void {
|
||||
this.scroller.scrollEdge(Edge.End)
|
||||
setTimeout(() => {
|
||||
this.scroller.scrollEdge(Edge.End)
|
||||
}, 10);
|
||||
}
|
||||
|
||||
build() {
|
||||
@@ -40,13 +47,15 @@ export struct BreadCrumb {
|
||||
.fontColor(this.direList.length ? $r('app.color.detail_path_text_color') : $r('app.color.black'))
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
if (this.direList.length) {
|
||||
Image($r("app.media.ic_arrow_right"))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.height($r('app.float.common_size15'))
|
||||
.width($r('app.float.common_size15'))
|
||||
.interpolation(ImageInterpolation.Medium)
|
||||
}
|
||||
}
|
||||
.onClick(() => {
|
||||
@@ -103,7 +112,8 @@ struct BreadCrumbItem {
|
||||
.textAlign(TextAlign.Center)
|
||||
.maxLines(1)
|
||||
.stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
if (!this.isLast()) {
|
||||
Image($r("app.media.ic_arrow_right"))
|
||||
|
||||
@@ -30,6 +30,11 @@ const filePickerViewFlag = globalThis.filePickerViewFlag
|
||||
.backgroundColor($r('app.color.hicloud_hmos_bg'))
|
||||
}
|
||||
|
||||
@Styles function normalStyles() {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.transparent_color'))
|
||||
}
|
||||
|
||||
@Extend(Text) function grayText() {
|
||||
.fontSize($r('app.float.common_font_size12'))
|
||||
.fontColor($r('app.color.black'))
|
||||
@@ -144,6 +149,9 @@ struct FileListItem {
|
||||
|
||||
getRightIcon(item): Resource {
|
||||
if (this.isMulti) {
|
||||
if (pickerStatus(this.fileItem, this.checkedNum).differentTypes) {
|
||||
return
|
||||
}
|
||||
return item.isChecked ? $r("app.media.checkbox_b") : $r("app.media.checkbox_g")
|
||||
} else if (item.isFolder && this.isList) {
|
||||
return $r("app.media.ic_arrow_right")
|
||||
@@ -163,7 +171,8 @@ struct FileListItem {
|
||||
this.onClickEvent()
|
||||
})
|
||||
.stateStyles({
|
||||
pressed: pressedStyles
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.gesture(
|
||||
LongPressGesture({ repeat: false })
|
||||
@@ -181,11 +190,15 @@ struct FileListItem {
|
||||
Logger.i(TAG, 'longPressEvent start');
|
||||
if (!this.isMulti) {
|
||||
this.isMulti = true
|
||||
if (pickerStatus(this.fileItem, this.checkedNum).exceedLimit) {
|
||||
if (this.fileItem.isFolder) {
|
||||
return
|
||||
}
|
||||
let status = pickerStatus(this.fileItem, this.checkedNum);
|
||||
if (status.exceedLimit) {
|
||||
filePickerTip()
|
||||
return
|
||||
}
|
||||
if (!this.fileItem.isFolder && pickerStatus(this.fileItem, this.checkedNum).differentTypes) {
|
||||
if (status.differentTypes) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -195,22 +208,18 @@ struct FileListItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择器页面,判断文件不是用户期望的类型
|
||||
*/
|
||||
notTargetType(): boolean {
|
||||
return!this.fileItem.isFolder
|
||||
&& pickerStatus(this.fileItem, this.checkedNum).differentTypes
|
||||
}
|
||||
|
||||
onClickEvent() {
|
||||
Logger.i(TAG, 'onClickEvent start');
|
||||
let status = pickerStatus(this.fileItem, this.checkedNum);
|
||||
if (this.isMulti) {
|
||||
if (this.fileItem.isFolder) {
|
||||
return
|
||||
}
|
||||
// 选择器页面,选择文件超出上限
|
||||
if (pickerStatus(this.fileItem, this.checkedNum).exceedLimit) {
|
||||
if (status.exceedLimit) {
|
||||
filePickerTip()
|
||||
return
|
||||
} else if (this.notTargetType()) {
|
||||
} else if (status.differentTypes) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -225,15 +234,15 @@ struct FileListItem {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.notTargetType()) {
|
||||
return
|
||||
}
|
||||
if (!pickerStatus(this.fileItem, this.checkedNum).exceedLimit
|
||||
&& !pickerStatus(this.fileItem, this.checkedNum).differentTypes
|
||||
&& !this.fileItem.isFolder) {
|
||||
// 选中的数据回调给三方应用
|
||||
this.fileItem.pickFile()
|
||||
return
|
||||
if (!this.fileItem.isFolder) {
|
||||
if (status.differentTypes) {
|
||||
return
|
||||
}
|
||||
if (!status.exceedLimit && !status.differentTypes) {
|
||||
// 选中的数据回调给三方应用
|
||||
this.fileItem.pickFile()
|
||||
return
|
||||
}
|
||||
}
|
||||
this.clickFolder()
|
||||
}
|
||||
@@ -251,10 +260,9 @@ struct FileListItem {
|
||||
}
|
||||
|
||||
calOpacity() {
|
||||
return pickerStatus(this.fileItem, this.checkedNum).exceedLimit
|
||||
|| (!this.fileItem.isFolder &&
|
||||
pickerStatus(this.fileItem, this.checkedNum)
|
||||
.differentTypes) ? $r('app.float.common_opacity2') : $r('app.float.common_opacity10')
|
||||
const statusObj = pickerStatus(this.fileItem, this.checkedNum)
|
||||
return statusObj.exceedLimit || (!this.fileItem.isFolder && statusObj.differentTypes) || (this.isMulti && this.fileItem.isFolder)
|
||||
? $r('app.float.common_opacity2') : $r('app.float.common_opacity10')
|
||||
}
|
||||
|
||||
@Builder
|
||||
@@ -267,9 +275,9 @@ struct FileListItem {
|
||||
.height($r('app.float.common_size36'))
|
||||
.width($r('app.float.common_size36'))
|
||||
.borderRadius($r('app.float.album_borderRadius_5'))
|
||||
.onError(() => {
|
||||
.onError((error) => {
|
||||
this.isImageLoaded = false
|
||||
Logger.e(TAG, 'onError: ' + this.fileItem.fileName + ', ' + this.fileItem.thumbUri)
|
||||
Logger.e(TAG, 'onError: ' + this.fileItem.fileName + ', ' + this.fileItem.thumbUri + ',' + JSON.stringify(error))
|
||||
})
|
||||
if (isDlpFile(this.fileItem.fileName)) {
|
||||
Image($r("app.media.lockNoBorder"))
|
||||
@@ -311,11 +319,13 @@ struct FileListItem {
|
||||
.margin({ left: $r('app.float.common_margin10') })
|
||||
.width('70%')
|
||||
|
||||
Image(this.getRightIcon(this.fileItem))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.autoResize(false)
|
||||
.height($r('app.float.common_size20'))
|
||||
.width($r('app.float.common_size20'))
|
||||
if ((this.fileItem.isFolder && !this.isMulti) || (this.isMulti && !this.fileItem.isFolder)) {
|
||||
Image(this.getRightIcon(this.fileItem))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.autoResize(false)
|
||||
.height($r('app.float.common_size20'))
|
||||
.width($r('app.float.common_size20'))
|
||||
}
|
||||
}
|
||||
.height($r('app.float.common_size64'))
|
||||
.padding({ right: $r('app.float.common_padding16'), left: $r('app.float.common_padding16') })
|
||||
@@ -334,13 +344,15 @@ struct FileListItem {
|
||||
.onError(() => {
|
||||
this.isImageLoaded = false
|
||||
})
|
||||
Image(this.getRightIcon(this.fileItem))
|
||||
.objectFit(ImageFit.Fill)
|
||||
.width($r('app.float.common_size20'))
|
||||
.height($r('app.float.common_size20'))
|
||||
.opacity(true ? 1 : $r('app.float.common_opacity4'))
|
||||
.markAnchor({ x: $r('app.float.common_vp26'), y: $r('app.float.common_vp26') })
|
||||
.position({ x: '100%', y: '100%' })
|
||||
if ((this.fileItem.isFolder && !this.isMulti) || (this.isMulti && !this.fileItem.isFolder)) {
|
||||
Image(this.getRightIcon(this.fileItem))
|
||||
.objectFit(ImageFit.Fill)
|
||||
.width($r('app.float.common_size20'))
|
||||
.height($r('app.float.common_size20'))
|
||||
.opacity(true ? 1 : $r('app.float.common_opacity4'))
|
||||
.markAnchor({ x: $r('app.float.common_vp26'), y: $r('app.float.common_vp26') })
|
||||
.position({ x: '100%', y: '100%' })
|
||||
}
|
||||
if (isDlpFile(this.fileItem.fileName)) {
|
||||
Image($r("app.media.lockNoBorder"))
|
||||
.objectFit(ImageFit.Fill)
|
||||
|
||||
+25
-15
@@ -2,7 +2,7 @@
|
||||
"module": {
|
||||
"name": "entry",
|
||||
"type": "entry",
|
||||
"srcEntrance": "./ets/application/PickerAbilityStage.ets",
|
||||
"srcEntry": "./ets/application/PickerAbilityStage.ets",
|
||||
"description": "$string:module_desc",
|
||||
"mainElement": "MainAbility",
|
||||
"deviceTypes": [
|
||||
@@ -12,22 +12,16 @@
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
"pages": "$profile:main_pages",
|
||||
"metadata": [
|
||||
{
|
||||
"name": "ArkTSPartialUpdate",
|
||||
"value": "false"
|
||||
}
|
||||
],
|
||||
"abilities": [
|
||||
{
|
||||
"name": "MainAbility",
|
||||
"srcEntrance": "./ets/entryability/MainAbility.ts",
|
||||
"srcEntry": "./ets/entryability/MainAbility.ts",
|
||||
"description": "$string:EntryAbility_desc",
|
||||
"icon": "$media:app_icon",
|
||||
"label": "$string:EntryAbility_label",
|
||||
"startWindowIcon": "$media:app_icon",
|
||||
"startWindowBackground": "$color:start_window_background",
|
||||
"visible": true,
|
||||
"exported": true,
|
||||
"skills": [
|
||||
{
|
||||
"actions": [
|
||||
@@ -41,24 +35,40 @@
|
||||
requestPermissions: [
|
||||
// 媒体库管理权限
|
||||
{
|
||||
name: "ohos.permission.MEDIA_LOCATION"
|
||||
name: "ohos.permission.MEDIA_LOCATION",
|
||||
"reason": "$string:permission_storage_reason_tips",
|
||||
usedScene: {
|
||||
"when": "always",
|
||||
"abilities": ['MainAbility']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "ohos.permission.READ_MEDIA"
|
||||
name: "ohos.permission.READ_MEDIA",
|
||||
"reason": "$string:permission_storage_reason_tips",
|
||||
usedScene: {
|
||||
"when": "always",
|
||||
"abilities": ['MainAbility']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "ohos.permission.WRITE_MEDIA"
|
||||
name: "ohos.permission.WRITE_MEDIA",
|
||||
"reason": "$string:permission_storage_reason_tips",
|
||||
usedScene: {
|
||||
"when": "always",
|
||||
"abilities": ['MainAbility']
|
||||
}
|
||||
},
|
||||
// 文件管理权限
|
||||
{
|
||||
name: "ohos.permission.FILE_ACCESS_MANAGER"
|
||||
},
|
||||
// 应用程序包管理权限
|
||||
{
|
||||
name: 'ohos.permission.GET_BUNDLE_INFO'
|
||||
},
|
||||
{
|
||||
name: 'ohos.permission.GET_BUNDLE_INFO_PRIVILEGED'
|
||||
},
|
||||
// 公共目录uri代理授权的权限
|
||||
{
|
||||
"name": "ohos.permission.PROXY_AUTHORIZATION_URI"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -59,6 +59,14 @@
|
||||
{
|
||||
"name": "error_message_color",
|
||||
"value": "#FF3300"
|
||||
},
|
||||
{
|
||||
"name": "path_pick_selected_bg",
|
||||
"value": "#1A254FF7"
|
||||
},
|
||||
{
|
||||
"name": "list_item_pressed_bg",
|
||||
"value": "#1A000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -251,6 +251,10 @@
|
||||
{
|
||||
"name": "text_input_margin_minus20",
|
||||
"value": "-20vp"
|
||||
},
|
||||
{
|
||||
"name": "common_size56",
|
||||
"value": "56vp"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -111,6 +111,10 @@
|
||||
{
|
||||
"name": "max_input_length",
|
||||
"value": "Maximum length reached"
|
||||
},
|
||||
{
|
||||
"name": "permission_storage_reason_tips",
|
||||
"value": "This is used to acquire and store photos, files, and other media content."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -111,6 +111,14 @@
|
||||
{
|
||||
"name": "max_input_length",
|
||||
"value": "Maximum length reached"
|
||||
},
|
||||
{
|
||||
"name": "save_file_has_same_file",
|
||||
"value": "Duplicate name file already exists"
|
||||
},
|
||||
{
|
||||
"name": "permission_storage_reason_tips",
|
||||
"value": "This is used to acquire and store photos, files, and other media content."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -111,6 +111,14 @@
|
||||
{
|
||||
"name": "max_input_length",
|
||||
"value": "已达到长度上限"
|
||||
},
|
||||
{
|
||||
"name": "save_file_has_same_file",
|
||||
"value": "已有重名文件"
|
||||
},
|
||||
{
|
||||
"name": "permission_storage_reason_tips",
|
||||
"value": "用于获取和存储照片、媒体内容和文件"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"hvigorVersion": "2.0.0",
|
||||
"dependencies": {
|
||||
"@ohos/hvigor-ohos-plugin": "2.0.0"
|
||||
},
|
||||
"execution": {
|
||||
// "daemon": true, /* Enable daemon compilation. Default: true */
|
||||
// "incremental": true, /* Enable incremental compilation. Default: true */
|
||||
// "parallel": true, /* Enable parallel compilation. Default: true */
|
||||
// "typeCheck": false, /* Enable typeCheck. Default: false */
|
||||
},
|
||||
"logging": {
|
||||
// "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
|
||||
},
|
||||
"debugging": {
|
||||
// "stacktrace": false /* Disable stacktrace compilation. Default: false */
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Hvigor startup script, version 1.0.0
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# NODE_HOME - location of a Node home dir
|
||||
# or
|
||||
# Add /usr/local/nodejs/bin to the PATH environment variable
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
HVIGOR_APP_HOME="`pwd -P`"
|
||||
HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js
|
||||
warn() {
|
||||
echo ""
|
||||
echo -e "\033[1;33m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo ""
|
||||
echo -e "\033[1;31m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
|
||||
}
|
||||
|
||||
fail() {
|
||||
error "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Determine node to start hvigor wrapper script
|
||||
if [ -n "${NODE_HOME}" ];then
|
||||
EXECUTABLE_NODE="${NODE_HOME}/bin/node"
|
||||
if [ ! -x "$EXECUTABLE_NODE" ];then
|
||||
fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed"
|
||||
fi
|
||||
else
|
||||
EXECUTABLE_NODE="node"
|
||||
which ${EXECUTABLE_NODE} > /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path"
|
||||
fi
|
||||
|
||||
# Check hvigor wrapper script
|
||||
if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then
|
||||
fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}"
|
||||
fi
|
||||
|
||||
# start hvigor-wrapper script
|
||||
exec "${EXECUTABLE_NODE}" \
|
||||
"${HVIGOR_WRAPPER_SCRIPT}" "$@"
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Hvigor startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js
|
||||
set NODE_EXE=node.exe
|
||||
|
||||
goto start
|
||||
|
||||
:start
|
||||
@rem Find node.exe
|
||||
if defined NODE_HOME goto findNodeFromNodeHome
|
||||
|
||||
%NODE_EXE% --version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the NODE_HOME variable in your environment to match the
|
||||
echo location of your NodeJs installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findNodeFromNodeHome
|
||||
set NODE_HOME=%NODE_HOME:"=%
|
||||
set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE%
|
||||
|
||||
if exist "%NODE_EXE_PATH%" goto execute
|
||||
echo.
|
||||
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the NODE_HOME variable in your environment to match the
|
||||
echo location of your NodeJs installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Execute hvigor
|
||||
"%NODE_EXE%" "%WRAPPER_MODULE_PATH%" %*
|
||||
|
||||
if "%ERRORLEVEL%" == "0" goto hvigorwEnd
|
||||
|
||||
:fail
|
||||
exit /b 1
|
||||
|
||||
:hvigorwEnd
|
||||
if "%OS%" == "Windows_NT" endlocal
|
||||
|
||||
:end
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@ohos/hypium": "1.0.6"
|
||||
},
|
||||
"name": "filepicker",
|
||||
"description": "example description",
|
||||
"repository": {},
|
||||
"version": "1.0.0",
|
||||
"dependencies": {}
|
||||
}
|
||||
Generated
-1232
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"license": "ISC",
|
||||
"devDependencies": {},
|
||||
"name": "filepicker",
|
||||
"ohos": {
|
||||
"org": "huawei",
|
||||
"directoryLevel": "project",
|
||||
"buildTool": "hvigor"
|
||||
},
|
||||
"description": "example description",
|
||||
"repository": {},
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@ohos/hypium": "1.0.1",
|
||||
"@ohos/hvigor-ohos-plugin": "1.1.6",
|
||||
"hypium": "^1.0.0",
|
||||
"@ohos/hvigor": "1.1.6"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user