mirror of
https://github.com/openharmony/applications_filepicker.git
synced 2026-07-01 22:33:59 -04:00
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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 enum PreferenceMode {
|
||||
FOLDER = 'FolderPreference',
|
||||
FILE_PICKER = 'FilePickerFolderPreference'
|
||||
}
|
||||
|
||||
export enum UnityStartMode {
|
||||
NORMAL,
|
||||
FILE_PICKER_OPEN_FILE,
|
||||
FILE_PICKER_OPEN_FOLDER,
|
||||
FILE_PICKER_OPEN_MIXED,
|
||||
FILE_PICKER_CREATE,
|
||||
DESKTOP_FILE_START,
|
||||
GRANT_PERMISSION
|
||||
}
|
||||
|
||||
export enum SelectMode {
|
||||
FILE,
|
||||
FOLDER,
|
||||
MIXED
|
||||
}
|
||||
|
||||
export enum PickerWindowType {
|
||||
ABILITY = 'Ability',
|
||||
SERVICE = 'ServiceExtensionAbility',
|
||||
UI = 'UIExtensionAbility'
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.
|
||||
*/
|
||||
/**
|
||||
* uri of the virtual directory
|
||||
*/
|
||||
export enum VirtualUri {
|
||||
// Quick Access
|
||||
RECENT = 'recent',
|
||||
DESKTOP = 'file://docs/storage/Users/currentUser/Desktop',
|
||||
DOWNLOAD = 'file://docs/storage/Users/currentUser/Download',
|
||||
RECYCLE_BIN = 'recycleBin',
|
||||
// Storage Location
|
||||
MY_PC = 'file://docs/storage/Users/currentUser',
|
||||
DOCUMENT = 'file://docs/storage/Users/currentUser/Documents',
|
||||
EXTERNAL_DISK = 'file://docs/storage/External',
|
||||
PCENGINE = 'file://docs/storage/Users/currentUser/PCEngine',
|
||||
// gallery
|
||||
GALLERY = 'gallery',
|
||||
// fileTag
|
||||
FILE_TAG = 'fileTag',
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2024 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 { common, Context, UIExtensionContentSession } from '@kit.AbilityKit';
|
||||
import { PickerWindowType, SelectMode, UnityStartMode } from '../constants/FilePickerItems';
|
||||
|
||||
export class StartModeOptions {
|
||||
/**************************** picker *********************************/
|
||||
/************** common *******************/
|
||||
/**
|
||||
* picker场景下,界面模式
|
||||
*/
|
||||
public windowType = PickerWindowType.ABILITY;
|
||||
|
||||
public session: UIExtensionContentSession;
|
||||
|
||||
/**
|
||||
* want对应的action
|
||||
*/
|
||||
public action: string = '';
|
||||
|
||||
/**
|
||||
* 拉起picker的应用ability名
|
||||
*/
|
||||
public callerAbilityName: string = '';
|
||||
|
||||
/**
|
||||
* 拉起picker的包名
|
||||
*/
|
||||
public callerBundleName: string = '';
|
||||
|
||||
/**
|
||||
* 选择器callerId
|
||||
*/
|
||||
public callerUid: number = 0;
|
||||
|
||||
/**
|
||||
* 拉起picker的默认文件或者指定目录
|
||||
*/
|
||||
public defaultFilePathUri: string = '';
|
||||
|
||||
/**
|
||||
* 代表拉起sysPicker/filePicker类型的ExtensionAbility
|
||||
*/
|
||||
public extType: string = '';
|
||||
|
||||
/**
|
||||
* UIExtensionContext
|
||||
*/
|
||||
public uiExtContext: common.UIExtensionContext;
|
||||
|
||||
/**
|
||||
* UIExtensionContext
|
||||
*/
|
||||
public uiContext: common.UIAbilityContext;
|
||||
|
||||
/**
|
||||
* context
|
||||
*/
|
||||
public context: Context;
|
||||
|
||||
|
||||
/**
|
||||
* 用来区分选择,保存还是下载模式
|
||||
* 当pickerType设置为downloadAuth时,用户配置的参数newFileNames、defaultFilePathUri和fileSuffixChoices将不会生效
|
||||
*/
|
||||
public pickerType: string = 'DEFAULT';
|
||||
|
||||
/************** select *******************/
|
||||
/**
|
||||
* 选择文件的后缀类型
|
||||
*/
|
||||
public fileSuffixFilters: string[] = [];
|
||||
|
||||
/**
|
||||
* 选择文件最大个数,上限500, 默认为1
|
||||
*/
|
||||
public maxSelectNumber: number = 1;
|
||||
|
||||
/**
|
||||
* 支持选择的资源类型,比如:文件、文件夹和二者混合
|
||||
*/
|
||||
public selectMode: SelectMode = SelectMode.FILE;
|
||||
|
||||
/**
|
||||
* 当为授权模式,defaultFilePathUri必填,表明待授权uri
|
||||
*/
|
||||
public isAuthMode: boolean = false;
|
||||
|
||||
/**
|
||||
* 调用方传入文件类型(兼容双框架action)
|
||||
*/
|
||||
public phonePickerType: string = '';
|
||||
|
||||
/**
|
||||
* 调用方传入文件类型列表
|
||||
*/
|
||||
public phonePickerTypeList: string[] = [];
|
||||
|
||||
|
||||
/************** save *******************/
|
||||
/**
|
||||
* 进行保存的文件名列表
|
||||
*/
|
||||
public newFileNames: string[] = [];
|
||||
|
||||
/**
|
||||
* 保存文件的后缀类型
|
||||
*/
|
||||
public fileSuffixChoices: string[] = [];
|
||||
|
||||
/**
|
||||
* 手机保存文件的后缀类型
|
||||
*/
|
||||
public PhoneFileSuffixChoices: string = '';
|
||||
|
||||
|
||||
/**************************** 主界面模式 *********************************/
|
||||
/**
|
||||
* 文管启动模式,只允许初始化过程修改一次,默认为主界面模式
|
||||
*/
|
||||
public startMode: UnityStartMode = UnityStartMode.NORMAL;
|
||||
|
||||
public getFileSuffixFilterList(): string[] {
|
||||
if (this.fileSuffixFilters.length === 0) {
|
||||
this.fileSuffixFilters.push('.*');
|
||||
}
|
||||
return this.fileSuffixFilters;
|
||||
}
|
||||
|
||||
public setSelectMode(mode: number | undefined): void {
|
||||
if (mode === undefined) {
|
||||
this.selectMode = SelectMode.FILE;
|
||||
return;
|
||||
}
|
||||
if ((mode < SelectMode.FILE) || (mode > SelectMode.MIXED)) {
|
||||
this.selectMode = SelectMode.FILE;
|
||||
return;
|
||||
}
|
||||
this.selectMode = mode;
|
||||
}
|
||||
|
||||
public setNewFileNames(names: string[] | undefined): void {
|
||||
if (names === undefined) {
|
||||
this.newFileNames = [];
|
||||
return;
|
||||
}
|
||||
if (names.length === 0) {
|
||||
this.newFileNames = [''];
|
||||
return;
|
||||
}
|
||||
this.newFileNames = names;
|
||||
}
|
||||
|
||||
public isDownloadMode(): boolean {
|
||||
return this.pickerType === 'downloadAuth';
|
||||
}
|
||||
|
||||
public isGrantPermissionMode(): boolean {
|
||||
return this.isAuthMode;
|
||||
}
|
||||
|
||||
public isSelectFolderMode(): boolean {
|
||||
return this.startMode === UnityStartMode.FILE_PICKER_OPEN_FOLDER;
|
||||
}
|
||||
|
||||
public isOpenFileMode(): boolean {
|
||||
// 新方案需要通过pickerType区分
|
||||
return this.action === 'ohos.want.action.OPEN_FILE_SERVICE' || this.action === 'ohos.want.action.OPEN_FILE';
|
||||
}
|
||||
|
||||
public isCreateFileMode(): boolean {
|
||||
// 新方案需要通过pickerType区分
|
||||
return this.action === 'ohos.want.action.CREATE_FILE_SERVICE' || this.action === 'ohos.want.action.CREATE_FILE';
|
||||
}
|
||||
|
||||
public isUxt(): boolean {
|
||||
return this.windowType === PickerWindowType.UI;
|
||||
}
|
||||
|
||||
public setUiExtContext(context: common.UIExtensionContext): void {
|
||||
this.uiExtContext = context;
|
||||
}
|
||||
}
|
||||
@@ -25,19 +25,37 @@ import { FILE_MANAGER_PREFERENCES, FILE_SUFFIX, SELECT_MODE } from '../constants
|
||||
import StringUtil from './StringUtil'
|
||||
import { ArrayUtil } from './ArrayUtil'
|
||||
import { getPreferences } from './PreferencesUtil'
|
||||
import { ability, Want } from '@kit.AbilityKit'
|
||||
import { StartModeOptions } from '../model/StartModeOptions'
|
||||
import ctx from '@ohos.app.ability.common';
|
||||
import { PickerWindowType } from '../constants/FilePickerItems'
|
||||
|
||||
const TAG = 'AbilityCommonUtil'
|
||||
|
||||
const BUNDLE_NAME = 'com.ohos.filepicker'
|
||||
let mediaLibrary: MediaLibrary.MediaLibrary = null
|
||||
|
||||
/**
|
||||
* picker对外返回的响应码
|
||||
*/
|
||||
export enum ResultCodePicker {
|
||||
SUCCESS = 0,
|
||||
CANCEL = -1
|
||||
}
|
||||
|
||||
interface abilityResultInterface {
|
||||
want: Want,
|
||||
resultCode: number
|
||||
};
|
||||
|
||||
/**
|
||||
* Ability公共工具类
|
||||
*/
|
||||
namespace AbilityCommonUtil {
|
||||
|
||||
/**
|
||||
* 需要用户授权的权限列表
|
||||
*/
|
||||
/**
|
||||
* 需要用户授权的权限列表
|
||||
*/
|
||||
export const PERMISSION_LIST: Array<Permissions> = [
|
||||
"ohos.permission.MEDIA_LOCATION",
|
||||
"ohos.permission.READ_MEDIA",
|
||||
@@ -79,6 +97,7 @@ namespace AbilityCommonUtil {
|
||||
FILE_PICKER: 'FilePickerAbility',
|
||||
PATH_PICKER: 'PathPickerAbility'
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉起Ability时必要的初始化操作
|
||||
*/
|
||||
@@ -108,7 +127,8 @@ 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+','+rootInfo.relativePath)
|
||||
Logger.i(TAG, 'RootInfo: ' + rootInfo.uri + ', ' + rootInfo.deviceType + ', ' + rootInfo.deviceFlags + ', ' +
|
||||
rootInfo.displayName + ',' + rootInfo.relativePath)
|
||||
rootInfoArr.push(rootInfo)
|
||||
result = rootIterator.next()
|
||||
isDone = result.done
|
||||
@@ -185,14 +205,14 @@ namespace AbilityCommonUtil {
|
||||
grantSuccessCount++;
|
||||
} catch (error) {
|
||||
resolve(false);
|
||||
Logger.e(TAG, `grantUriPermission fail,grantSuccessCount:${grantSuccessCount}}, 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)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,78 +221,64 @@ namespace AbilityCommonUtil {
|
||||
* @param result
|
||||
* @param message
|
||||
*/
|
||||
export async function terminateFilePicker(result: Array<string> = [], displayNames: Array<string> = [], resultCode: number = RESULT_CODE.SUCCESS, message: string = ''): Promise<void> {
|
||||
const bundleName = globalThis.pickerCallerBundleName
|
||||
if (result.length && bundleName) {
|
||||
// uri授权
|
||||
const isSuccess = await grantUriPermission(result, bundleName);
|
||||
if (!isSuccess) {
|
||||
resultCode = ErrorCodeConst.PICKER.GRANT_URI_PERMISSION_FAIL,
|
||||
result = []
|
||||
message = 'uri grant permission fail'
|
||||
displayNames = []
|
||||
export async function terminateFilePicker(result: string[] = [],
|
||||
resultCode: number = ResultCodePicker.SUCCESS, startModeOptions: StartModeOptions): Promise<void> {
|
||||
Logger.i(TAG, 'enter terminateFilePicker, result length: ' + result.length + ', resultCode:' + resultCode);
|
||||
let want: Want = {
|
||||
bundleName: BUNDLE_NAME,
|
||||
flags: wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION,
|
||||
parameters: {
|
||||
'ability.params.stream': result
|
||||
}
|
||||
}
|
||||
|
||||
let abilityResult = {
|
||||
resultCode: resultCode,
|
||||
want: {
|
||||
bundleName: globalThis.abilityContext.abilityInfo.bundleName,
|
||||
abilityName: ABILITY_LIST.FILE_PICKER,
|
||||
parameters: {
|
||||
'select_item_list': result,
|
||||
'file_name_list': displayNames,
|
||||
message: message,
|
||||
'result': result[0],
|
||||
}
|
||||
}
|
||||
}
|
||||
globalThis.abilityContext.terminateSelfWithResult(abilityResult, (error) => {
|
||||
if (error.code) {
|
||||
Logger.e(TAG, 'terminateFilePicker failed. Cause: ' + JSON.stringify(error))
|
||||
return
|
||||
}
|
||||
Logger.d(TAG, 'terminateFilePicker success. result: ' + JSON.stringify(abilityResult))
|
||||
})
|
||||
};
|
||||
returnAbilityResult(want, resultCode, startModeOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件创建完成,返回uri列表
|
||||
* @param result
|
||||
* @param resultCode
|
||||
* @param message
|
||||
*/
|
||||
export async function terminatePathPicker(result: Array<string>, resultCode: number = RESULT_CODE.SUCCESS, message: string = ''): Promise<void> {
|
||||
const bundleName = globalThis.pathCallerBundleName
|
||||
if (result.length && bundleName) {
|
||||
// uri授权
|
||||
const isSuccess = await grantUriPermission(result, bundleName);
|
||||
if (!isSuccess) {
|
||||
resultCode = ErrorCodeConst.PICKER.GRANT_URI_PERMISSION_FAIL,
|
||||
result = []
|
||||
message = 'uri grant permission fail'
|
||||
export async function terminatePathPicker(result: string[],
|
||||
resultCode: number = ResultCodePicker.SUCCESS, startModeOptions: StartModeOptions): Promise<void> {
|
||||
|
||||
Logger.i(TAG, 'enter terminatePathPicker, result length: ' + result.length + ', resultCode:' + resultCode);
|
||||
let want: Want = {
|
||||
bundleName: BUNDLE_NAME,
|
||||
abilityName: ABILITY_LIST.PATH_PICKER,
|
||||
flags: wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION,
|
||||
parameters: {
|
||||
'ability.params.stream': result,
|
||||
KEY_PICK_SELECT_CLOUD_DISK: false
|
||||
}
|
||||
};
|
||||
returnAbilityResult(want, resultCode, startModeOptions);
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function returnAbilityResult(want: Want, resultCode: number, options: StartModeOptions) {
|
||||
Logger.i(TAG, 'returnPicker start');
|
||||
if (options.windowType === PickerWindowType.ABILITY) {
|
||||
let abilityResult: abilityResultInterface = {
|
||||
want: want,
|
||||
resultCode: resultCode
|
||||
};
|
||||
Logger.i(TAG, 'uiContext terminateSelfWithResult start');
|
||||
options.uiContext.terminateSelfWithResult(abilityResult, (error) => {
|
||||
Logger.i(TAG, 'terminateSelfWithResult is called = ' + error.code);
|
||||
});
|
||||
} else {
|
||||
let abilityResult: ability.AbilityResult = {
|
||||
resultCode: resultCode,
|
||||
want: want
|
||||
};
|
||||
Logger.i(TAG, 'session terminateSelfWithResult start');
|
||||
options.session.terminateSelfWithResult(abilityResult, (error) => {
|
||||
Logger.e(TAG, 'closeUIExtFilePicker terminateSelfWithResult is called = ' + error?.code);
|
||||
});
|
||||
}
|
||||
let abilityResult = {
|
||||
resultCode: resultCode,
|
||||
want: {
|
||||
bundleName: globalThis.pathAbilityContext.abilityInfo.bundleName,
|
||||
abilityName: ABILITY_LIST.PATH_PICKER,
|
||||
parameters: {
|
||||
'pick_path_return': result,
|
||||
'key_pick_select_clouddisk': false,
|
||||
'message': message,
|
||||
// 兼容老版本picker
|
||||
'result': result[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
globalThis.pathAbilityContext.terminateSelfWithResult(abilityResult, (error) => {
|
||||
if (error.code) {
|
||||
Logger.e(TAG, 'terminatePathPicker failed. Cause: ' + JSON.stringify(error))
|
||||
return
|
||||
}
|
||||
Logger.d(TAG, 'terminatePathPicker success. result: ' + JSON.stringify(abilityResult))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,8 +299,8 @@ namespace AbilityCommonUtil {
|
||||
* @param keyPickType 调用方传入文件类型(兼容双框架action)
|
||||
* @param keyPickTypeList 调用方传入文件类型列表
|
||||
*/
|
||||
export function getKeyPickTypeList(keyPickType, keyPickTypeList): Array<string>{
|
||||
let typeList =[]
|
||||
export function getKeyPickTypeList(keyPickType, keyPickTypeList): Array<string> {
|
||||
let typeList = []
|
||||
if (keyPickType) {
|
||||
typeList.push(keyPickType)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,86 @@ import { toast } from '../../base/utils/Common';
|
||||
import { FileMimeTypeUtil } from '../../base/utils/FileMimeTypeUtil';
|
||||
import { FILE_SUFFIX, SELECT_MODE } from '../constants/Constant';
|
||||
import ObjectUtil from './ObjectUtil';
|
||||
import { ability, Want } from '@kit.AbilityKit';
|
||||
import Logger from '../log/Logger';
|
||||
import { PickerWindowType } from '../constants/FilePickerItems';
|
||||
import { StartModeOptions } from '../model/StartModeOptions';
|
||||
import AbilityCommonUtil from './AbilityCommonUtil';
|
||||
import ctx from '@ohos.app.ability.common';
|
||||
|
||||
interface abilityResultInterface {
|
||||
want: Want,
|
||||
resultCode: number
|
||||
};
|
||||
|
||||
const TAG = 'FilePickerUtil';
|
||||
|
||||
export namespace FilePickerUtil {
|
||||
export function returnAbilityResult(want: Want, resultCode: number, options: StartModeOptions) {
|
||||
Logger.i(TAG, 'returnPicker start');
|
||||
let context = getContext() as ctx.UIAbilityContext;
|
||||
if (options.windowType === PickerWindowType.ABILITY) {
|
||||
let abilityResult: abilityResultInterface = {
|
||||
want: want,
|
||||
resultCode: resultCode
|
||||
};
|
||||
Logger.i(TAG, 'terminateSelfWithResult start');
|
||||
context.terminateSelfWithResult(abilityResult, (error) => {
|
||||
Logger.e(TAG, 'terminateSelfWithResult is called = ' + error.code);
|
||||
});
|
||||
} else {
|
||||
let abilityResult: ability.AbilityResult = {
|
||||
resultCode: resultCode,
|
||||
want: want
|
||||
};
|
||||
options.session?.terminateSelfWithResult(abilityResult, (error) => {
|
||||
Logger.e(TAG, 'closeUIExtFilePicker terminateSelfWithResult is called = ' + error?.code);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getStartModeOptions(want: Want): StartModeOptions {
|
||||
let options = new StartModeOptions();
|
||||
if (!want) {
|
||||
Logger.e(TAG, 'getDocumentSelectOptions want is undefined')
|
||||
return options;
|
||||
}
|
||||
options.action = want.action as string || '';
|
||||
options.callerAbilityName = want.parameters?.['ohos.aafwk.param.callerAbilityName'] as string || '';
|
||||
options.callerBundleName = want.parameters?.['ohos.aafwk.param.callerBundleName'] as string || '';
|
||||
options.callerUid = want?.parameters?.[AbilityCommonUtil.CALLER_UID] as number || 0;
|
||||
options.defaultFilePathUri = want.parameters?.key_pick_dir_path as string || '';
|
||||
options.extType = want.parameters?.extType as string || '';
|
||||
options.pickerType = want.parameters?.pickerType as string || '';
|
||||
if (options.isOpenFileMode()) {
|
||||
options.fileSuffixFilters = want.parameters?.key_file_suffix_filter as string[] || [];
|
||||
options.maxSelectNumber = want.parameters?.key_pick_num as number || 1;
|
||||
options.setSelectMode(want.parameters?.key_select_mode as number);
|
||||
options.isAuthMode = want.parameters?.key_auth_mode as boolean || false;
|
||||
} else if (options.isCreateFileMode()) {
|
||||
options.setNewFileNames(want.parameters?.key_pick_file_name as string[]);
|
||||
options.fileSuffixChoices = want.parameters?.key_file_suffix_choices as string[] || [];
|
||||
} else {
|
||||
Logger.e(TAG, 'getDocumentSelectOptions mode is error')
|
||||
}
|
||||
Logger.i(TAG, 'getDocumentOptions : ' + JSON.stringify(options));
|
||||
return options;
|
||||
}
|
||||
|
||||
export function getStartOptionsFromStorage(): StartModeOptions {
|
||||
let storage: LocalStorage = LocalStorage.getShared();
|
||||
if (!storage) {
|
||||
Logger.i(TAG, `Storage is null`)
|
||||
return new StartModeOptions();
|
||||
}
|
||||
let options: StartModeOptions | undefined = storage.get<StartModeOptions>('startModeOptions');
|
||||
if (options === undefined) {
|
||||
options = new StartModeOptions();
|
||||
storage.setOrCreate('startModeOptions', options);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件选择器文件状态
|
||||
@@ -25,12 +105,12 @@ import ObjectUtil from './ObjectUtil';
|
||||
* @param checkedNum 选中数量
|
||||
* @return 是否超限 选择类型是否不匹配
|
||||
*/
|
||||
export function pickerStatus(item, checkedNum) {
|
||||
export function pickerStatus(item, checkedNum, startModeOptions:StartModeOptions) {
|
||||
return {
|
||||
// 选择是否超限
|
||||
exceedLimit: globalThis.filePickerViewFlag && (checkedNum >= globalThis.filePickNum && !item.isChecked),
|
||||
exceedLimit: checkedNum >= globalThis.filePickNum && !item.isChecked,
|
||||
// 选择类型是否不匹配
|
||||
differentTypes: !checkFileSelectable(item)
|
||||
differentTypes: !checkFileSelectable(item, startModeOptions)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,14 +118,9 @@ export function pickerStatus(item, checkedNum) {
|
||||
* 根据文件后缀判断文件是否可选
|
||||
* @param item
|
||||
*/
|
||||
function checkFileSelectable(item): boolean {
|
||||
// 非文件选择器场景
|
||||
if (!globalThis.filePickerViewFlag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkFileSelectable(item, startModeOptions: StartModeOptions): boolean {
|
||||
// selectMode检查
|
||||
let selectMode: number = globalThis.keySelectMode;
|
||||
let selectMode: number = startModeOptions.selectMode;
|
||||
let isFolder = false;
|
||||
if (ObjectUtil.hasKey(item, 'isFolder')) {
|
||||
isFolder = item.isFolder;
|
||||
@@ -64,13 +139,13 @@ function checkFileSelectable(item): boolean {
|
||||
return false;
|
||||
}
|
||||
// 后缀检查
|
||||
let keyFileSuffixFilter: string[] = globalThis.keyFileSuffixFilter;
|
||||
let keyFileSuffixFilter: string[] = startModeOptions.fileSuffixFilters;
|
||||
if (Array.isArray(keyFileSuffixFilter) && keyFileSuffixFilter.length > 0) {
|
||||
return checkFileSuffix(item.fileName, keyFileSuffixFilter);
|
||||
}
|
||||
|
||||
// mimeType检查
|
||||
return checkFileMimetype(item.fileName);
|
||||
return checkFileMimetype(item.fileName, startModeOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,16 +174,16 @@ function checkFileSuffix(fileName: string, keyFileSuffixFilter: Array<string>):
|
||||
* @param fileName 文件名称
|
||||
* @return 条件满足返回true
|
||||
*/
|
||||
function checkFileMimetype(fileName: string): boolean {
|
||||
function checkFileMimetype(fileName: string, startModeOptions: StartModeOptions): boolean {
|
||||
if (!fileName) {
|
||||
return false;
|
||||
}
|
||||
let keyPickTypeList: string[] = globalThis.keyPickTypeList;
|
||||
let keyPickTypeList: string[] = startModeOptions.phonePickerTypeList;
|
||||
// 输入的类型全转换成小写,避免大小敏感问题
|
||||
keyPickTypeList.forEach(item => item.toLowerCase());
|
||||
// 类型列表为空或包含*或*/*时,可选择所有文件
|
||||
if (!keyPickTypeList || keyPickTypeList.length === 0 ||
|
||||
keyPickTypeList.includes('*') || keyPickTypeList.includes('*/*')) {
|
||||
keyPickTypeList.includes('*') || keyPickTypeList.includes('*/*')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -143,8 +218,9 @@ function checkFileMimetype(fileName: string): boolean {
|
||||
*
|
||||
* @param isImmersion 是否沉浸式
|
||||
*/
|
||||
export const filePickerTip = () => {
|
||||
globalThis.abilityContext.resourceManager.getPluralString($r('app.plural.filePickerTip').id, globalThis.filePickNum)
|
||||
export const filePickerTip = (startModeOptions: StartModeOptions) => {
|
||||
globalThis.abilityContext.resourceManager.getPluralString($r('app.plural.filePickerTip').id,
|
||||
startModeOptions.maxSelectNumber)
|
||||
.then((value) => {
|
||||
toast(value)
|
||||
})
|
||||
|
||||
@@ -18,14 +18,14 @@ 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 { FILENAME_MAX_LENGTH, RENAME_CONNECT_CHARACTER } from '../constants/Constant';
|
||||
import MediaLibrary from '@ohos.multimedia.mediaLibrary';
|
||||
import fs from '@ohos.file.fs';
|
||||
import FileUri from '@ohos.file.fileuri';
|
||||
|
||||
const TAG = 'FileUtil';
|
||||
|
||||
export class FileUtil {
|
||||
|
||||
/**
|
||||
* uri 格式开头
|
||||
*/
|
||||
@@ -68,7 +68,8 @@ export class FileUtil {
|
||||
* @param fileAccessHelper fileAccess.FileAccessHelper
|
||||
* @returns fileAccess.FileInfo
|
||||
*/
|
||||
public static async getFileInfoByUri(uri: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
|
||||
public static async getFileInfoByUri(uri: string,
|
||||
fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
|
||||
try {
|
||||
return await fileAccessHelper.getFileInfoFromUri(uri);
|
||||
} catch (err) {
|
||||
@@ -83,7 +84,8 @@ export class FileUtil {
|
||||
* @param fileAccessHelper fileAccess.FileAccessHelper
|
||||
* @returns fileAccess.FileInfo
|
||||
*/
|
||||
public static async getFileInfoByRelativePath(relativePath: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
|
||||
public static async getFileInfoByRelativePath(relativePath: string,
|
||||
fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
|
||||
try {
|
||||
return await fileAccessHelper.getFileInfoFromRelativePath(relativePath);
|
||||
} catch (err) {
|
||||
@@ -98,7 +100,8 @@ export class FileUtil {
|
||||
* @param fileAccessHelper
|
||||
* @returns FileIterator
|
||||
*/
|
||||
public static async getFileIteratorByUri(uri: string, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileIterator> {
|
||||
public static async getFileIteratorByUri(uri: string,
|
||||
fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileIterator> {
|
||||
try {
|
||||
let fileInfo = await fileAccessHelper.getFileInfoFromUri(uri);
|
||||
return fileInfo.listFile();
|
||||
@@ -167,7 +170,8 @@ export class FileUtil {
|
||||
* @param fileName 文件名
|
||||
* return 结果
|
||||
*/
|
||||
public static async getFileFromFolder(foldrUri: string, fileName, fileAccessHelper: fileAccess.FileAccessHelper): Promise<fileAccess.FileInfo> {
|
||||
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)) {
|
||||
@@ -193,7 +197,11 @@ export class FileUtil {
|
||||
return "";
|
||||
}
|
||||
|
||||
public static async createFolder(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string, name: string): Promise<{code, uri}> {
|
||||
public static async createFolder(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string,
|
||||
name: string): Promise<{
|
||||
code,
|
||||
uri
|
||||
}> {
|
||||
let uri: string = '';
|
||||
let code: any;
|
||||
try {
|
||||
@@ -202,7 +210,7 @@ export class FileUtil {
|
||||
code = error.code;
|
||||
Logger.e(TAG, 'createFolder error occurred:' + error.code + ', ' + error.message);
|
||||
}
|
||||
return {code: code, uri: uri};
|
||||
return { code: code, uri: uri };
|
||||
}
|
||||
|
||||
public static async hardDelete(uri: string, mediaLibrary: MediaLibrary.MediaLibrary): Promise<boolean> {
|
||||
@@ -225,19 +233,26 @@ export class FileUtil {
|
||||
* @param newName newName
|
||||
* @returns {err, uri}
|
||||
*/
|
||||
public static async rename(fileAccessHelper: fileAccess.FileAccessHelper, oldUri: string, newName: string): Promise<{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};
|
||||
err = { code: error.code, message: error.message };
|
||||
Logger.e(TAG, 'rename error occurred:' + error.code + ', ' + error.message);
|
||||
}
|
||||
return {err: err, uri: uri};
|
||||
return { err: err, uri: uri };
|
||||
}
|
||||
|
||||
public static async createFile(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string, fileName: string): Promise<{err, uri}> {
|
||||
public static async createFile(fileAccessHelper: fileAccess.FileAccessHelper, parentUri: string,
|
||||
fileName: string): Promise<{
|
||||
err,
|
||||
uri
|
||||
}> {
|
||||
let retUri: string = '';
|
||||
let err: any;
|
||||
try {
|
||||
@@ -245,9 +260,9 @@ export class FileUtil {
|
||||
retUri = await fileAccessHelper.createFile(parentUri, fileName);
|
||||
} catch (e) {
|
||||
Logger.e(TAG, 'createFile error: ' + e.code + ', ' + e.message);
|
||||
err = {code: e.code, message: e.message};
|
||||
err = { code: e.code, message: e.message };
|
||||
}
|
||||
return {err: err, uri: retUri};
|
||||
return { err: err, uri: retUri };
|
||||
}
|
||||
|
||||
public static hasSubFolder(loadPath: string, curFolderPath: string): boolean {
|
||||
@@ -338,4 +353,65 @@ export class FileUtil {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件的沙箱路径获取文件uri
|
||||
* @param path 文件的沙箱路径
|
||||
* @returns 文件的uri
|
||||
*/
|
||||
public static getUriFromPath(path: string): string {
|
||||
let uri = '';
|
||||
try {
|
||||
// 该接口如果以’/'结尾,返回的uri会以‘/'结尾
|
||||
uri = FileUri.getUriFromPath(path);
|
||||
} catch (error) {
|
||||
Logger.e(TAG, 'getUriFromPath fail, error:' + JSON.stringify(error));
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件uri转换成FileUri对象
|
||||
*/
|
||||
public static getFileUriObjectFromUri(uri: string): FileUri.FileUri | undefined {
|
||||
let fileUriObject: FileUri.FileUri | undefined;
|
||||
try {
|
||||
fileUriObject = new FileUri.FileUri(uri);
|
||||
} catch (error) {
|
||||
Logger.e(TAG, 'getFileUriObjectFromUri fail, error:' + JSON.stringify(error));
|
||||
}
|
||||
return fileUriObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过将文件uri转换成FileUri对象获取文件的沙箱路径
|
||||
* @param uri 文件uri
|
||||
* @returns 文件的沙箱路径
|
||||
*/
|
||||
public static getPathFromUri(uri: string): string {
|
||||
let path = '';
|
||||
const fileUriObj = FileUtil.getFileUriObjectFromUri(uri);
|
||||
if (!!fileUriObj) {
|
||||
path = fileUriObj.path;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文件夹
|
||||
* @param parentFolderUri 父目录uri
|
||||
* @param newFolderName 新文件夹名
|
||||
* @returns 新文件夹uri
|
||||
*/
|
||||
public static createFolderByFs(parentFolderUri: string, newFolderName: string): string {
|
||||
try {
|
||||
const parentFolderPath = FileUtil.getPathFromUri(parentFolderUri);
|
||||
const newFolderPath = parentFolderPath + '/' + newFolderName;
|
||||
fs.mkdirSync(newFolderPath);
|
||||
return FileUtil.getUriFromPath(newFolderPath);
|
||||
} catch (error) {
|
||||
Logger.e(TAG, 'createFolderByFs fail, error:' + JSON.stringify(error));
|
||||
throw error as Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2024 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 type { BusinessError } from '@ohos.base';
|
||||
import fs from '@ohos.file.fs';
|
||||
import fileuri from '@ohos.file.fileuri';
|
||||
import type uri from '@ohos.uri';
|
||||
import Logger from '../log/Logger';
|
||||
|
||||
export class FsUtil {
|
||||
static readonly TAG: string = 'FsUtil';
|
||||
|
||||
public static async stat(file: string | number): Promise<fs.Stat | BusinessError> {
|
||||
try {
|
||||
return await fs.stat(file);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs stat error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static statSync(file: string | number): fs.Stat | BusinessError {
|
||||
try {
|
||||
return fs.statSync(file);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs statSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static async access(path: string): Promise<boolean | BusinessError> {
|
||||
try {
|
||||
return await fs.access(path);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs access error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static accessSync(path: string): boolean {
|
||||
try {
|
||||
return fs.accessSync(path);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs accessSync error = ' + JSON.stringify(error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static openSync(path: string, mode?: number): fs.File | BusinessError {
|
||||
try {
|
||||
return fs.openSync(path, mode);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs openSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static async close(file: number | fs.File): Promise<void | BusinessError> {
|
||||
try {
|
||||
return await fs.close(file);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs close error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static closeSync(file: number | fs.File): void | BusinessError {
|
||||
try {
|
||||
return fs.closeSync(file);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs closeSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static async mkdir(path: string, recursion: boolean = false): Promise<void | BusinessError> {
|
||||
try {
|
||||
return await fs.mkdir(path, recursion);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs mkdir error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static mkdirSync(path: string, recursion: boolean = false): void | BusinessError {
|
||||
try {
|
||||
return fs.mkdirSync(path, recursion);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs mkdirSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static async rmdir(path: string): Promise<void | BusinessError> {
|
||||
try {
|
||||
return await fs.rmdir(path);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs rmdir error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static rmdirSync(path: string): void | BusinessError {
|
||||
try {
|
||||
return fs.rmdirSync(path);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs rmdirSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static async moveFile(src: string, dest: string, mode?: number): Promise<void | BusinessError> {
|
||||
try {
|
||||
return await fs.moveFile(src, dest, mode);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs moveFile error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static async moveDir(src: string, dest: string, mode?: number): Promise<void | BusinessError> {
|
||||
try {
|
||||
return await fs.moveDir(src, dest, mode);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs moveDir error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static moveFileSync(src: string, dest: string, mode?: number): void | BusinessError {
|
||||
try {
|
||||
return fs.moveFileSync(src, dest, mode);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs moveFileSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static moveDirSync(src: string, dest: string, mode?: number): void | BusinessError {
|
||||
try {
|
||||
return fs.moveDirSync(src, dest, mode);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs moveDirSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static async rename(oldPath: string, newPath: string): Promise<void | BusinessError> {
|
||||
try {
|
||||
return await fs.rename(oldPath, newPath);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs rename error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static renameSync(oldPath: string, newPath: string): void | BusinessError {
|
||||
try {
|
||||
return fs.renameSync(oldPath, newPath);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs renameSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static async unlink(path: string): Promise<void | BusinessError> {
|
||||
try {
|
||||
return await fs.unlink(path);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs unlink error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static unlinkSync(path: string): void | BusinessError {
|
||||
try {
|
||||
return fs.unlinkSync(path);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs unlinkSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
public static async write(fd: number, buffer: ArrayBuffer | string, options?: fs.WriteOptions): Promise<number | BusinessError> {
|
||||
try {
|
||||
return await fs.write(fd, buffer, options);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs write error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
public static writeSync(fd: number, buffer: ArrayBuffer | string, options?: fs.WriteOptions): number | BusinessError {
|
||||
try {
|
||||
return fs.writeSync(fd, buffer, options);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs writeSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
public static async read(fd: number, buffer: ArrayBuffer, options?: fs.ReadOptions): Promise<number | BusinessError> {
|
||||
try {
|
||||
return await fs.read(fd, buffer, options);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs read error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
public static readSync(fd: number, buffer: ArrayBuffer, options?: fs.ReadOptions): number | BusinessError {
|
||||
try {
|
||||
return fs.readSync(fd, buffer, options);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs readSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static readTextSync(path: string): string | BusinessError {
|
||||
try {
|
||||
return fs.readTextSync(path);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, `fs readTextSync error = ${JSON.stringify(error)}`);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
public static listFileSync(path: string, options?: fs.ListFileOptions): string[] | BusinessError {
|
||||
try {
|
||||
let res = fs.listFileSync(path, options);
|
||||
return res;
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs listFileSync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static async fsync(fd: number): Promise<void | BusinessError> {
|
||||
try {
|
||||
return await fs.fsync(fd);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs fsync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static fsyncSync(fd: number): void | BusinessError {
|
||||
try {
|
||||
return fs.fsyncSync(fd);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs fsync error = ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制删除文件
|
||||
* @param uri 删除文件的uri
|
||||
*/
|
||||
public static forceDelete(uri: string): number | BusinessError {
|
||||
try {
|
||||
let fileUri: fileuri.FileUri = new fileuri.FileUri(uri);
|
||||
let filePath: string = fileUri.path;
|
||||
if (fs.statSync(filePath).isDirectory()) {
|
||||
fs.rmdirSync(filePath);
|
||||
} else {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
return 0;
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'force delete file error: ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件夹判空
|
||||
* @param path 文件夹的uri
|
||||
*/
|
||||
public static isFolderEmpty(path: string): boolean | BusinessError {
|
||||
try {
|
||||
let fileList = fs.listFileSync(path, { listNum: 1 });
|
||||
return fileList.length === 0;
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'isFolderEmpty error: ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 判断文件是否为文件夹(目前暂不支持应用沙箱目录)
|
||||
* @param path 文件
|
||||
* @returns
|
||||
*/
|
||||
public static isFolder(path: string): boolean | BusinessError {
|
||||
try {
|
||||
let stat = fs.statSync(path);
|
||||
return stat?.isDirectory();
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, path + ' isFolder error: ' + JSON.stringify(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否存在
|
||||
* @param uri 文件uri
|
||||
* @returns 判断结果
|
||||
*/
|
||||
public static isFileExist(uri: string): boolean {
|
||||
let isExist: boolean = false;
|
||||
try {
|
||||
Logger.i(FsUtil.TAG, 'open start');
|
||||
let fileFd: fs.File = fs.openSync(uri, fs.OpenMode.READ_ONLY);
|
||||
fs.closeSync(fileFd);
|
||||
isExist = true;
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'openSync fail: ' + JSON.stringify(error));
|
||||
}
|
||||
return isExist;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否被删除(包括软删除和硬删除)
|
||||
* @param uri 文件uri
|
||||
* @returns 判断结果
|
||||
*/
|
||||
public static isFileDeleted(uri: string): boolean {
|
||||
try {
|
||||
Logger.i(FsUtil.TAG, 'open start');
|
||||
let fileFd: fs.File = fs.openSync(uri, fs.OpenMode.READ_ONLY); // 此处报错说明被硬删除了
|
||||
const path = fileFd.path;
|
||||
fs.closeSync(fileFd);
|
||||
let stat = fs.statSync(path);
|
||||
if (stat.ctime === 0 && stat.mtime === 0) { // 说明被软删除了
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'openSync fail: ' + JSON.stringify(error));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断目录下是否存在同名文件
|
||||
* @param destUri:目录uri
|
||||
* @param fileName:待判断的文件名
|
||||
* @returns 判断结果
|
||||
*/
|
||||
public static isExistDupName(destUri: string, fileName: string): boolean {
|
||||
let isExistDupName: boolean = false;
|
||||
try {
|
||||
let destFileInfo: uri.URI = new fileuri.FileUri(destUri);
|
||||
let newFilePath: string = destFileInfo.path + '/' + fileName;
|
||||
isExistDupName = fs.accessSync(newFilePath);
|
||||
} catch (err) {
|
||||
Logger.i(FsUtil.TAG, 'isExistDupName err: ' + JSON.stringify(err));
|
||||
}
|
||||
return isExistDupName;
|
||||
}
|
||||
|
||||
public static getInoByUri(uri: string): string {
|
||||
try {
|
||||
let fileUri: fileuri.FileUri = new fileuri.FileUri(uri);
|
||||
let stat = fs.statSync(fileUri.path);
|
||||
return stat.ino.toString();
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, `get ino failed, error message : ${error?.message}, error code : ${error?.code}`);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件拷贝同步接口,适合十几兆的小文件拷贝
|
||||
* @param srcPath 源文件
|
||||
* @param destinationPath 目标文件
|
||||
* @param mode 拷贝模式
|
||||
* @returns true:拷贝成功,目标文件已经存在
|
||||
*/
|
||||
public static copyFileSyncByPath(srcPath: string, destinationPath: string, mode?: number): boolean {
|
||||
try {
|
||||
fs.copyFileSync(srcPath, destinationPath, mode);
|
||||
return FsUtil.isExistSyncByPath(destinationPath);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'copyFileSyncByPath err: ' + JSON.stringify(error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否存在
|
||||
*
|
||||
* @param path 文件全目录
|
||||
* @returns true:文件存在
|
||||
*/
|
||||
public static isExistSyncByPath(path: string): boolean {
|
||||
try {
|
||||
return fs.accessSync(path);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'isExistSyncByPath error = ' + JSON.stringify(error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重命名异步接口
|
||||
* @param oldPath 即将要重命名的文件全路径
|
||||
* @param newPath 重命名之后的文件全路径
|
||||
* @returns true:命名成功
|
||||
*/
|
||||
public static renameSyncByPath(oldPath: string, newPath: string): boolean {
|
||||
try {
|
||||
fs.renameSync(oldPath, newPath);
|
||||
return FsUtil.isExistSyncByPath(newPath);
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'fs renameSync error = ' + JSON.stringify(error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步获取文件大小
|
||||
* @param path 文件全路径
|
||||
* @returns 文件夹大小
|
||||
*/
|
||||
public static getFileSizeSyncByPath(path: string): number {
|
||||
let size = 0;
|
||||
try {
|
||||
let stat = fs.statSync(path);
|
||||
size = stat.size;
|
||||
} catch (error) {
|
||||
Logger.i(FsUtil.TAG, 'getFileInfoByFs fail, error:' + JSON.stringify(error));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,8 @@ import { MimeType } from './MimeType';
|
||||
import { THUMBNAIL_SIZE } from '../../base/constants/UiConstant';
|
||||
import { BasicDataSource } from './BasicDataSource';
|
||||
import Logger from '../../base/log/Logger';
|
||||
import AbilityCommonUtil from '../../base/utils/AbilityCommonUtil';
|
||||
import AbilityCommonUtil, { ResultCodePicker } from '../../base/utils/AbilityCommonUtil';
|
||||
import { StartModeOptions } from '../../base/model/StartModeOptions';
|
||||
|
||||
const TAG = 'FileAssetModel';
|
||||
|
||||
@@ -175,8 +176,8 @@ export class FileAssetModel {
|
||||
}
|
||||
}
|
||||
|
||||
pickFile(): void {
|
||||
AbilityCommonUtil.terminateFilePicker([this.uri], [this.fileName]);
|
||||
pickFile(startModeOptions: StartModeOptions): void {
|
||||
AbilityCommonUtil.terminateFilePicker([this.uri], ResultCodePicker.SUCCESS, startModeOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,10 @@ import fileAccess from '@ohos.file.fileAccess';
|
||||
import { THUMBNAIL_SIZE } from '../../base/constants/UiConstant';
|
||||
import { MimeType } from './MimeType';
|
||||
import { BasicDataSource } from './BasicDataSource';
|
||||
import AbilityCommonUtil from '../../base/utils/AbilityCommonUtil';
|
||||
import AbilityCommonUtil, { ResultCodePicker } from '../../base/utils/AbilityCommonUtil';
|
||||
import { FileUtil } from '../../base/utils/FileUtil';
|
||||
import { ArrayUtil } from '../../base/utils/ArrayUtil';
|
||||
import { StartModeOptions } from '../../base/model/StartModeOptions';
|
||||
|
||||
export class BreadData {
|
||||
public title: string;
|
||||
@@ -187,8 +188,8 @@ export class FilesData {
|
||||
}
|
||||
}
|
||||
|
||||
pickFile(): void {
|
||||
AbilityCommonUtil.terminateFilePicker([this.uri], [this.fileName]);
|
||||
pickFile(startModeOptions: StartModeOptions): void {
|
||||
AbilityCommonUtil.terminateFilePicker([this.uri], ResultCodePicker.SUCCESS, startModeOptions);
|
||||
}
|
||||
|
||||
setSubFolderList(subFolderList: FilesData[]) {
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
|
||||
*/
|
||||
|
||||
import UIExtensionAbility from '@ohos.app.ability.UIExtensionAbility';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import type Want from '@ohos.app.ability.Want';
|
||||
import dataPreferences from '@ohos.data.preferences';
|
||||
import Logger from '../base/log/Logger';
|
||||
import { StartModeOptions } from '../base/model/StartModeOptions';
|
||||
import { PickerWindowType } from '../base/constants/FilePickerItems';
|
||||
import { UIExtensionContentSession } from '@kit.AbilityKit';
|
||||
import AbilityCommonUtil from '../base/utils/AbilityCommonUtil';
|
||||
import { FilePickerUtil } from '../base/utils/FilePickerUtil';
|
||||
import bundleResourceManager from '@ohos.bundle.bundleResourceManager';
|
||||
|
||||
const TRANSPARENT_COLOR = '#00000000';
|
||||
|
||||
const TAG: string = 'FilePickerUIExtAbility';
|
||||
|
||||
export default class FilePickerUIExtAbility extends UIExtensionAbility {
|
||||
private abilityKey: string = '';
|
||||
private securityPreferences?: dataPreferences.Preferences;
|
||||
private storage: LocalStorage = new LocalStorage();
|
||||
|
||||
onCreate(): void {
|
||||
Logger.i(TAG, 'FilePickerUIExtAbility onCreate');
|
||||
}
|
||||
|
||||
async onSessionCreate(want: Want, session: UIExtensionContentSession): Promise<void> {
|
||||
Logger.i(TAG, 'FilePickerUIExtAbility onSessionCreate, want: ' + JSON.stringify(want));
|
||||
globalThis.abilityContext = this.context;
|
||||
let options = this.initParam(want, session);
|
||||
this.getAppResourceInfo(options.callerBundleName, this.storage);
|
||||
if (options.isDownloadMode()) {
|
||||
this.initSessionDownloadAuth(session);
|
||||
return;
|
||||
}
|
||||
|
||||
this.abilityKey = `${TAG}+${Date.now()}`;
|
||||
if (options.isOpenFileMode()) {
|
||||
this.initSessionFilePicker(session);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.isCreateFileMode()) {
|
||||
this.initSessionPathPicker(session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
onSessionDestroy(session: UIExtensionContentSession): void {
|
||||
Logger.i(TAG, 'FilePickerUIExtAbility onSessionDestroy');
|
||||
}
|
||||
|
||||
onDestroy(): void {
|
||||
Logger.i(TAG, 'FilePickerUIExtAbility onDestroy');
|
||||
}
|
||||
|
||||
private getAppResourceInfo(bundleName: string, storage: LocalStorage): void {
|
||||
Logger.i(TAG, `getAppResourceInfo start`)
|
||||
const bundleFlags = bundleResourceManager.ResourceFlag.GET_RESOURCE_INFO_ALL;
|
||||
try {
|
||||
const resourceInfo = bundleResourceManager.getBundleResourceInfo(bundleName, bundleFlags);
|
||||
storage.setOrCreate<string>('appName', resourceInfo.label);
|
||||
storage.setOrCreate<string>('appIcon', resourceInfo.icon);
|
||||
} catch (err) {
|
||||
const message = (err as BusinessError).message;
|
||||
Logger.e(TAG, 'getBundleResourceInfo failed: %{public}s' + message);
|
||||
}
|
||||
}
|
||||
|
||||
initParam(want: Want, session: UIExtensionContentSession): StartModeOptions {
|
||||
let options: StartModeOptions = FilePickerUtil.getStartModeOptions(want);
|
||||
options.windowType = PickerWindowType.UI;
|
||||
options.setUiExtContext(this.context);
|
||||
options.context = this.context;
|
||||
options.session = session;
|
||||
options.fileSuffixFilters = AbilityCommonUtil.getKeyFileSuffixFilter(options.fileSuffixFilters);
|
||||
if (options.isOpenFileMode()) {
|
||||
options.fileSuffixFilters = AbilityCommonUtil.getKeyFileSuffixFilter(options.fileSuffixFilters);
|
||||
options.phonePickerType = (want.parameters?.key_pick_type as string) || '';
|
||||
options.phonePickerTypeList = AbilityCommonUtil.getKeyPickTypeList(want.parameters?.key_picker_type as object,
|
||||
want.parameters?.key_picker_type_list as object)
|
||||
}
|
||||
if (options.isCreateFileMode()) {
|
||||
options.PhoneFileSuffixChoices = AbilityCommonUtil.getKeyFileSuffixChoices(options.fileSuffixChoices);
|
||||
}
|
||||
this.storage.setOrCreate<StartModeOptions>('startModeOptions', options);
|
||||
return options;
|
||||
}
|
||||
|
||||
private initSessionDownloadAuth(session: UIExtensionContentSession) {
|
||||
Logger.i(TAG, `initSessionDownloadAuth start`)
|
||||
session.loadContent('pages/DownloadAuth', this.storage);
|
||||
session.setWindowBackgroundColor(TRANSPARENT_COLOR);
|
||||
}
|
||||
|
||||
private initSessionFilePicker(session: UIExtensionContentSession) {
|
||||
Logger.i(TAG, `initSessionFilePicker start`)
|
||||
try {
|
||||
const promise = dataPreferences.getPreferences(this.context, 'securityWarning');
|
||||
promise.then(async (object) => {
|
||||
this.securityPreferences = object;
|
||||
Logger.i(TAG, 'Succeeded in getting preferences.');
|
||||
const hasSecurityWarning = this.securityPreferences.hasSync('securityWarning');
|
||||
if (!hasSecurityWarning) {
|
||||
await this.securityPreferences.put('securityWarning', '1');
|
||||
await this.securityPreferences.flush();
|
||||
this.storage?.setOrCreate('securityWarning', '1');
|
||||
Logger.i(TAG, 'dataPreferences.flush');
|
||||
}
|
||||
}).catch((err: BusinessError) => {
|
||||
console.error('Failed to get preferences. code =' + err.code + ', message =' + err.message);
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('Failed to get preferences. code =' + err.code + ', message =' + err.message);
|
||||
}
|
||||
AbilityCommonUtil.init().then(() => {
|
||||
session.loadContent('pages/browser/storage/MyPhone', this.storage);
|
||||
session.setWindowBackgroundColor(TRANSPARENT_COLOR);
|
||||
});
|
||||
}
|
||||
|
||||
private initSessionPathPicker(session: UIExtensionContentSession) {
|
||||
Logger.i(TAG, `initSessionPathPicker start`)
|
||||
AbilityCommonUtil.init().then(() => {
|
||||
session.loadContent('pages/PathPicker', this.storage);
|
||||
session.setWindowBackgroundColor(TRANSPARENT_COLOR);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 UIAbility from '@ohos.app.ability.UIAbility'
|
||||
import window from '@ohos.window'
|
||||
import AbilityCommonUtil from '../base/utils/AbilityCommonUtil'
|
||||
import Logger from '../base/log/Logger'
|
||||
import { FilePickerUtil } from '../base/utils/FilePickerUtil'
|
||||
import { StartModeOptions } from '../base/model/StartModeOptions'
|
||||
import { PickerWindowType } from '../base/constants/FilePickerItems'
|
||||
import Want from '@ohos.app.ability.Want'
|
||||
import { AbilityConstant } from '@kit.AbilityKit'
|
||||
|
||||
const TAG = 'MainAbility'
|
||||
|
||||
export default class MainAbility extends UIAbility {
|
||||
private storage: LocalStorage = new LocalStorage();
|
||||
private startModeOptions?: StartModeOptions;
|
||||
|
||||
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
|
||||
Logger.i(TAG, 'onCreate')
|
||||
globalThis.abilityContext = this.context;
|
||||
let options: StartModeOptions = FilePickerUtil.getStartModeOptions(want);
|
||||
options.windowType = PickerWindowType.ABILITY;
|
||||
options.uiContext = this.context;
|
||||
options.context = this.context;
|
||||
options.fileSuffixFilters = AbilityCommonUtil.getKeyFileSuffixFilter(options.fileSuffixFilters);
|
||||
if (options.isOpenFileMode()) {
|
||||
options.fileSuffixFilters = AbilityCommonUtil.getKeyFileSuffixFilter(options.fileSuffixFilters);
|
||||
options.phonePickerType = (want.parameters?.key_pick_type as string) || '';
|
||||
options.phonePickerTypeList = AbilityCommonUtil.getKeyPickTypeList(want.parameters?.key_picker_type as object,
|
||||
want.parameters?.key_picker_type_list as object)
|
||||
}
|
||||
if (options.isCreateFileMode()) {
|
||||
options.PhoneFileSuffixChoices = AbilityCommonUtil.getKeyFileSuffixChoices(options.fileSuffixChoices);
|
||||
}
|
||||
this.startModeOptions = options;
|
||||
this.storage.setOrCreate<StartModeOptions>('startModeOptions', options);
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
Logger.i(TAG, 'onDestroy')
|
||||
AbilityCommonUtil.releaseMediaLibrary()
|
||||
}
|
||||
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
// Main window is created, set main page for this ability
|
||||
Logger.i(TAG, 'onWindowStageCreate')
|
||||
AbilityCommonUtil.init().then(() => {
|
||||
globalThis.windowClass = windowStage.getMainWindowSync();
|
||||
if (this.startModeOptions?.isOpenFileMode()) {
|
||||
// 文件选择器
|
||||
windowStage.loadContent('pages/browser/storage/MyPhone', this.storage, (err, data) => {
|
||||
if (err.code) {
|
||||
Logger.e(TAG, 'Failed to load the content: ' + JSON.stringify(err));
|
||||
return
|
||||
}
|
||||
Logger.i(TAG, 'data: ' + JSON.stringify(data));
|
||||
})
|
||||
} else {
|
||||
// 路径选择器
|
||||
windowStage.loadContent('pages/PathPicker', this.storage, (err, data) => {
|
||||
if (err.code) {
|
||||
Logger.e(TAG, 'Failed to load the content. Cause: ' + JSON.stringify(err))
|
||||
return;
|
||||
}
|
||||
Logger.i(TAG, 'Succeeded in loading the content. Data: ' + JSON.stringify(data))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
onWindowStageDestroy() {
|
||||
// Main window is destroyed, release UI related resources
|
||||
Logger.i(TAG, 'onWindowStageDestroy')
|
||||
}
|
||||
|
||||
onForeground() {
|
||||
// Ability has brought to foreground
|
||||
Logger.i(TAG, 'onForeground')
|
||||
}
|
||||
|
||||
onBackground() {
|
||||
// Ability has back to background
|
||||
Logger.i(TAG, 'onBackground')
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* 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 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'));
|
||||
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.filePickNum = AbilityCommonUtil.getPickFileNum(parameters.key_pick_num);
|
||||
// 文件选择范围:0-本地 1-云盘 不传则默认展示全部路径(未实现)
|
||||
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
|
||||
// 保存文件时的文件名列表
|
||||
globalThis.keyPickFileName = parameters.key_pick_file_name || globalThis.saveFile || []
|
||||
// 保存位置,[本地、云盘](未实现)
|
||||
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))
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
Logger.i(TAG, 'onDestroy')
|
||||
AbilityCommonUtil.releaseMediaLibrary()
|
||||
}
|
||||
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
// Main window is created, set main page for this ability
|
||||
Logger.i(TAG, 'onWindowStageCreate')
|
||||
AbilityCommonUtil.init().then(() => {
|
||||
globalThis.windowClass = windowStage.getMainWindowSync();
|
||||
if (globalThis.action == 'ohos.want.action.OPEN_FILE' || globalThis.startMode == 'choose') {
|
||||
// 文件选择器
|
||||
windowStage.loadContent('pages/browser/storage/MyPhone', (err, data) => {
|
||||
if (err.code) {
|
||||
Logger.e(TAG, 'Failed to load the content: ' + JSON.stringify(err));
|
||||
return
|
||||
}
|
||||
Logger.i(TAG, 'data: ' + JSON.stringify(data));
|
||||
})
|
||||
} else {
|
||||
// 路径选择器
|
||||
windowStage.loadContent('pages/PathPicker', (err, data) => {
|
||||
if (err.code) {
|
||||
Logger.e(TAG, 'Failed to load the content. Cause: ' + JSON.stringify(err))
|
||||
return;
|
||||
}
|
||||
Logger.i(TAG, 'Succeeded in loading the content. Data: ' + JSON.stringify(data))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
onWindowStageDestroy() {
|
||||
// Main window is destroyed, release UI related resources
|
||||
Logger.i(TAG, 'onWindowStageDestroy')
|
||||
}
|
||||
|
||||
onForeground() {
|
||||
// Ability has brought to foreground
|
||||
Logger.i(TAG, 'onForeground')
|
||||
}
|
||||
|
||||
onBackground() {
|
||||
// Ability has back to background
|
||||
Logger.i(TAG, 'onBackground')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
|
||||
*/
|
||||
import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession';
|
||||
import { ability, wantConstant } from '@kit.AbilityKit';
|
||||
import bundleManager from '@ohos.bundle.bundleManager';
|
||||
import { DownloadDialog } from './component/dialog/DownloadDialog';
|
||||
import { StartModeOptions } from '../base/model/StartModeOptions';
|
||||
import { FilePickerUtil } from '../base/utils/FilePickerUtil';
|
||||
import Logger from '../base/log/Logger';
|
||||
import { VirtualUri } from '../base/constants/FolderRecord';
|
||||
import { FsUtil } from '../base/utils/FsUtil';
|
||||
import { FileUtil } from '../base/utils/FileUtil';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import uriPermissionManager from '@ohos.application.uriPermissionManager';
|
||||
import AbilityCommonUtil from '../base/utils/AbilityCommonUtil';
|
||||
|
||||
|
||||
const TAG = 'DownloadAuth';
|
||||
const DOWNLOAD_PATH = '/storage/Users/currentUser/Download';
|
||||
let storage = LocalStorage.getShared();
|
||||
|
||||
@Component
|
||||
@Entry(storage)
|
||||
struct DownloadAuth {
|
||||
private downloadNewUri: string = '';
|
||||
private startModeOptions: StartModeOptions = FilePickerUtil.getStartOptionsFromStorage();
|
||||
private session: UIExtensionContentSession = this.startModeOptions.session;
|
||||
// 存储当前从bms查询到的所有应用的bundle信息
|
||||
public bundleArray: Array<bundleManager.BundleInfo> = [];
|
||||
private appName: string | undefined = storage.get<string>('appName');
|
||||
private appIcon: string | undefined = storage.get<string>('appIcon');
|
||||
private confirm: Function = () => {
|
||||
};
|
||||
// 弹窗关联取消
|
||||
private cancel: Function = () => {
|
||||
};
|
||||
|
||||
aboutToAppear(): void {
|
||||
Logger.i(TAG, 'DownloadAuth aboutToAppear');
|
||||
}
|
||||
|
||||
onPageShow() {
|
||||
Logger.i(TAG, 'DownloadAuth onPageShow appName: ' + this.appName + ', appIcon: ' + this.appIcon);
|
||||
this.downloadDialogOpen();
|
||||
}
|
||||
|
||||
downloadDialogOpen(): void {
|
||||
this.confirm = async () => {
|
||||
this.downloadDialogConfirm();
|
||||
this.externalDownloadDialog.close();
|
||||
};
|
||||
this.cancel = () => {
|
||||
this.externalDownloadDialog.close();
|
||||
if (this.session != undefined) {
|
||||
this.session.terminateSelf();
|
||||
}
|
||||
};
|
||||
this.externalDownloadDialog.open();
|
||||
}
|
||||
|
||||
async downloadDialogConfirm(): Promise<void> {
|
||||
const bundleName: string = this.startModeOptions.callerBundleName;
|
||||
Logger.i(TAG, 'Download Dialog confirm.');
|
||||
this.downloadNewUri = VirtualUri.DOWNLOAD + '/' + bundleName;
|
||||
let isExist: boolean = FsUtil.accessSync(DOWNLOAD_PATH + '/' + bundleName);
|
||||
if (!isExist) {
|
||||
this.downloadNewUri = FileUtil.createFolderByFs(VirtualUri.DOWNLOAD, bundleName);
|
||||
}
|
||||
Logger.i(TAG, 'Download Dialog return uri is: ' + this.downloadNewUri);
|
||||
AbilityCommonUtil.grantUriPermission([this.downloadNewUri], bundleName);
|
||||
this.externalDownloadDialog.close();
|
||||
if (this.session === undefined) {
|
||||
Logger.i(TAG, `this.session is undefined`)
|
||||
return;
|
||||
}
|
||||
Logger.i(TAG, 'Download Dialog exist close.');
|
||||
let abilityResult: ability.AbilityResult = {
|
||||
resultCode: (this.downloadNewUri === undefined) ? -1 : 0,
|
||||
want: {
|
||||
parameters: {
|
||||
'downloadNewUri': this.downloadNewUri
|
||||
}
|
||||
}
|
||||
};
|
||||
this.session.terminateSelfWithResult(abilityResult, (error) => {
|
||||
Logger.i(TAG, 'terminateSelfWithResult is called = ' + error?.code);
|
||||
});
|
||||
}
|
||||
|
||||
build() {
|
||||
}
|
||||
|
||||
//外部调用下载弹窗
|
||||
externalDownloadDialog: CustomDialogController = new CustomDialogController({
|
||||
builder: DownloadDialog({
|
||||
appName: this.appName,
|
||||
appIcon: this.appIcon,
|
||||
confirm: this.confirm,
|
||||
cancel: this.cancel
|
||||
}),
|
||||
autoCancel: false,
|
||||
customStyle: true,
|
||||
alignment: DialogAlignment.Center, // 可设置dialog的对齐方式,设定显示在底部或中间等,默认为底部显示
|
||||
})
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import { fileTree } from './component/dialog/FileMoveDialog';
|
||||
import Logger from '../base/log/Logger';
|
||||
import ErrorCodeConst from '../base//constants/ErrorCodeConst';
|
||||
import { toast } from '../base/utils/Common';
|
||||
import AbilityCommonUtil from '../base/utils/AbilityCommonUtil';
|
||||
import AbilityCommonUtil, { ResultCodePicker } from '../base/utils/AbilityCommonUtil';
|
||||
import { SYSTEM_BAR_COLOR } from '../base/constants/UiConstant';
|
||||
import StringUtil from '../base/utils/StringUtil';
|
||||
import { FileUtil } from '../base/utils/FileUtil';
|
||||
@@ -26,30 +26,34 @@ import MediaLibrary from '@ohos.multimedia.mediaLibrary';
|
||||
import fileAccess from '@ohos.file.fileAccess';
|
||||
import { ArrayUtil } from '../base/utils/ArrayUtil';
|
||||
import { UiUtil } from '../base/utils/UiUtil';
|
||||
import { StartModeOptions } from '../base/model/StartModeOptions';
|
||||
import { FilePickerUtil } from '../base/utils/FilePickerUtil';
|
||||
|
||||
const TAG = 'PathSelector';
|
||||
let storage = LocalStorage.getShared();
|
||||
|
||||
@Entry
|
||||
@Entry(storage)
|
||||
@Component
|
||||
struct PathSelector {
|
||||
private startModeOptions: StartModeOptions = FilePickerUtil.getStartOptionsFromStorage();
|
||||
@State createResultType: number = ErrorCodeConst.PICKER.NORMAL;
|
||||
|
||||
aboutToAppear() {
|
||||
UiUtil.setWindowBackground(SYSTEM_BAR_COLOR.LIGHT_GRAY);
|
||||
}
|
||||
|
||||
async saveFileCallback(res): Promise<void> {
|
||||
async saveFileCallback(res, startModeOptions: StartModeOptions): Promise<void> {
|
||||
if (res?.cancel) {
|
||||
globalThis.pathAbilityContext.terminateSelf();
|
||||
AbilityCommonUtil.terminatePathPicker([], ResultCodePicker.CANCEL, startModeOptions);
|
||||
return;
|
||||
} else {
|
||||
let fileNameList = globalThis.keyPickFileName;
|
||||
let fileNameList = this.startModeOptions.newFileNames;
|
||||
// 保存单个文件时文件名可修改,需使用修改后的文件名来创建文件
|
||||
if (fileNameList.length <= 1) {
|
||||
fileNameList = [res.fileName];
|
||||
}
|
||||
this.saveFiles(res.selectUri, fileNameList).then((createdFileList) => {
|
||||
AbilityCommonUtil.terminatePathPicker(createdFileList);
|
||||
AbilityCommonUtil.terminatePathPicker(createdFileList, ResultCodePicker.SUCCESS, startModeOptions);
|
||||
}).catch((err) => {
|
||||
let errorMessage = '';
|
||||
let errorCode = 0;
|
||||
@@ -59,7 +63,7 @@ struct PathSelector {
|
||||
errorMessage = 'Same name file already exists';
|
||||
errorCode = ErrorCodeConst.PICKER.FILE_NAME_EXIST;
|
||||
this.createResultType = errorCode;
|
||||
const pathName = globalThis.keyPickFileName;
|
||||
const pathName = startModeOptions.newFileNames;
|
||||
let listLength: number = pathName.length;
|
||||
if (listLength == 1) {
|
||||
return;
|
||||
@@ -75,7 +79,7 @@ struct PathSelector {
|
||||
errorMessage = err.message ? err.message : err;
|
||||
errorCode = ErrorCodeConst.PICKER.OTHER_ERROR;
|
||||
}
|
||||
AbilityCommonUtil.terminatePathPicker([], errorCode, errorMessage);
|
||||
AbilityCommonUtil.terminatePathPicker([], errorCode, startModeOptions);
|
||||
toast($r('app.string.save_file_fail'));
|
||||
Logger.e(TAG, `path select error, errorCode: ${errorCode}, errorMessage: ${errorMessage}`);
|
||||
})
|
||||
@@ -182,7 +186,7 @@ struct PathSelector {
|
||||
}
|
||||
|
||||
private async tryRenameFileOperate(fileAccessHelper: fileAccess.FileAccessHelper, fileName: string,
|
||||
dirUri: string, renameCount: number, fileNameList: string[] = []): Promise<{
|
||||
dirUri: string, renameCount: number, fileNameList: string[] = []): Promise<{
|
||||
err,
|
||||
uri
|
||||
}> {
|
||||
@@ -229,11 +233,32 @@ struct PathSelector {
|
||||
}
|
||||
|
||||
build() {
|
||||
if (this.startModeOptions.isUxt()) {
|
||||
Column() {
|
||||
}.bindSheet(true, this.mainContent(), {
|
||||
height: SheetSize.FIT_CONTENT,
|
||||
dragBar: false,
|
||||
showClose: false,
|
||||
preferType: SheetType.CENTER,
|
||||
onAppear: () => {
|
||||
},
|
||||
shouldDismiss: () => {
|
||||
this.startModeOptions.session.terminateSelf();
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.mainContent()
|
||||
}
|
||||
}
|
||||
|
||||
@Builder
|
||||
mainContent() {
|
||||
Row() {
|
||||
fileTree({
|
||||
startModeOptions: this.startModeOptions,
|
||||
createFileFailType: $createResultType,
|
||||
moveCallback: (e) => {
|
||||
this.saveFileCallback(e);
|
||||
this.saveFileCallback(e, this.startModeOptions);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -28,20 +28,24 @@ import { Loading } from '../../component/common/Loading';
|
||||
import { getMediaType, getDurationByUri } from '../../../databases/model/FileAssetModel';
|
||||
import Logger from '../../../base/log/Logger';
|
||||
import multimedia_image from '@ohos.multimedia.image';
|
||||
import AbilityCommonUtil from '../../../base/utils/AbilityCommonUtil';
|
||||
import AbilityCommonUtil, { ResultCodePicker } 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';
|
||||
import { StartModeOptions } from '../../../base/model/StartModeOptions';
|
||||
import { FilePickerUtil } from '../../../base/utils/FilePickerUtil';
|
||||
|
||||
const TAG = 'myPhone';
|
||||
let storage = LocalStorage.getShared();
|
||||
|
||||
@Entry
|
||||
@Entry(storage)
|
||||
@Component
|
||||
struct MyPhone {
|
||||
/**
|
||||
* 正在加载
|
||||
*/
|
||||
private startModeOptions: StartModeOptions = FilePickerUtil.getStartOptionsFromStorage();
|
||||
@State isShowLoading: boolean = true;
|
||||
/**
|
||||
* 文件或文件夹数据
|
||||
@@ -119,7 +123,7 @@ struct MyPhone {
|
||||
}
|
||||
if (Array.isArray(fileData)) {
|
||||
isContinue = true;
|
||||
for (let i = 0;i < fileData.length; i++) {
|
||||
for (let i = 0; i < fileData.length; i++) {
|
||||
let fileName: string = fileData[i].fileName;
|
||||
let currentDir: string = FileUtil.getPathWithFileSplit(fileData[i].currentDir);
|
||||
if (data.startsWith(currentDir)) {
|
||||
@@ -149,7 +153,7 @@ struct MyPhone {
|
||||
|
||||
onPageShow() {
|
||||
// 文件选择器并且是多选模式下详情返回不更新,避免原有多选被重置
|
||||
if (globalThis.filePickerViewFlag && this.isMulti) {
|
||||
if (this.isMulti) {
|
||||
return;
|
||||
}
|
||||
setImmersion(false);
|
||||
@@ -197,7 +201,7 @@ struct MyPhone {
|
||||
|
||||
backCallback(): void {
|
||||
if (!this.isMulti) {
|
||||
AbilityCommonUtil.terminateFilePicker([], [], AbilityCommonUtil.RESULT_CODE.CANCEL);
|
||||
AbilityCommonUtil.terminateFilePicker([], ResultCodePicker.SUCCESS, this.startModeOptions);
|
||||
} else {
|
||||
this.initData();
|
||||
}
|
||||
@@ -228,7 +232,7 @@ struct MyPhone {
|
||||
multimedia_image.createPixelMap(new ArrayBuffer(4096), { size: { height: 1, width: 2 } }).then((pixelMap) => {
|
||||
})
|
||||
this.setShowLoading(true);
|
||||
let pickPath = this.getParams();
|
||||
let pickPath = this.getParams(this.startModeOptions);
|
||||
if (StringUtil.isEmpty(pickPath)) {
|
||||
this.getRootListFile();
|
||||
} else {
|
||||
@@ -241,8 +245,8 @@ struct MyPhone {
|
||||
this.fileMkdirDialog = null;
|
||||
}
|
||||
|
||||
getParams(): string {
|
||||
let defaultPickPath = globalThis.keyFileDefaultPickPath;
|
||||
getParams(startModeOptions: StartModeOptions): string {
|
||||
let defaultPickPath = startModeOptions.defaultFilePathUri;
|
||||
if (!ObjectUtil.isNullOrUndefined(defaultPickPath)) {
|
||||
return defaultPickPath;
|
||||
}
|
||||
@@ -294,7 +298,7 @@ struct MyPhone {
|
||||
this.getRootListFile();
|
||||
}
|
||||
} else {
|
||||
AbilityCommonUtil.terminateFilePicker([], [], AbilityCommonUtil.RESULT_CODE.CANCEL);
|
||||
AbilityCommonUtil.terminateFilePicker([], ResultCodePicker.CANCEL, this.startModeOptions);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -302,9 +306,30 @@ struct MyPhone {
|
||||
}
|
||||
|
||||
build() {
|
||||
if (this.startModeOptions.isUxt()) {
|
||||
Column() {
|
||||
}.bindSheet(true, this.mainContent(), {
|
||||
height: SheetSize.FIT_CONTENT,
|
||||
dragBar: false,
|
||||
showClose: false,
|
||||
preferType: SheetType.CENTER,
|
||||
onAppear: () => {
|
||||
},
|
||||
shouldDismiss: () => {
|
||||
this.startModeOptions.session.terminateSelf();
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.mainContent()
|
||||
}
|
||||
}
|
||||
|
||||
@Builder
|
||||
mainContent() {
|
||||
Column() {
|
||||
// 头部导航
|
||||
TopBar({
|
||||
startModeOptions: this.startModeOptions,
|
||||
title: getResourceString($r('app.string.myPhone')),
|
||||
isMulti: this.isMulti,
|
||||
selectAll: this.selectAll,
|
||||
@@ -328,6 +353,7 @@ struct MyPhone {
|
||||
if (!this.isShowLoading) {
|
||||
// 文件列表
|
||||
FilesList({
|
||||
startModeOptions: this.startModeOptions,
|
||||
fileListSource: $fileListSource,
|
||||
direList: $direList,
|
||||
isMulti: $isMulti,
|
||||
|
||||
@@ -73,7 +73,7 @@ export struct TreeItem {
|
||||
}
|
||||
|
||||
private async getPickPathListFiles(dirUri: string, expandPath: string, level: number): Promise<FileBase[]> {
|
||||
let fileHelper = await FileUtil.getFileAccessHelperAsync(globalThis.abilityContext);
|
||||
let fileHelper = await FileUtil.getFileAccessHelperAsync(getContext());
|
||||
let fileInfo: fileAccess.FileInfo = await FileUtil.getFileInfoByUri(dirUri, fileHelper);
|
||||
if (ObjectUtil.isNullOrUndefined(fileInfo) || !FileUtil.isFolder(fileInfo.mode)) {
|
||||
Logger.e(TAG, 'uri is not folder');
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
|
||||
import context from '@ohos.app.ability.common';
|
||||
import { renderSize } from '../../../base/utils/Tools';
|
||||
import AbilityCommonUtil from '../../../base//utils/AbilityCommonUtil';
|
||||
import AbilityCommonUtil, { ResultCodePicker } from '../../../base//utils/AbilityCommonUtil';
|
||||
import { StartModeOptions } from '../../../base/model/StartModeOptions';
|
||||
import { FilePickerUtil } from '../../../base/utils/FilePickerUtil';
|
||||
|
||||
@Styles
|
||||
function pressedStyles() {
|
||||
@@ -24,7 +26,7 @@ function pressedStyles() {
|
||||
}
|
||||
|
||||
@Styles
|
||||
function normalStyles () {
|
||||
function normalStyles() {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.transparent_color'))
|
||||
}
|
||||
@@ -35,10 +37,9 @@ function subtitleStyles(fontSize: Resource) {
|
||||
.alignSelf(ItemAlign.Start)
|
||||
}
|
||||
|
||||
const filePickerViewFlag = globalThis.filePickerViewFlag;
|
||||
|
||||
@Component
|
||||
export struct TopBar {
|
||||
private startModeOptions: StartModeOptions = FilePickerUtil.getStartOptionsFromStorage();
|
||||
private title?: string = '';
|
||||
private subtitle?: string = '';
|
||||
private fileSize?: number = 0;
|
||||
@@ -57,9 +58,10 @@ export struct TopBar {
|
||||
}
|
||||
|
||||
initTitle(): string | Resource {
|
||||
if (this.isMulti && !filePickerViewFlag) {
|
||||
if (this.isMulti) {
|
||||
return this.checkedNum === 0 ? $r('app.string.selected_none') : this.checkedNum === 1 ?
|
||||
$r('app.string.selected_items_singular', this.checkedNum) : $r('app.string.selected_items_plural', this.checkedNum);
|
||||
$r('app.string.selected_items_singular', this.checkedNum) :
|
||||
$r('app.string.selected_items_plural', this.checkedNum);
|
||||
} else {
|
||||
return this.title;
|
||||
}
|
||||
@@ -67,7 +69,8 @@ export struct TopBar {
|
||||
|
||||
filePickerTitle() {
|
||||
if (this.isMulti) {
|
||||
return this.checkedNum === 0 ? $r('app.string.selected_none') : $r('app.string.selected', this.checkedNum, globalThis.filePickNum);
|
||||
return this.checkedNum === 0 ? $r('app.string.selected_none') :
|
||||
$r('app.string.selected', this.checkedNum, globalThis.filePickNum);
|
||||
} else {
|
||||
return this.title;
|
||||
}
|
||||
@@ -89,7 +92,7 @@ export struct TopBar {
|
||||
}
|
||||
const uriList = this.checkedList.map(item => item.uri);
|
||||
const fileNameList = this.checkedList.map(item => item.fileName);
|
||||
AbilityCommonUtil.terminateFilePicker(uriList, fileNameList);
|
||||
AbilityCommonUtil.terminateFilePicker(uriList, ResultCodePicker.SUCCESS, this.startModeOptions);
|
||||
}
|
||||
|
||||
build() {
|
||||
@@ -115,7 +118,7 @@ export struct TopBar {
|
||||
})
|
||||
|
||||
Column() {
|
||||
Text(filePickerViewFlag ? this.filePickerTitle() : this.initTitle())
|
||||
Text(this.filePickerTitle())
|
||||
.fontColor($r('app.color.black'))
|
||||
.fontSize($r('app.float.common_font_size20'))
|
||||
.fontWeight(FontWeight.Medium)
|
||||
@@ -136,49 +139,46 @@ export struct TopBar {
|
||||
.layoutWeight(1)
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
|
||||
if (filePickerViewFlag) {
|
||||
if (!this.isMulti) {
|
||||
Column() {
|
||||
Image($r('app.media.hidisk_cancel_normal'))
|
||||
.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'),
|
||||
top: $r('app.float.common_padding10'),
|
||||
bottom: $r('app.float.common_padding10')
|
||||
})
|
||||
.stateStyles({
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.onClick(() => {
|
||||
let abilityContext = getContext(this) as context.UIAbilityContext;
|
||||
abilityContext.terminateSelf();
|
||||
})
|
||||
} else {
|
||||
Column() {
|
||||
Image($r('app.media.ic_ok'))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.width($r('app.float.common_size24'))
|
||||
.height($r('app.float.common_size24'))
|
||||
}.padding({
|
||||
left: $r('app.float.common_padding12'),
|
||||
right: $r('app.float.common_padding12'),
|
||||
top: $r('app.float.common_padding10'),
|
||||
bottom: $r('app.float.common_padding10')
|
||||
})
|
||||
.stateStyles({
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.onClick(() => {
|
||||
this.terminate();
|
||||
})
|
||||
.opacity(this.checkSelectedFileList() ? $r('app.float.common_opacity10') : $r('app.float.common_opacity4'))
|
||||
}
|
||||
if (!this.isMulti) {
|
||||
Column() {
|
||||
Image($r('app.media.hidisk_cancel_normal'))
|
||||
.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'),
|
||||
top: $r('app.float.common_padding10'),
|
||||
bottom: $r('app.float.common_padding10')
|
||||
})
|
||||
.stateStyles({
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.onClick(() => {
|
||||
AbilityCommonUtil.terminateFilePicker([], ResultCodePicker.CANCEL, this.startModeOptions);
|
||||
})
|
||||
} else {
|
||||
Column() {
|
||||
Image($r('app.media.ic_ok'))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.width($r('app.float.common_size24'))
|
||||
.height($r('app.float.common_size24'))
|
||||
}.padding({
|
||||
left: $r('app.float.common_padding12'),
|
||||
right: $r('app.float.common_padding12'),
|
||||
top: $r('app.float.common_padding10'),
|
||||
bottom: $r('app.float.common_padding10')
|
||||
})
|
||||
.stateStyles({
|
||||
pressed: pressedStyles,
|
||||
normal: normalStyles
|
||||
})
|
||||
.onClick(() => {
|
||||
this.terminate();
|
||||
})
|
||||
.opacity(this.checkSelectedFileList() ? $r('app.float.common_opacity10') : $r('app.float.common_opacity4'))
|
||||
}
|
||||
}
|
||||
.height($r('app.float.common_mark_y50'))
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
|
||||
*/
|
||||
|
||||
@Styles
|
||||
function pressStyles() {
|
||||
.backgroundColor($r('sys.color.ohos_id_color_click_effect'))
|
||||
}
|
||||
|
||||
@Styles
|
||||
function normalStyles() {
|
||||
.backgroundColor($r('sys.color.ohos_id_color_background_transparent'))
|
||||
}
|
||||
|
||||
@Component
|
||||
export struct DialogButton {
|
||||
text?: Resource;
|
||||
color: Resource | string = $r('sys.color.ohos_id_color_text_primary_activated');
|
||||
bgColor: Resource | string = $r('sys.color.ohos_id_color_background_transparent');
|
||||
@Prop isDisabled: boolean = false;
|
||||
click?: Function;
|
||||
compId?: Resource = $r('app.string.confirm');
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
Row() {
|
||||
Text(this.text)
|
||||
.fontSize($r('sys.float.ohos_id_text_size_button1'))
|
||||
.fontColor(this.color)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.textCase(TextCase.UpperCase)
|
||||
}.height('100%')
|
||||
.width('100%')
|
||||
.justifyContent(FlexAlign.Center)
|
||||
.onClick(() => {
|
||||
if ((!this.click) || this.isDisabled) {
|
||||
return
|
||||
}
|
||||
this.click()
|
||||
})
|
||||
}
|
||||
.id(this.text === this.compId ? 'dialog_confirm' : 'dialog_cancel')
|
||||
.enabled(!this.isDisabled)
|
||||
.height(40)
|
||||
.layoutWeight(1)
|
||||
.backgroundColor(this.bgColor)
|
||||
.stateStyles({
|
||||
normal: normalStyles,
|
||||
pressed: pressStyles
|
||||
})
|
||||
.opacity(this.isDisabled ? $r('app.float.common_opacity5') : $r('app.float.common_opacity10'))
|
||||
.borderRadius($r('sys.float.ohos_id_corner_radius_dialog'))
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
export struct DialogButtonDivider {
|
||||
build() {
|
||||
Divider().vertical(true)
|
||||
.margin({ left: 8, right: 8 })
|
||||
.height($r('app.float.divider_height24'))
|
||||
.color($r('sys.color.ohos_id_color_list_separator'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
|
||||
*/
|
||||
import { DialogButton, DialogButtonDivider } from './DialogComponent';
|
||||
import { display } from '@kit.ArkUI';
|
||||
import Logger from '../../../base/log/Logger';
|
||||
|
||||
const TAG = 'DownloadDialog';
|
||||
let storage = LocalStorage.getShared();
|
||||
|
||||
@CustomDialog
|
||||
export struct DownloadDialog {
|
||||
controller?: CustomDialogController;
|
||||
cancel: Function = () => {
|
||||
};
|
||||
confirm: Function = () => {
|
||||
};
|
||||
appName: string | undefined = storage.get<string>('appName');
|
||||
appIcon: string | undefined = storage.get<string>('appIcon');
|
||||
downloadTips: Resource = $r('app.string.download_tips', this.appName, this.appName);
|
||||
cancelButtonText: Resource = $r('app.string.cancel');
|
||||
confirmButtonText: Resource = $r('app.string.agree');
|
||||
@State contentAlign: ItemAlign = ItemAlign.Start;
|
||||
@State dialogWidth: number = 328;
|
||||
closeDialogBind: Function = () => this.closeDialog();
|
||||
|
||||
aboutToAppear(): void {
|
||||
let px2VpScale: number = px2vp(1);
|
||||
let screenWidth: number = display.getDefaultDisplaySync()?.width ?
|
||||
px2vp(display.getDefaultDisplaySync()?.width) : px2vp(display.getDefaultDisplaySync()?.width * px2VpScale);
|
||||
this.dialogWidth = screenWidth > 432 ? 400 : screenWidth - 32;
|
||||
}
|
||||
|
||||
closeDialog(): void {
|
||||
if (this.controller) {
|
||||
Logger.i(TAG, 'DownloadDialog close.');
|
||||
this.controller.close();
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Column() {
|
||||
this.downloadDialogContent();
|
||||
}
|
||||
.padding({
|
||||
left: $r('app.float.common_padding24'),
|
||||
right: $r('app.float.common_padding24')
|
||||
})
|
||||
}
|
||||
.borderRadius($r('sys.float.ohos_id_corner_radius_dialog'))
|
||||
.backgroundColor($r('sys.color.ohos_id_color_dialog_bg'))
|
||||
.alignItems(HorizontalAlign.End)
|
||||
.margin({ left: $r('app.float.common_margin16'), right: $r('app.float.common_margin16') })
|
||||
.width(this.dialogWidth)
|
||||
}
|
||||
|
||||
@Builder
|
||||
downloadDialogContent() {
|
||||
Row() {
|
||||
Image(this.appIcon)
|
||||
.fillColor($r('sys.color.ohos_id_color_primary'))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.width($r('app.float.common_size64'))
|
||||
.height($r('app.float.common_size64'))
|
||||
.interpolation(ImageInterpolation.High)
|
||||
.draggable(false)
|
||||
.focusable(true)
|
||||
.margin({ top: 24 })
|
||||
.autoResize(false)
|
||||
}
|
||||
|
||||
Row() {
|
||||
Text(this.downloadTips)
|
||||
.lineHeight(21)
|
||||
.fontColor($r('sys.color.ohos_id_color_text_primary'))
|
||||
.margin({ top: $r('app.float.common_margin16') })
|
||||
.alignSelf(ItemAlign.Center)
|
||||
}
|
||||
|
||||
Row() {
|
||||
DialogButton({
|
||||
text: this.cancelButtonText,
|
||||
isDisabled: false,
|
||||
color: '#0A56F7',
|
||||
bgColor: '#F1F3F5',
|
||||
click: () => {
|
||||
this.cancel()
|
||||
this.closeDialog()
|
||||
}
|
||||
})
|
||||
DialogButtonDivider()
|
||||
DialogButton({
|
||||
text: this.confirmButtonText,
|
||||
isDisabled: false,
|
||||
color: '#0A56F7',
|
||||
bgColor: '#F1F3F5',
|
||||
click: () => {
|
||||
this.confirm();
|
||||
this.closeDialog();
|
||||
}
|
||||
})
|
||||
}.width('100%')
|
||||
.padding({ bottom: $r('app.float.common_margin10'), top: $r('app.float.common_margin10') })
|
||||
.margin({
|
||||
top: 8,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -27,13 +27,17 @@ import { FileUtil } from '../../../base/utils/FileUtil';
|
||||
import Logger from '../../../base/log/Logger';
|
||||
import { ArrayUtil } from '../../../base/utils/ArrayUtil';
|
||||
import ErrorCodeConst from '../../../base/constants/ErrorCodeConst';
|
||||
import { StartModeOptions } from '../../../base/model/StartModeOptions';
|
||||
import { FilePickerUtil } from '../../../base/utils/FilePickerUtil';
|
||||
|
||||
@Styles function pressedStyles () {
|
||||
@Styles
|
||||
function pressedStyles() {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.hicloud_hmos_bg'))
|
||||
}
|
||||
|
||||
@Styles function normalStyles() {
|
||||
@Styles
|
||||
function normalStyles() {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.transparent_color'))
|
||||
}
|
||||
@@ -42,6 +46,7 @@ const TAG = 'fileTree';
|
||||
|
||||
@Component
|
||||
export struct fileTree {
|
||||
private startModeOptions: StartModeOptions = FilePickerUtil.getStartOptionsFromStorage();
|
||||
@State listLength: number = 0;
|
||||
@State positionY: string | number = '100%';
|
||||
@State topRotate: boolean = false;
|
||||
@@ -77,12 +82,12 @@ export struct fileTree {
|
||||
|
||||
async aboutToAppear() {
|
||||
toast($r('app.string.select_location'))
|
||||
const fileNameList = globalThis.keyPickFileName;
|
||||
const fileNameList = this.startModeOptions.newFileNames;
|
||||
this.listLength = fileNameList.length;
|
||||
const fileName: string = fileNameList[0];
|
||||
if (fileName) {
|
||||
const dotIndex = fileName.lastIndexOf('.');
|
||||
let fileSuffix = globalThis.keyFileSuffixChoices;
|
||||
let fileSuffix = this.startModeOptions.PhoneFileSuffixChoices;
|
||||
if (!StringUtil.isEmpty(fileSuffix)) {
|
||||
this.suffix = fileSuffix;
|
||||
if (dotIndex > 0) {
|
||||
@@ -104,7 +109,7 @@ export struct fileTree {
|
||||
if (globalThis.documentInfo) {
|
||||
this.selectUri = globalThis.documentInfo.uri;
|
||||
}
|
||||
this.loadDefaultExpandPath();
|
||||
this.loadDefaultExpandPath(this.startModeOptions);
|
||||
}
|
||||
|
||||
aboutToDisappear() {
|
||||
@@ -200,14 +205,14 @@ export struct fileTree {
|
||||
/**
|
||||
* 加载默认展开目录,如果是路径选择器拉起的,优先使用三方指定的目录
|
||||
*/
|
||||
async loadDefaultExpandPath() {
|
||||
let defaultPickDir = globalThis.keyPathDefaultPickDir;
|
||||
async loadDefaultExpandPath(startModeOptions: StartModeOptions) {
|
||||
let defaultPickDir = startModeOptions.defaultFilePathUri;
|
||||
let loadUri = this.lastSelectPath;
|
||||
if (!StringUtil.isEmpty(defaultPickDir)) {
|
||||
loadUri = defaultPickDir;
|
||||
}
|
||||
if (!StringUtil.isEmpty(loadUri)) {
|
||||
let fileHelper = await FileUtil.getFileAccessHelperAsync(globalThis.abilityContext);
|
||||
let fileHelper = await FileUtil.getFileAccessHelperAsync(startModeOptions.context);
|
||||
let fileInfo = await FileUtil.getFileInfoByUri(loadUri, fileHelper);
|
||||
if (fileInfo) {
|
||||
this.defaultExpandPath = FileUtil.getCurrentFolderByFileInfo(fileInfo);
|
||||
|
||||
@@ -16,26 +16,29 @@
|
||||
import { BreadData, FilesData, FileDataSource } from '../../../databases/model/FileData';
|
||||
import { renderSize, gridName, isDlpFile } from '../../../base/utils/Tools';
|
||||
import DateTimeUtil from '../../../base/utils/DateTimeUtil';
|
||||
import { pickerStatus, filePickerTip } from '../../../base/utils/FilePickerUtil';
|
||||
import { pickerStatus, filePickerTip, FilePickerUtil } from '../../../base/utils/FilePickerUtil';
|
||||
import { Z_INDEX } from '../../../base/constants/UiConstant';
|
||||
import Logger from '../../../base/log/Logger';
|
||||
import { NoContent } from '../common/NoContent';
|
||||
import { VideoDurationTag } from '../common/VideoDurationTag';
|
||||
import { StartModeOptions } from '../../../base/model/StartModeOptions';
|
||||
|
||||
const TAG = 'MyPhone_FilesList';
|
||||
const filePickerViewFlag = globalThis.filePickerViewFlag;
|
||||
|
||||
@Styles function pressedStyles() {
|
||||
@Styles
|
||||
function pressedStyles() {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.hicloud_hmos_bg'))
|
||||
}
|
||||
|
||||
@Styles function normalStyles() {
|
||||
@Styles
|
||||
function normalStyles() {
|
||||
.borderRadius($r('app.float.common_borderRadius8'))
|
||||
.backgroundColor($r('app.color.transparent_color'))
|
||||
}
|
||||
|
||||
@Extend(Text) function grayText() {
|
||||
@Extend(Text)
|
||||
function grayText() {
|
||||
.fontSize($r('app.float.common_font_size12'))
|
||||
.fontColor($r('app.color.black'))
|
||||
.lineHeight($r('app.float.common_size19'))
|
||||
@@ -44,6 +47,7 @@ const filePickerViewFlag = globalThis.filePickerViewFlag;
|
||||
|
||||
@Component
|
||||
export struct FilesList {
|
||||
private startModeOptions: StartModeOptions = FilePickerUtil.getStartOptionsFromStorage();
|
||||
@Link fileListSource: FileDataSource;
|
||||
/**
|
||||
* 面包屑
|
||||
@@ -81,6 +85,7 @@ export struct FilesList {
|
||||
LazyForEach(this.fileListSource, (item, index) => {
|
||||
ListItem() {
|
||||
FileListItem({
|
||||
startModeOptions: this.startModeOptions,
|
||||
fileItem: item,
|
||||
fileListSource: $fileListSource,
|
||||
direList: $direList,
|
||||
@@ -100,6 +105,7 @@ export struct FilesList {
|
||||
LazyForEach(this.fileListSource, (item, index) => {
|
||||
GridItem() {
|
||||
FileListItem({
|
||||
startModeOptions: this.startModeOptions,
|
||||
fileItem: item,
|
||||
fileListSource: $fileListSource,
|
||||
direList: $direList,
|
||||
@@ -120,6 +126,7 @@ export struct FilesList {
|
||||
|
||||
@Component
|
||||
struct FileListItem {
|
||||
private startModeOptions: StartModeOptions = FilePickerUtil.getStartOptionsFromStorage();
|
||||
@Consume isList: boolean;
|
||||
@State fileItem: FilesData = new FilesData({});
|
||||
@Link fileListSource: FileDataSource;
|
||||
@@ -127,7 +134,7 @@ struct FileListItem {
|
||||
@Link @Watch('isMultiChange') isMulti: boolean;
|
||||
@Link checkedNum: number;
|
||||
@State isChecked: boolean = false;
|
||||
@State filePickerViewFlag: boolean = globalThis.filePickerViewFlag;
|
||||
@State filePickerViewFlag: boolean = true;
|
||||
@State isImageLoaded: boolean = true;
|
||||
|
||||
isShowThumbnail(item) {
|
||||
@@ -148,7 +155,7 @@ struct FileListItem {
|
||||
|
||||
getRightIcon(item): Resource {
|
||||
if (this.isMulti) {
|
||||
if (pickerStatus(this.fileItem, this.checkedNum).differentTypes) {
|
||||
if (pickerStatus(this.fileItem, this.checkedNum, this.startModeOptions).differentTypes) {
|
||||
return;
|
||||
}
|
||||
return item.isChecked ? $r('app.media.checkbox_b') : $r('app.media.checkbox_g');
|
||||
@@ -191,9 +198,9 @@ struct FileListItem {
|
||||
if (this.fileItem.isFolder) {
|
||||
return;
|
||||
}
|
||||
let status = pickerStatus(this.fileItem, this.checkedNum);
|
||||
let status = pickerStatus(this.fileItem, this.checkedNum, this.startModeOptions);
|
||||
if (status.exceedLimit) {
|
||||
filePickerTip();
|
||||
filePickerTip(this.startModeOptions);
|
||||
return;
|
||||
}
|
||||
if (status.differentTypes) {
|
||||
@@ -208,14 +215,14 @@ struct FileListItem {
|
||||
|
||||
onClickEvent() {
|
||||
Logger.i(TAG, 'onClickEvent start');
|
||||
let status = pickerStatus(this.fileItem, this.checkedNum);
|
||||
let status = pickerStatus(this.fileItem, this.checkedNum, this.startModeOptions);
|
||||
if (this.isMulti) {
|
||||
if (this.fileItem.isFolder) {
|
||||
return;
|
||||
}
|
||||
// 选择器页面,选择文件超出上限
|
||||
if (status.exceedLimit) {
|
||||
filePickerTip();
|
||||
filePickerTip(this.startModeOptions);
|
||||
return;
|
||||
} else if (status.differentTypes) {
|
||||
return;
|
||||
@@ -238,7 +245,7 @@ struct FileListItem {
|
||||
}
|
||||
if (!status.exceedLimit && !status.differentTypes) {
|
||||
// 选中的数据回调给三方应用
|
||||
this.fileItem.pickFile();
|
||||
this.fileItem.pickFile(this.startModeOptions);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -258,7 +265,7 @@ struct FileListItem {
|
||||
}
|
||||
|
||||
calOpacity() {
|
||||
const statusObj = pickerStatus(this.fileItem, this.checkedNum);
|
||||
const statusObj = pickerStatus(this.fileItem, this.checkedNum, this.startModeOptions);
|
||||
return statusObj.exceedLimit || (!this.fileItem.isFolder && statusObj.differentTypes) ||
|
||||
(this.isMulti && this.fileItem.isFolder) ? $r('app.float.common_opacity2') : $r('app.float.common_opacity10');
|
||||
}
|
||||
@@ -332,8 +339,10 @@ struct FileListItem {
|
||||
|
||||
@Builder
|
||||
buildGridItemView() {
|
||||
Flex({ direction: FlexDirection.Column,
|
||||
alignItems: ItemAlign.Center }) {
|
||||
Flex({
|
||||
direction: FlexDirection.Column,
|
||||
alignItems: ItemAlign.Center
|
||||
}) {
|
||||
Column() {
|
||||
Column() {
|
||||
Image(this.isShowThumbnail(this.fileItem) ? this.fileItem.thumbUri : this.fileItem.localGridIcon)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"abilities": [
|
||||
{
|
||||
"name": "MainAbility",
|
||||
"srcEntry": "./ets/entryability/MainAbility.ts",
|
||||
"srcEntry": "./ets/entryability/MainAbility.ets",
|
||||
"description": "$string:EntryAbility_desc",
|
||||
"icon": "$media:app_icon",
|
||||
"label": "$string:EntryAbility_label",
|
||||
@@ -32,6 +32,15 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"extensionAbilities": [
|
||||
{
|
||||
"name": "FilePickerUIExtAbility",
|
||||
"srcEntry": "./ets/entryability/FilePickerUIExtAbility.ets",
|
||||
"description": "FilePickerUIExtAbility",
|
||||
"exported": true,
|
||||
"type": "sysPicker/filePicker",
|
||||
},
|
||||
],
|
||||
requestPermissions: [
|
||||
// 媒体库管理权限
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user