Skip to content

Commit a2a8cd3

Browse files
committed
Switch to new FilteredSubscription
1 parent edd5f8b commit a2a8cd3

4 files changed

Lines changed: 116 additions & 104 deletions

File tree

internal/app/component/miniwave/miniwave.go

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ type MiniWaveformComponent struct {
3939
normalizeFactor float32
4040
lastCacheRequestTime float64
4141

42-
eventSub chan events.Event
42+
filteredEventSub *eventbus.FilteredSubscription
4343
}
4444

4545
// NewMiniWaveform creates a new waveform component
@@ -54,37 +54,42 @@ func NewMiniWaveform(id imgui.ID, path string) *MiniWaveformComponent {
5454
lastCachedColormap: theme.GetCurrentColormap(),
5555
normalizeFactor: 1.0,
5656
lastCacheRequestTime: 0.0,
57-
eventSub: make(chan events.Event, 10),
5857
}
5958

6059
cmp.Component = component.NewComponent[*MiniWaveformComponent](id, cmp.handleUpdate)
6160
cmp.Component.SetLayoutBuilder(cmp)
6261

63-
// Subscribe to all load events. drainEvents will filter by path.
62+
// Subscribe to all load events using filtered subscription
6463
bus := eventbus.Bus
6564
uuid := cmp.UUID()
66-
bus.Subscribe(events.AudioMetadataLoadedKey, uuid, cmp.eventSub)
67-
bus.Subscribe(events.AudioSamplesLoadedKey, uuid, cmp.eventSub)
68-
bus.Subscribe(events.AudioLoadFailedKey, uuid, cmp.eventSub)
65+
cmp.filteredEventSub = eventbus.NewFilteredSubscription(uuid, 10)
66+
cmp.filteredEventSub.SubscribeMultiple(
67+
bus,
68+
events.AudioMetadataLoadedKey,
69+
events.AudioSamplesLoadedKey,
70+
events.AudioLoadFailedKey,
71+
)
6972

7073
return cmp
7174
}
7275

