Przeglądaj źródła

新建webdav账号对话框

onecold 9 miesięcy temu
rodzic
commit
60cb9f60fc

+ 190 - 0
entry/src/main/ets/dialog/WebDavAccountDialog.ets

@@ -0,0 +1,190 @@
+import { ToastUtil } from '@pura/harmony-utils';
+import { CommonConstants } from '../common/constants/CommonConstants';
+import { WebDavAccount } from '../viewmodel/WebDavAccount';
+
+// WebDAV账户对话框
+@Component
+export struct WebDavAccountDialog {
+  @Prop isEditMode: boolean = false;
+  @Prop account: WebDavAccount;
+  onConfirm?: (account: WebDavAccount) => void;
+  onCancel?: () => void;
+  @State accountName: string = 'demo';
+  @State host: string = 'myhome.ss5.xyz';
+  @State port: number = 5005;
+  @State filepath: string = '/';
+  @State username: string = 'chendeben';
+  @State password: string = 'chen384626WYT';
+  @State enableHttps: boolean = false;
+  @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
+
+  aboutToAppear(): void {
+    if(this.isEditMode){
+      this.accountName = this.account.name;
+      this.host = this.account.host;
+      this.port = this.account.port;
+      this.filepath = this.account.filepath;
+      this.username = this.account.account;
+      this.password = this.account.password;
+      this.enableHttps = this.account.enableHttps;
+    }
+
+  }
+
+  build() {
+    Column({ space: 16 }) {
+      // 标题
+      Text(this.isEditMode ? '编辑账户' : '添加账户')
+        .fontSize(18)
+        .fontWeight(FontWeight.Bold)
+        .fontColor($r('app.color.index_tab_font_color'))
+
+      // 账户名称
+      Row({ space: 8 }) {
+        Text('名称')
+          .fontSize(14)
+          .fontColor($r('app.color.index_tab_font_color'))
+        TextArea({ placeholder: '请输入账户名称', text: this.accountName })
+          .layoutWeight(1)
+          .maxLines(1)
+          .onChange((value: string) => {
+            this.accountName = value;
+          })
+      }
+      .width('100%')
+      .alignItems(VerticalAlign.Center)
+
+      // 服务器地址
+      Row({ space: 8 }) {
+        Text('服务器')
+          .fontSize(14)
+          .maxLines(2)
+          .fontColor($r('app.color.index_tab_font_color'))
+        TextArea({ placeholder: '例如: example.com', text: this.host })
+          .layoutWeight(1)
+          .onChange((value: string) => {
+            this.host = value;
+          })
+      }
+      .alignItems(VerticalAlign.Center)
+
+      // 端口
+      Row({ space: 8 }) {
+        Text('端口')
+          .fontSize(14)
+          .fontColor($r('app.color.index_tab_font_color'))
+        TextInput({ placeholder: '默认: 80', text: this.port.toString() })
+          .layoutWeight(1)
+          .maxLines(1)
+          .type(InputType.Number)
+          .onChange((value: string) => {
+            this.port = parseInt(value) || 80;
+          })
+      }
+      .alignItems(VerticalAlign.Center)
+
+      // 文件目录
+      Row({ space: 8 }) {
+        Text('文件目录')
+          .fontSize(14)
+          .fontColor($r('app.color.index_tab_font_color'))
+        TextInput({ placeholder: '例如: /music', text: this.filepath })
+          .layoutWeight(1)
+          .maxLines(1)
+          .onChange((value: string) => {
+            this.filepath = value;
+          })
+      }
+      .alignItems(VerticalAlign.Center)
+
+      // 用户名
+      Row({ space: 8 }) {
+        Text('用户名')
+          .fontSize(14)
+          .fontColor($r('app.color.index_tab_font_color'))
+        TextInput({ placeholder: '请输入用户名', text: this.username })
+          .layoutWeight(1)
+          .maxLines(1)
+          .onChange((value: string) => {
+            this.username = value;
+          })
+      }
+      .alignItems(VerticalAlign.Center)
+
+      // 密码
+      Row({ space: 8 }) {
+        Text('密码')
+          .fontSize(14)
+          .fontColor($r('app.color.index_tab_font_color'))
+        TextInput({ placeholder: '请输入密码', text: this.password })
+          .type(InputType.Password)
+          .layoutWeight(1)
+          .maxLines(2)
+          .onChange((value: string) => {
+            this.password = value;
+          })
+      }
+      .alignItems(VerticalAlign.Center)
+
+      // HTTPS开关
+      Row() {
+        Text('启用HTTPS')
+          .fontSize(14)
+          .fontColor($r('app.color.index_tab_font_color'))
+        Blank()
+        Toggle({ type: ToggleType.Switch, isOn: this.enableHttps })
+          .selectedColor(this.themeColor)
+          .onChange((isOn: boolean) => {
+            this.enableHttps = isOn;
+          })
+      }
+      .width('100%')
+
+      // 按钮
+      Row({ space: 12 }) {
+        Button('取消', { type: ButtonType.Capsule })
+          .backgroundColor($r('app.color.input_background'))
+          .fontColor($r('app.color.index_tab_font_color'))
+          .layoutWeight(1)
+          .onClick(() => {
+            this.onCancel?.();
+          })
+
+        Button(this.isEditMode ? '保存' : '添加', { type: ButtonType.Capsule })
+          .backgroundColor(this.themeColor)
+          .layoutWeight(1)
+          .onClick(() => {
+            if (!this.accountName || !this.host) {
+              ToastUtil.showToast('请填写账户名称和服务器地址');
+              return;
+            }
+
+            const updatedAccount = new WebDavAccount();
+            updatedAccount.id = this.account.id;
+            updatedAccount.name = this.accountName;
+            updatedAccount.host = this.host;
+            updatedAccount.port = this.port;
+            updatedAccount.filepath = this.filepath;
+            updatedAccount.account = this.username;
+            updatedAccount.password = this.password;
+            updatedAccount.enableHttps = this.enableHttps;
+            updatedAccount.isActivate = true;
+            updatedAccount.localHost = '';
+            updatedAccount.isUseLocalHost = false;
+            updatedAccount.lyricFilePath = '';
+            updatedAccount.uploadFilePath = '';
+            updatedAccount.imageFilePath = '';
+
+            this.onConfirm?.(updatedAccount);
+            // this.controller.close();
+          })
+      }
+      .width('100%')
+      .margin({ top: 8 })
+    }
+    .padding(24)
+    .width('90%')
+    .backgroundColor($r('app.color.start_window_background'))
+    .borderRadius(16)
+  }
+}

