Fixes websocket subscription, date invalidation, & theme music (#616)

## Description
Makes sure the `ServerEventListener` and `DatePlayedInvalidationService`
are injected so that they run. This was broken in #538.

Also fixes the a delayed stopping of theme music

Also fixes for detecting a non-seamless refresh rate switch

### Related issues
Fixes #615
Fixes #568
This commit is contained in:
Ray 2026-01-01 22:19:36 -05:00 committed by GitHub
parent d15ffa13b8
commit 0958578082
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 29 additions and 22 deletions

View file

@ -41,11 +41,13 @@ import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.services.AppUpgradeHandler
import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.DatePlayedInvalidationService
import com.github.damontecres.wholphin.services.DeviceProfileService
import com.github.damontecres.wholphin.services.ImageUrlService
import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.PlaybackLifecycleObserver
import com.github.damontecres.wholphin.services.RefreshRateService
import com.github.damontecres.wholphin.services.ServerEventListener
import com.github.damontecres.wholphin.services.SetupDestination
import com.github.damontecres.wholphin.services.SetupNavigationManager
import com.github.damontecres.wholphin.services.UpdateChecker
@ -106,6 +108,14 @@ class MainActivity : AppCompatActivity() {
@Inject
lateinit var tvProviderSchedulerService: TvProviderSchedulerService
// Note: unused but injected to ensure it is created
@Inject
lateinit var serverEventListener: ServerEventListener
// Note: unused but injected to ensure it is created
@Inject
lateinit var datePlayedInvalidationService: DatePlayedInvalidationService
private var signInAuto = true
@OptIn(ExperimentalTvMaterial3Api::class)

View file

@ -95,13 +95,13 @@ class RefreshRateService
} catch (ex: InterruptedException) {
Timber.w(ex, "Exception waiting for refresh rate switch")
}
val targetRate = (targetMode.refreshRate * 100).roundToInt()
val targetRate = (targetMode.refreshRate * 1000).roundToInt()
val isSeamless =
targetRate == (display.mode.refreshRate * 100).roundToInt() ||
targetRate == (currentDisplayMode.refreshRate * 1000).roundToInt() ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
display.mode.alternativeRefreshRates
.map { (it * 100).roundToInt() }
.any { targetRate % it == 0 }
currentDisplayMode.alternativeRefreshRates
.map { (it * 1000).roundToInt() }
.any { it % targetRate == 0 }
} else {
false
}

View file

@ -104,7 +104,9 @@ class ThemeSongPlayer
}
fun stop() {
if (player.isPlaying) {
Timber.v("Stopping theme song")
player.stop()
}
}
}

View file

@ -25,7 +25,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.compose.LifecycleStartEffect
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ChosenStreams
import com.github.damontecres.wholphin.data.model.BaseItem
@ -112,12 +111,12 @@ fun EpisodeDetails(
LoadingState.Success -> {
item?.let { ep ->
LifecycleStartEffect(destination.itemId) {
LifecycleResumeEffect(destination.itemId) {
viewModel.maybePlayThemeSong(
destination.itemId,
preferences.appPreferences.interfacePreferences.playThemeSongs,
)
onStopOrDispose {
onPauseOrDispose {
viewModel.release()
}
}

View file

@ -31,7 +31,6 @@ import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R
@ -143,12 +142,12 @@ fun MovieDetails(
LoadingState.Success -> {
item?.let { movie ->
LifecycleStartEffect(destination.itemId) {
LifecycleResumeEffect(destination.itemId) {
viewModel.maybePlayThemeSong(
destination.itemId,
preferences.appPreferences.interfacePreferences.playThemeSongs,
)
onStopOrDispose {
onPauseOrDispose {
viewModel.release()
}
}

View file

@ -34,7 +34,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R
@ -124,12 +124,12 @@ fun SeriesDetails(
LoadingState.Success -> {
item?.let { item ->
LifecycleStartEffect(destination.itemId) {
LifecycleResumeEffect(destination.itemId) {
viewModel.maybePlayThemeSong(
destination.itemId,
preferences.appPreferences.interfacePreferences.playThemeSongs,
)
onStopOrDispose {
onPauseOrDispose {
viewModel.release()
}
}

View file

@ -16,7 +16,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.map
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.model.BaseItem
@ -167,12 +167,12 @@ fun SeriesOverview(
},
"series_overview",
)
LifecycleStartEffect(destination.itemId) {
LifecycleResumeEffect(destination.itemId) {
viewModel.maybePlayThemeSong(
destination.itemId,
preferences.appPreferences.interfacePreferences.playThemeSongs,
)
onStopOrDispose {
onPauseOrDispose {
viewModel.release()
}
}

View file

@ -221,9 +221,6 @@ class SeriesViewModel
) {
viewModelScope.launchIO {
themeSongPlayer.playThemeFor(seriesId, playThemeSongs)
addCloseable {
themeSongPlayer.stop()
}
}
}