7376
// drainEvents reads from the event bus subscription channel and translates relevant events into local commands.
7477
func (mw *MiniWaveformComponent) drainEvents() {
75-
for {
76-
select {
77-
case event := <-mw.eventSub:
78-
// Check if it's an audio load event
79-
if e, ok := event.(events.AudioLoadEventRecord); ok {
80-
// Check if it's for the file this component cares about
81-
if e.Path == mw.path {
82-
mw.SendUpdate(component.UpdateCmd{Type: cmdUpdateStateFromCache})
78+
if mw.filteredEventSub != nil {
79+
for {
80+
select {
81+
case event := <-mw.filteredEventSub.Events():
82+
// Check if it's an audio load event
83+
if e, ok := event.(events.AudioLoadEventRecord); ok {
84+
// Check if it's for the file this component cares about
85+
if e.Path == mw.path {
86+
mw.SendUpdate(component.UpdateCmd{Type: cmdUpdateStateFromCache})
87+
}
8388
}
89+
default:
90+
// No more events
91+
return
8492
}
85-
default:
86-
// No more events
87-
return
8893
}
8994
}
9095
}
@@ -109,9 +114,6 @@ func (mw *MiniWaveformComponent) updateStateFromCache() {
109114
mw.isReady = true
110115
mw.loadFailed = snapshot.LoadErr != nil
111116
// Mark cache as invalid so Layout() will rebuild it
112-
if mw.cacheValid {
113-
log.Debug("Invalidating cache due to new data", zap.String("path", mw.path))
114-
}
115117
mw.cacheValid = false
116118
} else if snapshot.LoadErr != nil {
117119
mw.loadFailed = true
@@ -416,12 +418,10 @@ func (mw *MiniWaveformComponent) renderPlaceholder(width, height float32) {
416418

417419
// Destroy cleans up the component
418420
func (mw *MiniWaveformComponent) Destroy() {
419-
// Unsubscribe from all events
420-
bus := eventbus.Bus
421-
uuid := mw.UUID()
422-
bus.Unsubscribe(events.AudioMetadataLoadedKey, uuid)
423-
bus.Unsubscribe(events.AudioSamplesLoadedKey, uuid)
424-
bus.Unsubscribe(events.AudioLoadFailedKey, uuid)
421+
// Unsubscribe from filtered subscriptions (handles all event types)
422+
if mw.filteredEventSub != nil {
423+
mw.filteredEventSub.Unsubscribe()
424+
}
425425

426426
// Call the base component's destroy method
427427
mw.Component.Destroy()

internal/app/component/waveform/waveform_component.go

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ type WaveComponent struct {
4545
repeatMode int
4646
repeatSliceIdx int
4747

48-
emptyText string
49-
eventSub chan events.Event
48+
emptyText string
49+
filteredEventSub *eventbus.FilteredSubscription
5050
}
5151

5252
// NewWaveformComponent constructor
@@ -72,47 +72,52 @@ func NewWaveformComponent(id imgui.ID) *WaveComponent {
7272
implot.AxisFlagsNoHighlight |
7373
implot.AxisFlagsNoSideSwitch |
7474
implot.AxisFlagsAutoFit,
75-
eventSub: make(chan events.Event, 50),
7675
}
7776

7877
cmp.Component = component.NewComponent[*WaveComponent](id, cmp.handleUpdate)
7978
cmp.Component.SetLayoutBuilder(cmp)
8079

81-
// Subscribe to playback progress events
80+
// Subscribe to playback progress events using filtered subscription
8281
bus := eventbus.Bus
8382
uuid := cmp.UUID()
84-
bus.Subscribe(events.AudioPlaybackProgressKey, uuid, cmp.eventSub)
85-
bus.Subscribe(events.AudioPlaybackStartedKey, uuid, cmp.eventSub)
86-
bus.Subscribe(events.AudioPlaybackStoppedKey, uuid, cmp.eventSub)
87-
bus.Subscribe(events.AudioPlaybackFinishedKey, uuid, cmp.eventSub)
83+
cmp.filteredEventSub = eventbus.NewFilteredSubscription(uuid, 50)
84+
cmp.filteredEventSub.SubscribeMultiple(
85+
bus,
86+
events.AudioPlaybackProgressKey,
87+
events.AudioPlaybackStartedKey,
88+
events.AudioPlaybackStoppedKey,
89+
events.AudioPlaybackFinishedKey,
90+
)
8891

8992
return cmp
9093
}
9194

9295
// drainEvents translates global bus events into local commands
9396
func (wc *WaveComponent) drainEvents() {
94-
for {
95-
select {
96-
case event := <-wc.eventSub:
97-
if e, ok := event.(events.AudioPlaybackEventRecord); ok {
98-
if wc.displayData.Path == "" || e.Path != wc.displayData.Path {
99-
continue
100-
}
97+
if wc.filteredEventSub != nil {
98+
for {
99+
select {
100+
case event := <-wc.filteredEventSub.Events():
101+
if e, ok := event.(events.AudioPlaybackEventRecord); ok {
102+
if wc.displayData.Path == "" || e.Path != wc.displayData.Path {
103+
continue
104+
}
101105

102-
// Translate to a local command
103-
cmd := component.UpdateCmd{
104-
Type: cmdUpdatePlaybackProgress,
105-
Data: PlaybackProgressUpdate{
106-
IsPlaying: e.IsPlaying,
107-
Progress: e.Progress,
108-
PositionSeconds: float64(e.PositionSamples) / float64(wc.displayData.SampleRate),
109-
},
106+
// Translate to a local command
107+
cmd := component.UpdateCmd{
108+
Type: cmdUpdatePlaybackProgress,
109+
Data: PlaybackProgressUpdate{
110+
IsPlaying: e.IsPlaying,
111+
Progress: e.Progress,
112+
PositionSeconds: float64(e.PositionSamples) / float64(wc.displayData.SampleRate),
113+
},
114+
}
115+
wc.SendUpdate(cmd)
110116
}
111-
wc.SendUpdate(cmd)
117+
default:
118+
// No more events
119+
return
112120
}
113-
default:
114-
// No more events
115-
return
116121
}
117122
}
118123
}
@@ -1126,13 +1131,10 @@ func (wc *WaveComponent) Layout() {
11261131

11271132
// Destroy cleans up the component
11281133
func (wc *WaveComponent) Destroy() {
1129-
// Unsubscribe from all events
1130-
bus := eventbus.Bus
1131-
uuid := wc.UUID()
1132-
bus.Unsubscribe(events.AudioPlaybackProgressKey, uuid)
1133-
bus.Unsubscribe(events.AudioPlaybackStartedKey, uuid)
1134-
bus.Unsubscribe(events.AudioPlaybackStoppedKey, uuid)
1135-
bus.Unsubscribe(events.AudioPlaybackFinishedKey, uuid)
1134+
// Unsubscribe from filtered subscriptions (handles all event types)
1135+
if wc.filteredEventSub != nil {
1136+
wc.filteredEventSub.Unsubscribe()
1137+
}
11361138

11371139
// Call the base component's destroy method
11381140
wc.Component.Destroy()

internal/app/window/library/library.go

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ type LibraryWindow struct {
6767
Tree *tree.TreeComponent
6868
}
6969

70-
eventSub chan events.Event
70+
filteredEventSub *eventbus.FilteredSubscription
7171
}
7272

7373
func (w *LibraryWindow) createTreeRowsFromData(data []tree.TreeRowData) []*tree.TreeRowComponent {
@@ -156,14 +156,16 @@ func (w *LibraryWindow) createInitialTopLevelRows(rowData []tree.TreeRowData) []
156156

157157
// drainEvents translates global bus events into local commands
158158
func (w *LibraryWindow) drainEvents() {
159-
for {
160-
select {
161-
case event := <-w.eventSub:
162-
if e, ok := event.(events.LibraryScanEventRecord); ok {
163-
w.SendUpdate(UpdateCmd{Type: cmdHandleScanEvent, Data: e})
159+
if w.filteredEventSub != nil {
160+
for {
161+
select {
162+
case event := <-w.filteredEventSub.Events():
163+
if e, ok := event.(events.LibraryScanEventRecord); ok {
164+
w.SendUpdate(UpdateCmd{Type: cmdHandleScanEvent, Data: e})
165+
}
166+
default:
167+
return
164168
}
165-
default:
166-
return
167169
}
168170
}
169171
}
@@ -547,13 +549,10 @@ func (w *LibraryWindow) Layout() {
547549

548550
// Destroy cleans up the window and its subscriptions
549551
func (w *LibraryWindow) Destroy() {
550-
// Unsubscribe from all events
551-
bus := eventbus.Bus
552-
uuid := w.UUID()
553-
bus.Unsubscribe(events.LibraryScanStartedKey, uuid)
554-
bus.Unsubscribe(events.LibraryScanProgressKey, uuid)
555-
bus.Unsubscribe(events.LibraryScanCompletedKey, uuid)
556-
bus.Unsubscribe(events.LibraryScanFailedKey, uuid)
552+
// Unsubscribe from filtered subscriptions (handles all event types)
553+
if w.filteredEventSub != nil {
554+
w.filteredEventSub.Unsubscribe()
555+
}
557556

558557
// Destroy child components
559558
if w.Components.Tree != nil {
@@ -567,7 +566,6 @@ func (w *LibraryWindow) Destroy() {
567566
func NewLibraryWindow() *LibraryWindow {
568567
w := &LibraryWindow{
569568
isScanning: false,
570-
eventSub: make(chan events.Event, 50),
571569
}
572570
w.Window = window.NewWindow[*LibraryWindow]("Library", "LibraryBig", w.handleUpdate)
573571

@@ -596,10 +594,16 @@ func NewLibraryWindow() *LibraryWindow {
596594

597595
bus := eventbus.Bus
598596
uuid := w.UUID()
599-
bus.Subscribe(events.LibraryScanStartedKey, uuid, w.eventSub)
600-
bus.Subscribe(events.LibraryScanProgressKey, uuid, w.eventSub)
601-
bus.Subscribe(events.LibraryScanCompletedKey, uuid, w.eventSub)
602-
bus.Subscribe(events.LibraryScanFailedKey, uuid, w.eventSub)
597+
598+
// Create filtered subscription for library scan events
599+
w.filteredEventSub = eventbus.NewFilteredSubscription(uuid, 50)
600+
w.filteredEventSub.SubscribeMultiple(
601+
bus,
602+
events.LibraryScanStartedKey,
603+
events.LibraryScanProgressKey,
604+
events.LibraryScanCompletedKey,
605+
events.LibraryScanFailedKey,
606+
)
603607

604608
return w
605609
}

internal/app/window/presetlist/preset_list.go

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ type PresetListWindow struct {
3939
presetLocation *storage.StorageLocation
4040
loading bool
4141

42-
eventSub chan events.Event
42+
filteredEventSub *eventbus.FilteredSubscription
4343
}
4444

4545
func NewPresetListWindow() *PresetListWindow {
@@ -48,7 +48,6 @@ func NewPresetListWindow() *PresetListWindow {
4848
presetLocation: nil,
4949
selectedPreset: nil,
5050
loading: false,
51-
eventSub: make(chan events.Event, 20),
5251
}
5352

5453
w.Window = window.NewWindow[*PresetListWindow]("Presets", "ListMusic", w.handleUpdate)
@@ -72,30 +71,38 @@ func NewPresetListWindow() *PresetListWindow {
7271

7372
bus := eventbus.Bus
7473
uuid := w.UUID()
75-
bus.Subscribe(events.StorageActivatedEventKey, uuid, w.eventSub)
76-
bus.Subscribe(events.ComponentClickEventKey, uuid, w.eventSub)
74+
75+
// Create filtered subscription for all events
76+
w.filteredEventSub = eventbus.NewFilteredSubscription(uuid, 20)
77+
w.filteredEventSub.SubscribeMultiple(
78+
bus,
79+
events.StorageActivatedEventKey,
80+
events.ComponentClickEventKey,
81+
)
7782

7883
return w
7984
}
8085

8186
// drainEvents translates global bus events into local commands
8287
func (w *PresetListWindow) drainEvents() {
83-
for {
84-
select {
85-
case event := <-w.eventSub:
86-
var cmd component.UpdateCmd
87-
switch event.Type() {
88-
case events.StorageActivatedEventKey:
89-
cmd = component.UpdateCmd{Type: cmdPresetListSetLocation, Data: event}
90-
case events.ComponentClickEventKey:
91-
cmd = component.UpdateCmd{Type: cmdHandleRowClick, Data: event}
92-
}
93-
if cmd.Type != 0 {
94-
w.SendUpdate(cmd)
88+
if w.filteredEventSub != nil {
89+
for {
90+
select {
91+
case event := <-w.filteredEventSub.Events():
92+
var cmd component.UpdateCmd
93+
switch event.Type() {
94+
case events.StorageActivatedEventKey:
95+
cmd = component.UpdateCmd{Type: cmdPresetListSetLocation, Data: event}
96+
case events.ComponentClickEventKey:
97+
cmd = component.UpdateCmd{Type: cmdHandleRowClick, Data: event}
98+
}
99+
if cmd.Type != 0 {
100+
w.SendUpdate(cmd)
101+
}
102+
default:
103+
// No more events
104+
return
95105
}
96-
default:
97-
// No more events
98-
return
99106
}
100107
}
101108
}
@@ -278,11 +285,10 @@ func (w *PresetListWindow) Layout() {
278285
}
279286

280287
func (w *PresetListWindow) Destroy() {
281-
// Unsubscribe from all events
282-
bus := eventbus.Bus
283-
uuid := w.UUID()
284-
bus.Unsubscribe(events.StorageActivatedEventKey, uuid)
285-
bus.Unsubscribe(events.ComponentClickEventKey, uuid)
288+
// Unsubscribe from filtered subscriptions
289+
if w.filteredEventSub != nil {
290+
w.filteredEventSub.Unsubscribe()
291+
}
286292

287293
// Destroy child components
288294
if w.Components.PresetTable != nil {

0 commit comments

Comments
 (0)