mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Add in-app & Android TV screensaver (#946)
## Description Adds both an optional in-app and Android TV OS (DreamService) screensaver Has settings for: - Starting delay, options from 30s to 1 hour - Duration to show each image, 30s to 2 minutes - Show clock (separate from app-wide clock) - Toggle animated zooming - Set a max age rating to limit what content is shown - Included media types: movies, tv shows, and/or photos By default only Movies & TV Shows are included. But if you have like family albums on your server, you could enable Photos too. There's also an button to start the screensaver so you can see what it looks like. ### Related issues Closes #230 ### Testing Emulator, Onn 4k pro, nvidia shield using both in-app and OS screensavers ## Screenshots  ## AI or LLM usage None ## Acknowledgements Some of the skeleton code for setting up the `DreamService` with the right lifecycle was copied and modified from the [official app's implementation](https://github.com/jellyfin/jellyfin-androidtv/blob/master/app/src/main/java/org/jellyfin/androidtv/integration/dream/DreamServiceCompat.kt).
This commit is contained in:
parent
536e8d366c
commit
a7e86fbc15
25 changed files with 954 additions and 78 deletions
|
|
@ -0,0 +1,98 @@
|
|||
package com.github.damontecres.wholphin
|
||||
|
||||
import android.service.dreams.DreamService
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleRegistry
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.setViewTreeLifecycleOwner
|
||||
import androidx.savedstate.SavedStateRegistry
|
||||
import androidx.savedstate.SavedStateRegistryController
|
||||
import androidx.savedstate.SavedStateRegistryOwner
|
||||
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.services.ScreensaverService
|
||||
import com.github.damontecres.wholphin.services.UserPreferencesService
|
||||
import com.github.damontecres.wholphin.ui.components.AppScreensaverContent
|
||||
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
@AndroidEntryPoint
|
||||
class WholphinDreamService :
|
||||
DreamService(),
|
||||
SavedStateRegistryOwner {
|
||||
@Inject
|
||||
lateinit var screensaverService: ScreensaverService
|
||||
|
||||
@Inject
|
||||
lateinit var userPreferencesService: UserPreferencesService
|
||||
|
||||
private val lifecycleRegistry = LifecycleRegistry(this)
|
||||
|
||||
private val savedStateRegistryController =
|
||||
SavedStateRegistryController.create(this).apply {
|
||||
performAttach()
|
||||
}
|
||||
|
||||
override val lifecycle: Lifecycle get() = lifecycleRegistry
|
||||
override val savedStateRegistry: SavedStateRegistry get() = savedStateRegistryController.savedStateRegistry
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
savedStateRegistryController.performRestore(null)
|
||||
lifecycleRegistry.currentState = Lifecycle.State.CREATED
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
val itemFlow = screensaverService.createItemFlow(lifecycleScope)
|
||||
setContentView(
|
||||
ComposeView(this).apply {
|
||||
setViewTreeLifecycleOwner(this@WholphinDreamService)
|
||||
setViewTreeSavedStateRegistryOwner(this@WholphinDreamService)
|
||||
setContent {
|
||||
var prefs by remember { mutableStateOf<UserPreferences?>(null) }
|
||||
LaunchedEffect(Unit) {
|
||||
userPreferencesService.flow.collectLatest { prefs = it }
|
||||
}
|
||||
prefs?.let { prefs ->
|
||||
WholphinTheme(appThemeColors = prefs.appPreferences.interfacePreferences.appThemeColors) {
|
||||
val screensaverPrefs =
|
||||
prefs.appPreferences.interfacePreferences.screensaverPreference
|
||||
val currentItem by itemFlow.collectAsState(null)
|
||||
AppScreensaverContent(
|
||||
currentItem = currentItem,
|
||||
showClock = screensaverPrefs.showClock,
|
||||
duration = screensaverPrefs.duration.milliseconds,
|
||||
animate = screensaverPrefs.animate,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDreamingStarted() {
|
||||
super.onDreamingStarted()
|
||||
lifecycleRegistry.currentState = Lifecycle.State.STARTED
|
||||
}
|
||||
|
||||
override fun onDreamingStopped() {
|
||||
super.onDreamingStopped()
|
||||
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue