@naxodev/opencode-music-player 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.tsx +46 -29
- package/package.json +1 -1
package/index.tsx
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
2
|
import { Plugin } from "@opencode-ai/plugin/tui"
|
|
3
|
-
import { createStore, produce } from "solid-js/store"
|
|
4
3
|
import { createSessionSystemMedia, openNowPlayingApp } from "./system-media.ts"
|
|
5
4
|
import { isMac, mergeArtworkCompletion, type SessionMedia } from "./types.ts"
|
|
6
5
|
import { CompactPlayer, SidebarPlayer, type UiState } from "./ui.tsx"
|
|
7
6
|
|
|
8
7
|
type Context = Plugin.Context
|
|
9
|
-
type SessionStore = UiState
|
|
8
|
+
type SessionStore = UiState & { loadingOwners?: string[] }
|
|
10
9
|
type SeekIntent = {
|
|
11
10
|
positionMs: number
|
|
12
11
|
resolves: Array<() => void>
|
|
@@ -83,14 +82,18 @@ export function createController(
|
|
|
83
82
|
context: Context,
|
|
84
83
|
dependencies: ControllerDependencies = controllerDependencies,
|
|
85
84
|
): Controller {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
const [session, setSession] = context.storage.memory<SessionStore>(
|
|
86
|
+
"music-player.session.v6",
|
|
87
|
+
{
|
|
88
|
+
initial: {
|
|
89
|
+
loading: false,
|
|
90
|
+
loadingOwners: [],
|
|
91
|
+
error: null,
|
|
92
|
+
player: null,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
const loadingOwner = crypto.randomUUID()
|
|
94
97
|
const media = dependencies.createSessionMedia()
|
|
95
98
|
let disposed = false
|
|
96
99
|
let lifecycleGeneration = 0
|
|
@@ -132,12 +135,18 @@ export function createController(
|
|
|
132
135
|
transportError = message
|
|
133
136
|
publishError()
|
|
134
137
|
}
|
|
135
|
-
const
|
|
136
|
-
if (!isActive()) return
|
|
138
|
+
const setLoadingOwner = (active: boolean) => {
|
|
137
139
|
setSession((draft) => {
|
|
138
|
-
|
|
140
|
+
const owners = new Set(draft.loadingOwners ?? [])
|
|
141
|
+
if (active) owners.add(loadingOwner)
|
|
142
|
+
else owners.delete(loadingOwner)
|
|
143
|
+
draft.loadingOwners = [...owners]
|
|
144
|
+
draft.loading = owners.size > 0
|
|
139
145
|
})
|
|
140
146
|
}
|
|
147
|
+
const updateLoading = () => {
|
|
148
|
+
if (isActive()) setLoadingOwner(pending.size > 0)
|
|
149
|
+
}
|
|
141
150
|
const settle = (resolve: () => void) => {
|
|
142
151
|
if (!pending.delete(resolve)) return
|
|
143
152
|
resolve()
|
|
@@ -319,11 +328,7 @@ export function createController(
|
|
|
319
328
|
activeSeek = null
|
|
320
329
|
for (const resolve of [...pending]) settle(resolve)
|
|
321
330
|
void media.dispose().catch(() => {})
|
|
322
|
-
|
|
323
|
-
setSession((draft) => {
|
|
324
|
-
draft.loading = false
|
|
325
|
-
})
|
|
326
|
-
}
|
|
331
|
+
setLoadingOwner(false)
|
|
327
332
|
},
|
|
328
333
|
}
|
|
329
334
|
}
|
|
@@ -404,22 +409,34 @@ export function createMusicPlayerPlugin(options?: {
|
|
|
404
409
|
}
|
|
405
410
|
: controllerDependencies,
|
|
406
411
|
)
|
|
412
|
+
// Slot renderers must observe host-owned state before package components run.
|
|
413
|
+
const observeSession = () => {
|
|
414
|
+
void ctrl.session.loading
|
|
415
|
+
void ctrl.session.error
|
|
416
|
+
void ctrl.session.player
|
|
417
|
+
}
|
|
407
418
|
const unsubApp = context.ui.slot({
|
|
408
419
|
append: "session.composer.top",
|
|
409
|
-
render: () =>
|
|
420
|
+
render: () => {
|
|
421
|
+
observeSession()
|
|
422
|
+
return <AppHost context={context} ctrl={ctrl} />
|
|
423
|
+
},
|
|
410
424
|
})
|
|
411
425
|
const unsubSidebar = context.ui.slot({
|
|
412
426
|
append: "sidebar.content",
|
|
413
|
-
render: () =>
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
427
|
+
render: () => {
|
|
428
|
+
observeSession()
|
|
429
|
+
return (
|
|
430
|
+
<SidebarPlayer
|
|
431
|
+
context={context}
|
|
432
|
+
state={ctrl.session}
|
|
433
|
+
onPlayPause={() => void ctrl.playPause()}
|
|
434
|
+
onNext={() => void ctrl.next()}
|
|
435
|
+
onPrev={() => void ctrl.prev()}
|
|
436
|
+
onSeek={(positionMs) => void ctrl.seek(positionMs)}
|
|
437
|
+
/>
|
|
438
|
+
)
|
|
439
|
+
},
|
|
423
440
|
})
|
|
424
441
|
return () => {
|
|
425
442
|
unsubApp()
|