+ 281 - 28
entry/src/main/ets/pages/NewIndex.ets

@@ -1,6 +1,10 @@
 import { AppUtil, ArrayUtil, DeviceUtil, DisplayUtil, LogUtil, PreferencesUtil, ToastUtil } from '@pura/harmony-utils';
 import TitleBar from '../view/TitleBar';
-import { curves, LengthMetrics, router, SegmentButton, SegmentButtonOptions, SymbolGlyphModifier } from '@kit.ArkUI';
+import { curves,
+  ImmersiveMode,
+  LengthMetrics,
+  LevelMode,
+  router, SegmentButton, SegmentButtonOptions, SymbolGlyphModifier } from '@kit.ArkUI';
 import mainViewModel, { MainViewModel } from '../viewmodel/MainViewModel';
 import ItemData from '../viewmodel/ItemData';
 import type { sysResource } from '../viewmodel/ItemData';
@@ -41,6 +45,9 @@ import MediaTable from '../common/util/MediaTable';
 import { showCreatePlaylistDialog } from '../dialog/PlaylistDialog';
 import { ImagePickerUtil } from '../common/util/ImagePickerUtil';
 import { WebDavMainPage } from './WebDavMainPage';
+import { WebDavAccount } from '../viewmodel/WebDavAccount';
+import { WebdavManager } from '../common/util/WebdavManager';
+import { WebDavAccountDialog } from '../dialog/WebDavAccountDialog';
 
 // import { FFmpeg, FFProgressMessageParser } from '@sj/ffmpeg';
 
