Forráskód Böngészése

refactor(player): route controller through coordinator

onecold 4 hónapja
szülő
commit
40963bb9ff

+ 86 - 4
entry/src/main/ets/controller/MusicPlaybackController.ets

@@ -1,3 +1,11 @@
+import { emitter } from '@kit.BasicServicesKit'
+import { EventConstants } from '../common/constants/EventConstants'
+import { buildPlaylistDispatchFilePaths } from '../common/util/PlaylistPlayDispatchHelper'
+import { PlaylistPlayRequest, savePendingPlaylistPlay } from '../common/util/PlaylistPlayRequestStore'
+import { setFindPlaylist } from '../common/util/FindPlaylistStore'
+import { PlaybackCoordinator } from './PlaybackCoordinator'
+import { VideoItem } from '../viewmodel/VideoItem'
+
 export interface MusicPlaybackControllerActions {
   playOrPause: () => void | Promise<void>
   playNext: () => void | Promise<void>
@@ -6,6 +14,15 @@ export interface MusicPlaybackControllerActions {
   seekTo: (value: string, source?: string) => void | Promise<void>
 }
 
+export interface InMemoryPlaylistPlaybackOptions {
+  playlistId: string
+  playlistName: string
+  songs: VideoItem[]
+  startIndex: number
+  isJump?: boolean
+  playType?: number
+}
+
 export interface LoopModeResolution {
   playType: number
   toastText: string
@@ -53,6 +70,7 @@ export type ItemPlaybackToggleAction = 'toggle_current' | 'play_target'
 export class MusicPlaybackController {
   private static instance?: MusicPlaybackController
   private actions?: MusicPlaybackControllerActions
+  private playbackCoordinator: PlaybackCoordinator = PlaybackCoordinator.getInstance()
 
   public static getInstance(): MusicPlaybackController {
     if (!MusicPlaybackController.instance) {
@@ -241,6 +259,23 @@ export class MusicPlaybackController {
     return 'play_target'
   }
 
+  public static buildInMemoryPlaylistPlayRequest(options: InMemoryPlaylistPlaybackOptions): PlaylistPlayRequest {
+    const songs = options.songs ?? []
+    const playlistId = options.playlistId.indexOf('find-') === 0 ? options.playlistId : `find-${options.playlistId}`
+    const maxIndex = Math.max(songs.length - 1, 0)
+    const safeStartIndex = songs.length <= 0 ? 0 : Math.max(0, Math.min(options.startIndex, maxIndex))
+
+    return new PlaylistPlayRequest(
+      playlistId,
+      options.playlistName,
+      songs.length,
+      safeStartIndex,
+      buildPlaylistDispatchFilePaths(playlistId, songs),
+      options.isJump,
+      options.playType
+    )
+  }
+
   public setActions(actions: MusicPlaybackControllerActions): void {
     this.actions = actions
   }
@@ -251,16 +286,48 @@ export class MusicPlaybackController {
     }
   }
 
+  public async playSong(song: VideoItem, source: string = 'controller'): Promise<void> {
+    await this.playbackCoordinator.playSong(song, source)
+  }
+
+  public async playQueue(queue: VideoItem[], startIndex: number, source: string = 'controller'): Promise<void> {
+    await this.playbackCoordinator.playQueue(queue, startIndex, source)
+  }
+
+  public async playOrPauseDirect(): Promise<void> {
+    await this.playbackCoordinator.playOrPause()
+  }
+
+  public async playNextDirect(): Promise<void> {
+    await this.playbackCoordinator.playNext()
+  }
+
+  public async playPreviousDirect(): Promise<void> {
+    await this.playbackCoordinator.playPrevious()
+  }
+
   public playOrPause(): void {
-    this.actions?.playOrPause()
+    if (this.actions) {
+      this.actions.playOrPause()
+      return
+    }
+    void this.playbackCoordinator.playOrPause()
   }
 
   public async playNext(): Promise<void> {
-    await this.actions?.playNext?.()
+    if (this.actions) {
+      await this.actions.playNext?.()
+      return
+    }
+    await this.playNextDirect()
   }
 
   public async playPrevious(): Promise<void> {
-    await this.actions?.playPrevious?.()
+    if (this.actions) {
+      await this.actions.playPrevious?.()
+      return
+    }
+    await this.playPreviousDirect()
   }
 
   public async setLoopMode(): Promise<void> {
@@ -268,6 +335,21 @@ export class MusicPlaybackController {
   }
 
   public async seekTo(value: string, source?: string): Promise<void> {
-    await this.actions?.seekTo?.(value, source)
+    if (this.actions) {
+      await this.actions.seekTo?.(value, source)
+      return
+    }
+    await this.playbackCoordinator.seekTo(value, source)
+  }
+
+  public playInMemoryPlaylist(options: InMemoryPlaylistPlaybackOptions): void {
+    if (!options.songs || options.songs.length <= 0) {
+      return
+    }
+
+    const request = MusicPlaybackController.buildInMemoryPlaylistPlayRequest(options)
+    setFindPlaylist(request.playlistId, request.playlistName, options.songs, request.startIndex)
+    savePendingPlaylistPlay(request)
+    emitter.emit({ eventId: EventConstants.EVENT_PLAYLIST_PLAY }, { data: request })
   }
 }

+ 61 - 0
entry/src/ohosTest/ets/test/MusicPlaybackController.test.ets

@@ -1,8 +1,47 @@
 import { describe, expect, it } from '@ohos/hypium'
 import { MusicPlaybackController } from '../../../main/ets/controller/MusicPlaybackController'
+import { PlaybackCoordinator } from '../../../main/ets/controller/PlaybackCoordinator'
+import { VideoItem } from '../../../main/ets/viewmodel/VideoItem'
 
 export default function musicPlaybackControllerTest() {
   describe('MusicPlaybackControllerTest', () => {
+    it('controllerPlayQueueUsesCoordinatorRuntimeWithoutActions', 0, async () => {
+      const controller = MusicPlaybackController.getInstance()
+      const coordinator = PlaybackCoordinator.getInstance()
+      const calls: string[] = []
+      const songs: VideoItem[] = [
+        new VideoItem('Song A', '1', '/music/a.flac', 0, 0, '2026-04-02'),
+        new VideoItem('Song B', '2', '/music/b.flac', 0, 0, '2026-04-02')
+      ]
+
+      controller.clearActions()
+      coordinator.clearRuntime()
+      coordinator.setRuntime({
+        playQueue: async (_queue, startIndex, source) => {
+          calls.push(`playQueue:${startIndex}:${source}`)
+        },
+        playOrPause: async () => {
+          calls.push('playOrPause')
+        },
+        playNext: async () => {
+          calls.push('playNext')
+        },
+        playPrevious: async () => {
+          calls.push('playPrevious')
+        },
+        seekTo: async (value, source) => {
+          calls.push(`seekTo:${value}:${source ?? ''}`)
+        }
+      })
+
+      await controller.playQueue(songs, 1, 'charts-count')
+      await controller.playOrPauseDirect()
+      await controller.seekTo('88', 'controller-test')
+
+      expect(calls.join(',')).assertEqual('playQueue:1:charts-count,playOrPause,seekTo:88:controller-test')
+      coordinator.clearRuntime()
+    })
+
     it('dispatchRegisteredActions', 0, async () => {
       const controller = MusicPlaybackController.getInstance()
       const calls: string[] = []
@@ -244,5 +283,27 @@ export default function musicPlaybackControllerTest() {
       expect(MusicPlaybackController.resolveItemPlaybackToggleAction('/a.flac', '/b.flac', true, true))
         .assertEqual('toggle_current')
     })
+
+    it('buildInMemoryPlaylistPlayRequestUsesFindPayload', 0, () => {
+      const songs: VideoItem[] = [
+        new VideoItem('Song A', '1', '/music/a.flac', 0, 0, '2026-04-02'),
+        new VideoItem('Song B', '2', '/music/b.flac', 0, 0, '2026-04-02')
+      ]
+
+      const request = MusicPlaybackController.buildInMemoryPlaylistPlayRequest({
+        playlistId: 'charts-count-playlist',
+        playlistName: '听歌次数排行榜',
+        songs,
+        startIndex: 99,
+        isJump: true
+      })
+
+      expect(request.playlistId).assertEqual('find-charts-count-playlist')
+      expect(request.playlistName).assertEqual('听歌次数排行榜')
+      expect(request.songCount).assertEqual(2)
+      expect(request.startIndex).assertEqual(1)
+      expect(request.songFilePaths.length).assertEqual(0)
+      expect(request.isJump).assertTrue()
+    })
   })
 }