|
|
@@ -9,10 +9,11 @@ import { CommonConstants } from '../common/constants/CommonConstants';
|
|
|
import { Constants } from '../Constants';
|
|
|
import { picker, fileUri } from '@kit.CoreFileKit';
|
|
|
import { BusinessError } from '@kit.BasicServicesKit';
|
|
|
-import { PreferencesUtil, AppUtil } from '@pura/harmony-utils';
|
|
|
+import { PreferencesUtil } from '@pura/harmony-utils';
|
|
|
import { UploadTaskDataSource } from '../viewmodel/UploadTask';
|
|
|
import { promptAction } from '@kit.ArkUI';
|
|
|
import fs from '@ohos.file.fs';
|
|
|
+import ReqPermissionUtil from '../common/util/ReqPermissionUtil';
|
|
|
|
|
|
const TAG = 'heanup UploadMusicPage';
|
|
|
|
|
|
@@ -64,6 +65,8 @@ export struct UploadMusicPage {
|
|
|
@State currentBrowsePath: string = '/';
|
|
|
@State browseFolders: FileInfo[] = [];
|
|
|
@State isLoadingFolders: boolean = false;
|
|
|
+ @State pendingCount: number = 0;
|
|
|
+ @State finishedCount: number = 0;
|
|
|
|
|
|
// RemoteDriveManager实例
|
|
|
private webdavManager: RemoteDriveManager = RemoteDriveManager.getInstance();
|
|
|
@@ -79,6 +82,7 @@ export struct UploadMusicPage {
|
|
|
this.handleUploadEvent(event);
|
|
|
};
|
|
|
private cachedDownloadRoot: string = '';
|
|
|
+ private localBrowseRoot: string = '';
|
|
|
|
|
|
aboutToAppear(): void {
|
|
|
Logger.info(TAG, '页面即将显示');
|
|
|
@@ -132,7 +136,7 @@ export struct UploadMusicPage {
|
|
|
// 如果没有选中账户且有可用账户,默认选择第一个
|
|
|
if (!this.selectedAccount && this.accounts.length > 0) {
|
|
|
this.selectedAccount = this.accounts[0];
|
|
|
- this.uploadPath = this.selectedAccount.uploadFilePath || '/';
|
|
|
+ this.applyDefaultUploadPath(this.selectedAccount);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
const err = error as Error;
|
|
|
@@ -156,9 +160,7 @@ export struct UploadMusicPage {
|
|
|
const err = error as Error;
|
|
|
Logger.warn(TAG, `读取download_path失败: ${err.message}`);
|
|
|
}
|
|
|
- const packName = AppUtil.getBundleName();
|
|
|
- this.cachedDownloadRoot = `/storage/Users/currentUser/Download/${packName}`;
|
|
|
- return this.cachedDownloadRoot;
|
|
|
+ return '';
|
|
|
}
|
|
|
|
|
|
private normalizeLocalDirectory(path: string): string {
|
|
|
@@ -189,7 +191,7 @@ export struct UploadMusicPage {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private async requestDownloadRootFromSystem(): Promise<string> {
|
|
|
+ private async requestDownloadRootFromSystem(force: boolean = false): Promise<string> {
|
|
|
try {
|
|
|
const documentViewPicker = new picker.DocumentViewPicker();
|
|
|
const documentSaveResult = await documentViewPicker.save({ pickerMode: picker.DocumentPickerMode.DOWNLOAD });
|
|
|
@@ -200,6 +202,7 @@ export struct UploadMusicPage {
|
|
|
this.cachedDownloadRoot = normalized;
|
|
|
const storedValue = normalized.endsWith('/') ? normalized : `${normalized}/`;
|
|
|
PreferencesUtil.putSync('download_path', storedValue);
|
|
|
+ await ReqPermissionUtil.persistPermission(documentSaveResult[0]);
|
|
|
return normalized;
|
|
|
}
|
|
|
}
|
|
|
@@ -219,7 +222,11 @@ export struct UploadMusicPage {
|
|
|
if (requested && this.ensureDirectoryAccessible(requested)) {
|
|
|
return requested;
|
|
|
}
|
|
|
- return '';
|
|
|
+ promptAction.showToast({
|
|
|
+ message: '请先在本地音乐页授权下载目录后再使用此功能',
|
|
|
+ duration: 2000
|
|
|
+ });
|
|
|
+ throw new Error('未授权任何本地目录');
|
|
|
}
|
|
|
|
|
|
private normalizeBrowsePath(path: string): string {
|
|
|
@@ -247,7 +254,7 @@ export struct UploadMusicPage {
|
|
|
const account = this.accounts[i];
|
|
|
if (account.id === accountId) {
|
|
|
this.selectedAccount = account;
|
|
|
- this.uploadPath = account.uploadFilePath || '/';
|
|
|
+ this.applyDefaultUploadPath(account);
|
|
|
Logger.info(TAG, `预选账户: ${account.name}`);
|
|
|
break;
|
|
|
}
|
|
|
@@ -390,10 +397,18 @@ export struct UploadMusicPage {
|
|
|
this.uploadQueue.push(tasks[i].song);
|
|
|
}
|
|
|
|
|
|
- // 更新LazyDataSource
|
|
|
+ this.pendingCount = this.uploadQueue.length;
|
|
|
+
|
|
|
+ if (this.pendingCount === 0) {
|
|
|
+ this.isUploading = false;
|
|
|
+ this.currentTask = null;
|
|
|
+ this.uploadProgress = 0;
|
|
|
+ this.uploadSpeed = '0 KB/s';
|
|
|
+ }
|
|
|
+
|
|
|
this.uploadQueueDataSource.updateTasks(this.uploadQueue);
|
|
|
|
|
|
- Logger.info(TAG, `上传队列更新,当前数量: ${this.uploadQueue.length}`);
|
|
|
+ Logger.info(TAG, `上传队列更新,当前数量: ${this.pendingCount}`);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -406,10 +421,11 @@ export struct UploadMusicPage {
|
|
|
this.finishQueue.push(tasks[i].song);
|
|
|
}
|
|
|
|
|
|
- // 更新LazyDataSource
|
|
|
+ this.finishedCount = this.finishQueue.length;
|
|
|
+
|
|
|
this.finishQueueDataSource.updateTasks(this.finishQueue);
|
|
|
|
|
|
- Logger.info(TAG, `完成队列更新,当前数量: ${this.finishQueue.length}`);
|
|
|
+ Logger.info(TAG, `完成队列更新,当前数量: ${this.finishedCount}`);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -430,6 +446,14 @@ export struct UploadMusicPage {
|
|
|
const documentSelectResult = await documentPicker.select(documentSelectOptions);
|
|
|
|
|
|
if (documentSelectResult && documentSelectResult.length > 0) {
|
|
|
+ for (let i = 0; i < documentSelectResult.length; i++) {
|
|
|
+ try {
|
|
|
+ await ReqPermissionUtil.persistPermission(documentSelectResult[i]);
|
|
|
+ } catch (error) {
|
|
|
+ const err = error as Error;
|
|
|
+ Logger.error(TAG, `持久化授权失败: ${err.message}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
Logger.info(TAG, `选择了 ${documentSelectResult.length} 个文件`);
|
|
|
|
|
|
// 保存选中的文件URI
|
|
|
@@ -476,15 +500,16 @@ export struct UploadMusicPage {
|
|
|
}
|
|
|
|
|
|
this.fileBrowserPath = initialPath;
|
|
|
+ this.localBrowseRoot = initialPath;
|
|
|
this.selectedBrowserItems.clear();
|
|
|
this.isShowFileBrowser = true;
|
|
|
await this.loadLocalFiles(initialPath);
|
|
|
Logger.info(TAG, `文件浏览器已定位到: ${initialPath}`);
|
|
|
} catch (error) {
|
|
|
- const err = error as BusinessError;
|
|
|
+ const err = error as Error;
|
|
|
Logger.error(TAG, `打开文件浏览器失败: ${err.message}`);
|
|
|
promptAction.showToast({
|
|
|
- message: '打开文件浏览器失败',
|
|
|
+ message: err.message || '打开文件浏览器失败',
|
|
|
duration: 2000
|
|
|
});
|
|
|
}
|
|
|
@@ -497,14 +522,17 @@ export struct UploadMusicPage {
|
|
|
try {
|
|
|
this.isLoadingFiles = true;
|
|
|
this.browserFiles = [];
|
|
|
+ let targetPath = path;
|
|
|
+ if (this.localBrowseRoot && !targetPath.startsWith(this.localBrowseRoot)) {
|
|
|
+ targetPath = this.localBrowseRoot;
|
|
|
+ }
|
|
|
+ Logger.info(TAG, `加载目录: ${targetPath}`);
|
|
|
|
|
|
- Logger.info(TAG, `加载目录: ${path}`);
|
|
|
-
|
|
|
- const files = fs.listFileSync(path);
|
|
|
+ const files = fs.listFileSync(targetPath);
|
|
|
|
|
|
for (let i = 0; i < files.length; i++) {
|
|
|
const fileName = files[i];
|
|
|
- const fullPath = `${path}/${fileName}`;
|
|
|
+ const fullPath = `${targetPath}/${fileName}`;
|
|
|
|
|
|
try {
|
|
|
const stat = fs.statSync(fullPath);
|
|
|
@@ -553,19 +581,39 @@ export struct UploadMusicPage {
|
|
|
* 进入子目录
|
|
|
*/
|
|
|
private async enterDirectory(item: LocalFileItem): Promise<void> {
|
|
|
- if (item.isDirectory) {
|
|
|
- this.fileBrowserPath = item.path;
|
|
|
- await this.loadLocalFiles(item.path);
|
|
|
+ if (!item.isDirectory) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (this.localBrowseRoot && !item.path.startsWith(this.localBrowseRoot)) {
|
|
|
+ promptAction.showToast({
|
|
|
+ message: '没有此目录的访问权限',
|
|
|
+ duration: 2000
|
|
|
+ });
|
|
|
+ return;
|
|
|
}
|
|
|
+ this.fileBrowserPath = item.path;
|
|
|
+ await this.loadLocalFiles(item.path);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 返回上级目录
|
|
|
*/
|
|
|
private async goBackDirectory(): Promise<void> {
|
|
|
+ if (!this.localBrowseRoot) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (this.fileBrowserPath === this.localBrowseRoot) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
const lastSlash = this.fileBrowserPath.lastIndexOf('/');
|
|
|
if (lastSlash > 0) {
|
|
|
- this.fileBrowserPath = this.fileBrowserPath.substring(0, lastSlash);
|
|
|
+ const parent = this.fileBrowserPath.substring(0, lastSlash);
|
|
|
+ if (!parent.startsWith(this.localBrowseRoot)) {
|
|
|
+ this.fileBrowserPath = this.localBrowseRoot;
|
|
|
+ await this.loadLocalFiles(this.localBrowseRoot);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.fileBrowserPath = parent;
|
|
|
await this.loadLocalFiles(this.fileBrowserPath);
|
|
|
}
|
|
|
}
|
|
|
@@ -586,7 +634,7 @@ export struct UploadMusicPage {
|
|
|
/**
|
|
|
* 确认选择文件
|
|
|
*/
|
|
|
- private confirmFileSelection(): void {
|
|
|
+ private async confirmFileSelection(): Promise<void> {
|
|
|
if (this.selectedBrowserItems.size === 0) {
|
|
|
promptAction.showToast({
|
|
|
message: '请至少选择一个项目',
|
|
|
@@ -596,16 +644,28 @@ export struct UploadMusicPage {
|
|
|
}
|
|
|
|
|
|
// 将选中的项目添加到已选列表
|
|
|
- this.selectedBrowserItems.forEach(path => {
|
|
|
- const item = this.browserFiles.find(f => f.path === path);
|
|
|
- if (item) {
|
|
|
- const uri = `file://${path}`;
|
|
|
- this.selectedFiles.push(uri);
|
|
|
- this.selectedFileNames.push(item.name);
|
|
|
- this.selectedFileTypes.push(item.isDirectory ? 'folder' : 'file');
|
|
|
+ const selectedItems: LocalFileItem[] = [];
|
|
|
+ this.selectedBrowserItems.forEach((path) => {
|
|
|
+ const found = this.browserFiles.find((f) => f.path === path);
|
|
|
+ if (found) {
|
|
|
+ selectedItems.push(found);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
+ for (let i = 0; i < selectedItems.length; i++) {
|
|
|
+ const item = selectedItems[i];
|
|
|
+ const uri = `file://${item.path}`;
|
|
|
+ try {
|
|
|
+ await ReqPermissionUtil.persistPermission(uri);
|
|
|
+ } catch (error) {
|
|
|
+ const err = error as Error;
|
|
|
+ Logger.error(TAG, `持久化授权失败: ${err.message}`);
|
|
|
+ }
|
|
|
+ this.selectedFiles.push(uri);
|
|
|
+ this.selectedFileNames.push(item.name);
|
|
|
+ this.selectedFileTypes.push(item.isDirectory ? 'folder' : 'file');
|
|
|
+ }
|
|
|
+
|
|
|
promptAction.showToast({
|
|
|
message: `已添加 ${this.selectedBrowserItems.size} 个项目`,
|
|
|
duration: 2000
|
|
|
@@ -621,6 +681,7 @@ export struct UploadMusicPage {
|
|
|
this.isShowFileBrowser = false;
|
|
|
this.selectedBrowserItems.clear();
|
|
|
this.browserFiles = [];
|
|
|
+ this.localBrowseRoot = '';
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -695,10 +756,28 @@ export struct UploadMusicPage {
|
|
|
*/
|
|
|
private selectUploadAccount(account: WebDavAccount): void {
|
|
|
this.selectedAccount = account;
|
|
|
- this.uploadPath = account.uploadFilePath || '/';
|
|
|
+ this.applyDefaultUploadPath(account);
|
|
|
Logger.info(TAG, `选择账户: ${account.name}, 上传路径: ${this.uploadPath}`);
|
|
|
}
|
|
|
|
|
|
+ private applyDefaultUploadPath(account: WebDavAccount | null): void {
|
|
|
+ if (!account) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const managerAccount = this.webdavManager.currentAccount;
|
|
|
+ const managerPath = this.webdavManager.currentPath;
|
|
|
+ if (
|
|
|
+ managerPath &&
|
|
|
+ managerPath.length > 0 &&
|
|
|
+ managerAccount &&
|
|
|
+ managerAccount.id === account.id
|
|
|
+ ) {
|
|
|
+ this.uploadPath = managerPath;
|
|
|
+ } else {
|
|
|
+ this.uploadPath = account.uploadFilePath || '/';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 打开路径浏览器
|
|
|
*/
|
|
|
@@ -711,8 +790,17 @@ export struct UploadMusicPage {
|
|
|
Logger.info(TAG, '========== 打开路径浏览器 ==========');
|
|
|
Logger.info(TAG, `当前上传路径: ${this.uploadPath}`);
|
|
|
Logger.info(TAG, `选中账户: ${this.selectedAccount.name}`);
|
|
|
+
|
|
|
+ const managerAccount = this.webdavManager.currentAccount;
|
|
|
+ const defaultPath =
|
|
|
+ managerAccount &&
|
|
|
+ managerAccount.id === this.selectedAccount.id &&
|
|
|
+ this.webdavManager.currentPath &&
|
|
|
+ this.webdavManager.currentPath.length > 0
|
|
|
+ ? this.webdavManager.currentPath
|
|
|
+ : this.uploadPath;
|
|
|
|
|
|
- this.currentBrowsePath = this.uploadPath;
|
|
|
+ this.currentBrowsePath = defaultPath;
|
|
|
this.isShowPathBrowser = true;
|
|
|
|
|
|
Logger.info(TAG, `isShowPathBrowser 设置为: ${this.isShowPathBrowser}`);
|
|
|
@@ -933,6 +1021,9 @@ export struct UploadMusicPage {
|
|
|
await this.webdavManager.startUploadQueue();
|
|
|
|
|
|
Logger.info(TAG, '上传任务已启动');
|
|
|
+ this.selectedFiles = [];
|
|
|
+ this.selectedFileNames = [];
|
|
|
+ this.selectedFileTypes = [];
|
|
|
} catch (error) {
|
|
|
const err = error as Error;
|
|
|
Logger.error(TAG, `启动上传失败: ${err.message}`);
|
|
|
@@ -1119,12 +1210,12 @@ export struct UploadMusicPage {
|
|
|
TabContent() {
|
|
|
this.QueueList(this.uploadQueueDataSource, 'pending')
|
|
|
}
|
|
|
- .tabBar(this.TabBarBuilder('⏳', '待上传', this.uploadQueue.length))
|
|
|
+ .tabBar(this.TabBarBuilder('⏳', '待上传', this.pendingCount))
|
|
|
|
|
|
TabContent() {
|
|
|
this.QueueList(this.finishQueueDataSource, 'finished')
|
|
|
}
|
|
|
- .tabBar(this.TabBarBuilder('✅', '已完成', this.finishQueue.length))
|
|
|
+ .tabBar(this.TabBarBuilder('✅', '已完成', this.finishedCount))
|
|
|
}
|
|
|
.width('100%')
|
|
|
.height(300)
|
|
|
@@ -1835,6 +1926,7 @@ export struct UploadMusicPage {
|
|
|
.onClick(() => {
|
|
|
this.openFileBrowser();
|
|
|
})
|
|
|
+
|
|
|
}
|
|
|
.width('100%')
|
|
|
|