diff --git a/android/app/src/main/java/com/fabledsword/minstrel/shared/widgets/trackactions/TrackActionsViewModel.kt b/android/app/src/main/java/com/fabledsword/minstrel/shared/widgets/trackactions/TrackActionsViewModel.kt index 9d885dbd..7e4748ea 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/shared/widgets/trackactions/TrackActionsViewModel.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/shared/widgets/trackactions/TrackActionsViewModel.kt @@ -2,6 +2,8 @@ package com.fabledsword.minstrel.shared.widgets.trackactions import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.fabledsword.minstrel.api.ErrorCopy +import com.fabledsword.minstrel.events.EventsStream import com.fabledsword.minstrel.likes.data.LikesRepository import com.fabledsword.minstrel.models.TrackRef import com.fabledsword.minstrel.player.PlayerController @@ -15,6 +17,7 @@ import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import javax.inject.Inject @@ -31,9 +34,10 @@ import javax.inject.Inject * Hidden-state observation: [QuarantineRepository] doesn't yet expose * a Flow for the caller's quarantine list (no Room cache; see the * repository's class comment), so this VM holds its own snapshot of - * the hidden track-id set. Refreshed on init and after every flag / - * unflag action so the sheet reflects the current state next time - * it opens for the same track. + * the hidden track-id set. Refreshed on init, after every flag / + * unflag action, AND on any `quarantine.*` SSE event so a hide/unhide + * from another device updates the sheet's Hide/Unhide label without + * a manual reload. */ @HiltViewModel class TrackActionsViewModel @Inject constructor( @@ -41,6 +45,7 @@ class TrackActionsViewModel @Inject constructor( private val quarantine: QuarantineRepository, private val player: PlayerController, private val playlists: PlaylistsRepository, + private val eventsStream: EventsStream, ) : ViewModel() { private val messages = MutableSharedFlow(extraBufferCapacity = 4) @@ -51,6 +56,11 @@ class TrackActionsViewModel @Inject constructor( init { refreshHidden() + viewModelScope.launch { + eventsStream.events + .filter { it.kind.startsWith("quarantine.") } + .collect { refreshHidden() } + } } fun isLikedFlow(trackId: String): Flow = @@ -84,7 +94,9 @@ class TrackActionsViewModel @Inject constructor( fun startRadio(trackId: String) { viewModelScope.launch { runCatching { player.startRadio(trackId) } - .onFailure { messages.tryEmit("Couldn't start radio: ${it.message ?: "unknown error"}") } + .onFailure { + messages.tryEmit("Couldn't start radio: ${ErrorCopy.fromThrowable(it)}") + } } } @@ -92,7 +104,9 @@ class TrackActionsViewModel @Inject constructor( viewModelScope.launch { runCatching { playlists.appendTrack(playlistId, trackId) } .onSuccess { messages.tryEmit("Added to playlist") } - .onFailure { messages.tryEmit("Couldn't add to playlist: ${it.message ?: "unknown error"}") } + .onFailure { + messages.tryEmit("Couldn't add to playlist: ${ErrorCopy.fromThrowable(it)}") + } } } @@ -100,7 +114,7 @@ class TrackActionsViewModel @Inject constructor( viewModelScope.launch { runCatching { quarantine.flag(track.id, reason, notes) } .onSuccess { refreshHidden() } - .onFailure { messages.tryEmit("Couldn't hide: ${it.message ?: "unknown error"}") } + .onFailure { messages.tryEmit("Couldn't hide: ${ErrorCopy.fromThrowable(it)}") } } } @@ -108,7 +122,7 @@ class TrackActionsViewModel @Inject constructor( viewModelScope.launch { runCatching { quarantine.unflag(trackId) } .onSuccess { refreshHidden() } - .onFailure { messages.tryEmit("Couldn't unhide: ${it.message ?: "unknown error"}") } + .onFailure { messages.tryEmit("Couldn't unhide: ${ErrorCopy.fromThrowable(it)}") } } }