mirror of
https://github.com/bbara04/Purefin.git
synced 2026-07-24 03:36:51 +00:00
220 lines
8.0 KiB
Kotlin
220 lines
8.0 KiB
Kotlin
package hu.bbara.purefin
|
|
|
|
import android.content.pm.ApplicationInfo
|
|
import android.os.Bundle
|
|
import androidx.activity.ComponentActivity
|
|
import androidx.activity.compose.setContent
|
|
import androidx.activity.enableEdgeToEdge
|
|
import androidx.compose.animation.core.tween
|
|
import androidx.compose.animation.fadeIn
|
|
import androidx.compose.animation.fadeOut
|
|
import androidx.compose.animation.togetherWith
|
|
import androidx.compose.foundation.background
|
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.CompositionLocalProvider
|
|
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.lifecycle.lifecycleScope
|
|
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
|
|
import androidx.navigation3.runtime.EntryProviderScope
|
|
import androidx.navigation3.runtime.NavBackStack
|
|
import androidx.navigation3.runtime.entryProvider
|
|
import androidx.navigation3.runtime.rememberNavBackStack
|
|
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
|
|
import androidx.navigation3.ui.NavDisplay
|
|
import coil3.ImageLoader
|
|
import coil3.SingletonImageLoader
|
|
import coil3.disk.DiskCache
|
|
import coil3.memory.MemoryCache
|
|
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
|
import coil3.request.crossfade
|
|
import coil3.util.DebugLogger
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
import hu.bbara.purefin.core.data.SessionBootstrapper
|
|
import hu.bbara.purefin.data.jellyfin.client.JellyfinAuthInterceptor
|
|
import hu.bbara.purefin.core.data.session.UserSessionRepository
|
|
import hu.bbara.purefin.navigation.LocalNavigationBackStack
|
|
import hu.bbara.purefin.navigation.LocalNavigationManager
|
|
import hu.bbara.purefin.core.navigation.NavigationCommand
|
|
import hu.bbara.purefin.core.navigation.NavigationManager
|
|
import hu.bbara.purefin.core.navigation.Route
|
|
import hu.bbara.purefin.ui.screen.waiting.PurefinWaitingScreen
|
|
import hu.bbara.purefin.ui.screen.login.LoginScreen
|
|
import hu.bbara.purefin.ui.theme.AppTheme
|
|
import hu.bbara.purefin.ui.theme.backgroundDark
|
|
import kotlinx.coroutines.launch
|
|
import okhttp3.OkHttpClient
|
|
import okio.Path.Companion.toPath
|
|
import javax.inject.Inject
|
|
|
|
@AndroidEntryPoint
|
|
class PurefinActivity : ComponentActivity() {
|
|
|
|
@Inject
|
|
lateinit var entryBuilders: Set<@JvmSuppressWildcards EntryProviderScope<Route>.() -> Unit>
|
|
@Inject
|
|
lateinit var userSessionRepository: UserSessionRepository
|
|
|
|
@Inject
|
|
lateinit var navigationManager: NavigationManager
|
|
|
|
@Inject
|
|
lateinit var sessionBootstrapper: SessionBootstrapper
|
|
|
|
@Inject
|
|
lateinit var authInterceptor: JellyfinAuthInterceptor
|
|
|
|
private val imageOkHttpClient: OkHttpClient by lazy {
|
|
OkHttpClient.Builder()
|
|
.addNetworkInterceptor(authInterceptor)
|
|
.build()
|
|
}
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
lifecycleScope.launch { init() }
|
|
configureImageLoader()
|
|
enableEdgeToEdge()
|
|
setContent {
|
|
AppTheme() {
|
|
MainApp(
|
|
userSessionRepository = userSessionRepository,
|
|
entryBuilders = entryBuilders,
|
|
navigationManager = navigationManager
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
private suspend fun init() {
|
|
sessionBootstrapper.initialize()
|
|
}
|
|
|
|
private fun configureImageLoader() {
|
|
SingletonImageLoader.setSafe { context ->
|
|
val builder = ImageLoader.Builder(context)
|
|
.components {
|
|
add(
|
|
OkHttpNetworkFetcherFactory(
|
|
callFactory = { imageOkHttpClient }
|
|
)
|
|
)
|
|
}
|
|
.memoryCache {
|
|
MemoryCache.Builder()
|
|
.maxSizePercent(context, 0.20)
|
|
.build()
|
|
}
|
|
.diskCache {
|
|
DiskCache.Builder()
|
|
.directory(context.cacheDir.resolve("image_cache").absolutePath.toPath())
|
|
.maxSizeBytes(30000000)
|
|
.build()
|
|
}
|
|
.crossfade(true)
|
|
|
|
if (isDebuggable()) {
|
|
builder.logger(DebugLogger())
|
|
}
|
|
|
|
builder.build()
|
|
}
|
|
}
|
|
|
|
private fun isDebuggable(): Boolean {
|
|
return (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0
|
|
}
|
|
|
|
@Composable
|
|
fun MainApp(
|
|
userSessionRepository: UserSessionRepository,
|
|
entryBuilders: Set<@JvmSuppressWildcards EntryProviderScope<Route>.() -> Unit>,
|
|
navigationManager: NavigationManager
|
|
) {
|
|
var sessionLoaded by remember { mutableStateOf(false) }
|
|
val isLoggedIn by userSessionRepository.isLoggedIn.collectAsState(initial = false)
|
|
|
|
LaunchedEffect(Unit) {
|
|
userSessionRepository.isLoggedIn.collect {
|
|
sessionLoaded = true
|
|
}
|
|
}
|
|
|
|
if (!sessionLoaded) {
|
|
PurefinWaitingScreen(modifier = Modifier.fillMaxSize())
|
|
return
|
|
}
|
|
|
|
if (isLoggedIn) {
|
|
@Suppress("UNCHECKED_CAST")
|
|
val backStack = rememberNavBackStack(Route.Home) as NavBackStack<Route>
|
|
val appEntryProvider =
|
|
entryProvider {
|
|
entryBuilders.forEach { builder -> builder() }
|
|
}
|
|
|
|
LaunchedEffect(navigationManager, backStack) {
|
|
navigationManager.commands.collect { command ->
|
|
when (command) {
|
|
NavigationCommand.Pop -> if (backStack.size > 1) backStack.removeLastOrNull()
|
|
is NavigationCommand.Navigate -> backStack.add(command.route)
|
|
is NavigationCommand.ReplaceAll -> {
|
|
backStack.clear()
|
|
backStack.add(command.route)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CompositionLocalProvider(
|
|
LocalNavigationManager provides navigationManager,
|
|
LocalNavigationBackStack provides backStack.toList()
|
|
) {
|
|
NavDisplay(
|
|
backStack = backStack,
|
|
onBack = { navigationManager.pop() },
|
|
modifier = Modifier.fillMaxSize().background(backgroundDark),
|
|
transitionSpec = {
|
|
fadeIn(
|
|
animationSpec = tween(
|
|
durationMillis = 140
|
|
)
|
|
) togetherWith
|
|
fadeOut(animationSpec = tween(durationMillis = 140))
|
|
},
|
|
popTransitionSpec = {
|
|
fadeIn(
|
|
animationSpec = tween(
|
|
durationMillis = 140
|
|
)
|
|
) togetherWith
|
|
fadeOut(animationSpec = tween(durationMillis = 140))
|
|
},
|
|
predictivePopTransitionSpec = { _ ->
|
|
fadeIn(
|
|
animationSpec = tween(
|
|
durationMillis = 140
|
|
)
|
|
) togetherWith
|
|
fadeOut(animationSpec = tween(durationMillis = 140))
|
|
},
|
|
entryDecorators =
|
|
listOf(
|
|
rememberSaveableStateHolderNavEntryDecorator(),
|
|
rememberViewModelStoreNavEntryDecorator(),
|
|
),
|
|
entryProvider = appEntryProvider
|
|
)
|
|
}
|
|
} else {
|
|
LoginScreen()
|
|
}
|
|
}
|
|
}
|