@@ -170,6 +177,10 @@ struct NewIndex {
   @State selectedPlaylist: Playlist | null = null
   private playlistTable: PlaylistTable | null = null
 
+  // WebDAV账户相关状态变量
+  @State webDavAccounts: WebDavAccount[] = []
+  private webdavManager: WebdavManager = WebdavManager.getInstance()
+
   /**
    * 返回键处理逻辑:
    * - 如果不是根目录或有历史记录,发送广播通知更新列表
@@ -218,9 +229,11 @@ struct NewIndex {
 
 
   onPageShow() {
-    LogUtil.info('heanup NewIndex', 'onPageShow 被调用,刷新歌单列表')
+    LogUtil.info('heanup NewIndex', 'onPageShow 被调用,刷新歌单列表和WebDAV账户列表')
     // 加载歌单列表
     this.loadPlaylistList()
+    // 加载WebDAV账户列表
+    this.loadWebDavAccounts()
   }
   /**
    * 页面显示生命周期钩子
@@ -252,6 +265,13 @@ struct NewIndex {
       this.videoLocalList = []
       LogUtil.info('heanup NewIndex', '路由参数中没有播放列表,使用空数组')
     }
+
+    // 检查是否从WebDavPage返回
+    if (params && params.fromWebDavPage) {
+      LogUtil.info('heanup NewIndex', '从WebDavPage返回,切换到网盘标签页')
+      this.mType = 6
+      this.tabSelectedIndexes = [2] // 切换到网盘标签
+    }
     // Utility.setStatusBarLight()
     ScreenUtil.setScreenSize();
     this.bundleName = AppUtil.getBundleName()
@@ -298,6 +318,9 @@ struct NewIndex {
     // 初始化歌单数据库
     await this.initPlaylistTable();
 
+    // 初始化WebDAV管理器
+    await this.initWebDavManager();
+
     // 监听歌单刷新事件
     emitter.on({ eventId: EventConstants.EVENT_PLAYLIST_REFRESH }, (eventData: emitter.EventData) => {
       LogUtil.info('heanup NewIndex', '收到歌单刷新事件,开始刷新歌单列表')
@@ -333,10 +356,14 @@ struct NewIndex {
     this.breakpointSystem.unregister();
     emitter.off(EventConstants.EVENT_SWIPE_BACK_UPDATE);
     emitter.off(EventConstants.EVENT_USER_STATE_CHANGE);
-    
+
     // 监听歌单刷新事件
     emitter.off(EventConstants.EVENT_PLAYLIST_REFRESH);
 
+    // 清理WebDAV管理器订阅
+    if (this.webdavManager) {
+      this.webdavManager.observers = [];
+    }
   }
 
   build() {
@@ -367,7 +394,7 @@ struct NewIndex {
           AboutPage()
             .visibility(this.mType === 5 ? Visibility.Visible : Visibility.None)
 
-          WebDavMainPage()
+          WebDavMainPage({mType:this.mType})
             .visibility(this.mType === 6 ? Visibility.Visible : Visibility.None)
           
           // 抽屉打开时的遮罩层,用于拦截点击事件  这个只能正常尺寸的手机竖屏的才能生效
@@ -656,7 +683,7 @@ struct NewIndex {
         }else if(this.tabSelectedIndexes[0]==1){//歌单
           this.buildPlaylistTab()
         }else if(this.tabSelectedIndexes[0]==2){//网盘
-          this.buildWebDavTab()
+          this.buildCloudStorageTab()
         }
 
       }
@@ -1130,27 +1157,105 @@ struct NewIndex {
   }
 
   /**
-   * 构建WebDAV网盘tab内容
+   * 构建网盘tab内容 - 从数据库获取所有网盘账户
+   * 支持多种类型的网盘账户(目前支持WebDAV,将来可扩展其他类型)
    */
   @Builder
-  buildWebDavTab() {
+  buildCloudStorageTab() {
+    // 当前只支持WebDAV账户,将来可以在这里添加其他类型的网盘账户
+    // 例如:OneDrive, Google Drive, Dropbox等
+
+    // 显示所有WebDAV账户
+    ForEach(this.webDavAccounts, (account: WebDavAccount) => {
+      ListItem() {
+        Button({ type: ButtonType.Capsule, stateEffect: true }) {
+          Row() {
+            // 网盘类型图标(目前只有WebDAV,将来可扩展其他类型)
+            Image($r('app.media.cloudDisk'))
+              .width(22)
+              .height(22)
+              .margin({ left: 25 })
+              .fillColor(this.themeColor)
+
+            Column() {
+              // 账户名称
+              Text(account.name)
+                .margin({ left: 10, right: 20 })
+                .fontSize(15)
+                .fontColor(account.isActivate ? this.themeColor : $r('app.color.index_tab_font_color'))
+                .fontWeight(480)
+                .maxLines(1)
+                .textOverflow({ overflow: TextOverflow.Ellipsis })
+
+              Row() {
+                // 账户类型标签
+                Text('WebDAV')
+                  .fontSize(10)
+                  .fontColor(this.themeColor)
+                  .opacity(0.8)
+                  .backgroundColor($r('app.color.left_draw_bg'))
+                  .padding({ left: 6, right: 6, top: 2, bottom: 2 })
+                  .borderRadius(3)
+                  .margin({ right: 8 })
+
+                // 服务器地址
+                Text(`${account.isUseLocalHost ? account.localHost : account.host}:${account.port}`)
+                  .fontSize(12)
+                  .fontColor($r('app.color.index_tab_font_color'))
+                  .opacity(0.7)
+                  .maxLines(1)
+                  .textOverflow({ overflow: TextOverflow.Ellipsis })
+              }
+            }
+            .alignItems(HorizontalAlign.Start)
+
+            Blank()
+
+            // 激活状态
+            if (account.isActivate) {
+              Text('已激活')
+                .fontSize(12)
+                .fontColor(this.themeColor)
+                .margin({ right: 10 })
+            }
+
+            Image($r('app.media.arrow_right'))
+              .width(22)
+              .height(22)
+              .margin({ left: 20, right: 0 })
+              .align(Alignment.Center)
+          }
+          .width('100%')
+          .height(55)
+        }
+        .backgroundColor(Color.Transparent)
+        .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
+        .onClick(() => {
+          console.info('heanup', '点击WebDAV账户:', account.name)
+          this.selectWebDavAccount(account)
+        })
+      }
+    })
+
+    // 添加新账户按钮
     ListItem() {
       Button({ type: ButtonType.Capsule, stateEffect: true }) {
         Row() {
-          Image($r('app.media.cloudDisk'))
-            .width(22)
-            .height(22)
+          SymbolGlyph($r('sys.symbol.plus_circle'))
+            .fontSize(22)
+            .fontColor([this.themeColor])
+            .effectStrategy(SymbolEffectStrategy.HIERARCHICAL)
+            .alignSelf(ItemAlign.Center)
             .margin({ left: 25 })
-            .fillColor(this.themeColor)
-          
-          Text('WebDAV网盘')
+
+          Text('添加WebDAV账户')
             .margin({ left: 10, right: 20 })
             .fontSize(15)
             .fontColor($r('app.color.index_tab_font_color'))
             .fontWeight(480)
-          
+
           Blank()
-          
+
           Image($r('app.media.arrow_right'))
             .width(22)
             .height(22)
@@ -1163,20 +1268,22 @@ struct NewIndex {
       .backgroundColor(Color.Transparent)
       .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
       .onClick(() => {
-        console.info('heanup', '点击WebDAV网盘菜单')
-        this.mType = 6
-        this.doShowDrawer()
+        console.info('heanup', '点击添加WebDAV账户')
+        this.showAddWebDavAccountDialog()
       })
     }
-    
-    ListItem() {
-      Text('暂无WebDAV账户,请在首页设置中添加')
-        .fontSize(14)
-        .fontColor($r('app.color.index_tab_font_color'))
-        .opacity(0.6)
-        .textAlign(TextAlign.Center)
-        .width('100%')
-        .padding(20)
+
+    // 如果没有账户,显示提示信息
+    if (this.webDavAccounts.length === 0) {
+      ListItem() {
+        Text('暂无WebDAV账户,点击上方按钮添加')
+          .fontSize(14)
+          .fontColor($r('app.color.index_tab_font_color'))
+          .opacity(0.6)
+          .textAlign(TextAlign.Center)
+          .width('100%')
+          .padding(20)
+      }
     }
   }
 
@@ -1316,7 +1423,7 @@ struct NewIndex {
       if (this.playlistTable) {
         const playlists = await this.playlistTable.queryAllPlaylists()
         // 强制触发UI更新
-        this.playlistList = [...playlists]
+        this.playlistList = playlists.slice()
         LogUtil.info('heanup NewIndex', `成功加载 ${playlists.length} 个歌单`)
         playlists.forEach((playlist, index) => {
           LogUtil.info('heanup NewIndex', `歌单${index + 1}: ${playlist.name}, 歌曲数: ${playlist.songCount}`)
@@ -1328,8 +1435,154 @@ struct NewIndex {
       LogUtil.error('heanup NewIndex', `加载歌单列表失败: ${(error as Error).message}`)
     }
   }
+
+  /**
+   * 初始化WebDAV管理器
+   */
+  async initWebDavManager() {
+    try {
+      // 设置WebDAV管理器的上下文
+      this.webdavManager.setContext(this.context)
+
+      // 创建WebDAV账户表
+      await this.webdavManager.createWebDavTableInDB()
+
+      // 订阅WebDAV管理器事件
+      this.webdavManager.subscribe((event: string) => {
+        LogUtil.info('heanup NewIndex', '收到WebDAV事件:', event)
+        if (event === 'QueryAccountsSucceed') {
+          this.loadWebDavAccounts()
+        }
+      })
+
+      // 加载WebDAV账户
+      await this.loadWebDavAccounts()
+
+      LogUtil.info('heanup NewIndex', 'WebDAV管理器初始化成功')
+    } catch (error) {
+      LogUtil.error('heanup NewIndex', `初始化WebDAV管理器失败: ${(error as Error).message}`)
+    }
+  }
+
+  /**
+   * 加载WebDAV账户列表
+   */
+  async loadWebDavAccounts() {
+    try {
+      LogUtil.info('heanup NewIndex', '开始加载WebDAV账户列表')
+      await this.webdavManager.queryWebDavAccountsFromDB()
+      // 强制触发UI更新
+      this.webDavAccounts = this.webdavManager.getAllWebDavAccounts().slice()
+      LogUtil.info('heanup NewIndex', `成功加载 ${this.webDavAccounts.length} 个WebDAV账户`)
+      this.webDavAccounts.forEach((account, index) => {
+        LogUtil.info('heanup NewIndex', `WebDAV账户${index + 1}: ${account.name}, 激活状态: ${account.isActivate}`)
+      })
+    } catch (error) {
+      LogUtil.error('heanup NewIndex', `加载WebDAV账户列表失败: ${(error as Error).message}`)
+    }
+  }
+
+  /**
+   * 选择WebDAV账户
+   */
+  selectWebDavAccount(account: WebDavAccount) {
+    try {
+      LogUtil.info('heanup NewIndex', '选择WebDAV账户:', account.name)
+
+      // 如果账户未激活,先激活它
+      if (!account.isActivate) {
+        // 先将所有账户设为未激活
+        this.webDavAccounts.forEach(acc => {
+          acc.isActivate = false
+        })
+
+        // 激活选中的账户
+        account.isActivate = true
+
+        // 更新数据库中的激活状态
+        this.webdavManager.editAccount(account).then(() => {
+          LogUtil.info('heanup NewIndex', 'WebDAV账户激活成功:', account.name)
+          // 重新加载账户列表
+          this.loadWebDavAccounts()
+        }).catch((error: Error) => {
+          LogUtil.error('heanup NewIndex', `激活WebDAV账户失败: ${error.message}`)
+          ToastUtil.showToast('激活账户失败')
+        })
+      }
+
+      // 切换到WebDAV页面
+      this.mType = 6
+      this.doShowDrawer()
+    } catch (error) {
+      LogUtil.error('heanup NewIndex', `选择WebDAV账户失败: ${(error as Error).message}`)
+      ToastUtil.showToast('选择账户失败')
+    }
+  }
+
+  /**
+   * 显示添加WebDAV账户对话框
+   */
+  @State addDavDialogId:number = 1
+  showAddWebDavAccountDialog() {
+
+    const node: FrameNode | null = this.getUIContext().getFrameNodeById("test_text") || null;
+    this.getUIContext().getPromptAction().openCustomDialog({
+      builder: () => {
+        this.webDavAccountBuilder()
+      },
+      levelMode: LevelMode.EMBEDDED, // 启用页面级弹出框
+      levelUniqueId: node?.getUniqueId(), // 设置页面级弹出框所在页面的任意节点ID
+      immersiveMode: ImmersiveMode.EXTEND, // 设置页面级弹出框蒙层的显示模式
+    }).then((dialogId: number) => {
+      this.addDavDialogId = dialogId;
+    })
+
+  }
+
+  @Builder
+  webDavAccountBuilder() {
+     WebDavAccountDialog({
+       isEditMode: false,
+       account: new WebDavAccount(),
+       onCancel: () => {
+         // 取消添加
+         this.getUIContext().getPromptAction().closeCustomDialog(this.addDavDialogId)
+       },
+       onConfirm: (account: WebDavAccount) => {
+         this.getUIContext().getPromptAction().closeCustomDialog(this.addDavDialogId)
+         this.webdavManager.insertAccount(
+           account.name,
+           account.host,
+           account.localHost,
+           account.isUseLocalHost,
+           account.port,
+           account.filepath,
+           account.lyricFilePath,
+           account.uploadFilePath,
+           account.imageFilePath,
+           account.account,
+           account.password,
+           account.enableHttps
+         ).then(() => {
+           ToastUtil.showToast('添加成功')
+           // 重新加载WebDAV账户列表
+           this.loadWebDavAccounts()
+           LogUtil.info('heanup NewIndex', 'WebDAV账户添加成功:', account.name)
+         }).catch((error: Error) => {
+           LogUtil.error('heanup NewIndex', `添加WebDAV账户失败: ${error.message}`)
+           ToastUtil.showToast('添加失败')
+         })
+       }
+
+     });
+
+  }
+
 }
 
+
+
+
 // 1. 工具函数:将 #RRGGBB 字符串和透明度转为 'rgba(r,g,b,a)' 字符串,深色模式下可返回深色变体
 function themeColorWithAlpha(themeColor: string, alpha: number, isDarkMode: boolean = false): string {
   if (isDarkMode) {

+ 7 - 3
entry/src/main/ets/pages/WebDavMainPage.ets

@@ -56,6 +56,7 @@ export struct WebDavMainPage {
   @State accounts: WebDavAccount[] = [];
   @State selectedAccount: WebDavAccount | null = null;
   @State songs: Song[] = [];
+  @Link mType: number;
   @State isLoading: boolean = false;
   @State webDavFiles: FileInfo[] = []; // 直接在页面中保存文件列表副本
   @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
@@ -455,8 +456,11 @@ export struct WebDavMainPage {
             .height(24)
             .margin({ left: 12, right: 8 })
             .onClick(() => {
-              router.back();
-            })
+              this.getUIContext()?.animateTo({ duration: 555 }, () => {
+                this.mType =0
+              })
+              });
+
 
           Text('WebDAV网盘')
             .fontSize(18)
@@ -673,7 +677,7 @@ export struct WebDavMainPage {
   @Builder
   buildFolderItem(folder: FileInfo) {
     Row({ space: 2 }) {
-      Image($r('app.media.folder'))
+      Image($r('app.media.dir'))
         .width(32)
         .height(32)
         .fillColor(this.themeColor)