wolfskin/app/src/main/java/com/github/damontecres/wholphin/WholphinDreamService.kt
Damontecres 0b450fc0ff
Remove dependency on livedata libraries (#1453)
## Description
Refactors all usages of `LiveData` into flows in keeping with best
practices. This also includes refactoring several `ViewModel`s to
combine multiple `LiveData` into a new single `StateFlow`.

There are no user facing changes

### Related issues
None

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
2026-05-25 08:27:19 -04:00

134 lines
5.5 KiB
Kotlin

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.datastore.core.DataStore
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.data.ServerRepository
import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.services.ScreensaverService
import com.github.damontecres.wholphin.services.hilt.AuthOkHttpClient
import com.github.damontecres.wholphin.ui.CoilConfig
import com.github.damontecres.wholphin.ui.components.AppScreensaverContent
import com.github.damontecres.wholphin.ui.launchDefault
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
import com.github.damontecres.wholphin.ui.util.ProvideLocalClock
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.first
import okhttp3.OkHttpClient
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
import timber.log.Timber
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
@AndroidEntryPoint
class WholphinDreamService :
DreamService(),
SavedStateRegistryOwner {
@Inject
lateinit var serverRepository: ServerRepository
@Inject
lateinit var screensaverService: ScreensaverService
@Inject
lateinit var preferencesDataStore: DataStore<AppPreferences>
@AuthOkHttpClient
@Inject
lateinit var okHttpClient: OkHttpClient
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()
Timber.d("onCreate")
savedStateRegistryController.performRestore(null)
lifecycleRegistry.currentState = Lifecycle.State.CREATED
lifecycleScope.launchDefault {
if (serverRepository.current.value == null) {
val prefs = preferencesDataStore.data.first()
serverRepository.restoreSession(prefs.currentServerId.toUUIDOrNull(), prefs.currentUserId.toUUIDOrNull())
}
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
Timber.d("onAttachedToWindow")
val itemFlow = screensaverService.createItemFlow(lifecycleScope)
setContentView(
ComposeView(this).apply {
setViewTreeLifecycleOwner(this@WholphinDreamService)
setViewTreeSavedStateRegistryOwner(this@WholphinDreamService)
setContent {
val user by serverRepository.currentUserFlow.collectAsState(null)
if (user != null) {
var prefs by remember { mutableStateOf<AppPreferences?>(null) }
LaunchedEffect(Unit) {
preferencesDataStore.data.collectLatest { prefs = it }
}
prefs?.let { prefs ->
CoilConfig(
prefs = prefs,
okHttpClient = okHttpClient,
debugLogging = false,
enableCache = true,
)
WholphinTheme(appThemeColors = prefs.interfacePreferences.appThemeColors) {
ProvideLocalClock {
val screensaverPrefs = prefs.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()
Timber.d("onDreamingStarted")
lifecycleRegistry.currentState = Lifecycle.State.STARTED
}
override fun onDreamingStopped() {
super.onDreamingStopped()
Timber.d("onDreamingStopped")
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}
}