196 lines
7.1 KiB
Kotlin
196 lines
7.1 KiB
Kotlin
package top.fatweb.oxygen.toolbox
|
|
|
|
import android.content.Context
|
|
import android.os.Bundle
|
|
import androidx.activity.ComponentActivity
|
|
import androidx.activity.SystemBarStyle
|
|
import androidx.activity.compose.setContent
|
|
import androidx.activity.enableEdgeToEdge
|
|
import androidx.activity.viewModels
|
|
import androidx.compose.foundation.isSystemInDarkTheme
|
|
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
|
|
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.CompositionLocalProvider
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
import androidx.compose.runtime.getValue
|
|
import androidx.compose.runtime.mutableStateOf
|
|
import androidx.compose.runtime.setValue
|
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|
import androidx.lifecycle.Lifecycle
|
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
import androidx.lifecycle.lifecycleScope
|
|
import androidx.lifecycle.repeatOnLifecycle
|
|
import dagger.hilt.EntryPoint
|
|
import dagger.hilt.InstallIn
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
import dagger.hilt.android.EntryPointAccessors
|
|
import dagger.hilt.components.SingletonComponent
|
|
import kotlinx.coroutines.flow.collect
|
|
import kotlinx.coroutines.flow.first
|
|
import kotlinx.coroutines.flow.onEach
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.runBlocking
|
|
import top.fatweb.oxygen.toolbox.model.userdata.DarkThemeConfig
|
|
import top.fatweb.oxygen.toolbox.model.userdata.LanguageConfig
|
|
import top.fatweb.oxygen.toolbox.model.userdata.LaunchPageConfig
|
|
import top.fatweb.oxygen.toolbox.model.userdata.ThemeBrandConfig
|
|
import top.fatweb.oxygen.toolbox.monitor.NetworkMonitor
|
|
import top.fatweb.oxygen.toolbox.monitor.TimeZoneMonitor
|
|
import top.fatweb.oxygen.toolbox.navigation.PREVIEW_ARG
|
|
import top.fatweb.oxygen.toolbox.navigation.navigateToToolView
|
|
import top.fatweb.oxygen.toolbox.repository.userdata.UserDataRepository
|
|
import top.fatweb.oxygen.toolbox.ui.OxygenApp
|
|
import top.fatweb.oxygen.toolbox.ui.rememberOxygenAppState
|
|
import top.fatweb.oxygen.toolbox.ui.theme.OxygenTheme
|
|
import top.fatweb.oxygen.toolbox.ui.util.LocalTimeZone
|
|
import top.fatweb.oxygen.toolbox.ui.util.LocaleUtils
|
|
import javax.inject.Inject
|
|
|
|
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
|
|
@AndroidEntryPoint
|
|
class MainActivity : ComponentActivity() {
|
|
@Inject
|
|
lateinit var networkMonitor: NetworkMonitor
|
|
|
|
@Inject
|
|
lateinit var timeZoneMonitor: TimeZoneMonitor
|
|
|
|
private val viewModel: MainActivityViewModel by viewModels()
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
val splashScreen = installSplashScreen()
|
|
super.onCreate(savedInstanceState)
|
|
|
|
var uiState: MainActivityUiState by mutableStateOf(MainActivityUiState.Loading)
|
|
|
|
lifecycleScope.launch {
|
|
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
viewModel.uiState
|
|
.onEach { uiState = it }
|
|
.collect()
|
|
}
|
|
}
|
|
|
|
splashScreen.setKeepOnScreenCondition {
|
|
when (uiState) {
|
|
MainActivityUiState.Loading -> true
|
|
is MainActivityUiState.Success -> false
|
|
}
|
|
}
|
|
enableEdgeToEdge()
|
|
|
|
setContent {
|
|
val locale = whatLocale(uiState)
|
|
if (uiState != MainActivityUiState.Loading) {
|
|
LaunchedEffect(locale) {
|
|
LocaleUtils.switchLocale(this@MainActivity, locale)
|
|
}
|
|
}
|
|
|
|
val darkTheme = shouldUseDarkTheme(uiState)
|
|
LaunchedEffect(darkTheme) {
|
|
enableEdgeToEdge(
|
|
statusBarStyle = SystemBarStyle.auto(
|
|
android.graphics.Color.TRANSPARENT,
|
|
android.graphics.Color.TRANSPARENT
|
|
) { darkTheme },
|
|
navigationBarStyle = SystemBarStyle.dark(android.graphics.Color.TRANSPARENT)
|
|
)
|
|
}
|
|
|
|
val appState = rememberOxygenAppState(
|
|
windowSizeClass = calculateWindowSizeClass(this),
|
|
networkMonitor = networkMonitor,
|
|
timeZoneMonitor = timeZoneMonitor,
|
|
launchPageConfig = whatLaunchPage(uiState)
|
|
)
|
|
|
|
val currentTimeZone by appState.currentTimeZone.collectAsStateWithLifecycle()
|
|
|
|
CompositionLocalProvider(
|
|
LocalTimeZone provides currentTimeZone
|
|
) {
|
|
OxygenTheme(
|
|
darkTheme = darkTheme,
|
|
androidTheme = shouldUseAndroidTheme(uiState),
|
|
dynamicColor = shouldUseDynamicColor(uiState)
|
|
) {
|
|
OxygenApp(appState)
|
|
}
|
|
}
|
|
|
|
LaunchedEffect(intent.data) {
|
|
intent.data?.run {
|
|
val pathSegments = pathSegments
|
|
val preview = getBooleanQueryParameter(PREVIEW_ARG, false)
|
|
if (pathSegments.size == 2) {
|
|
appState.navController.navigateToToolView(pathSegments[0], pathSegments[1], preview)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@EntryPoint
|
|
@InstallIn(SingletonComponent::class)
|
|
interface UserDataRepositoryEntryPoint {
|
|
val userDataRepository: UserDataRepository
|
|
}
|
|
|
|
override fun attachBaseContext(newBase: Context) {
|
|
val userDataRepository =
|
|
EntryPointAccessors.fromApplication<UserDataRepositoryEntryPoint>(newBase).userDataRepository
|
|
super.attachBaseContext(LocaleUtils.attachBaseContext(newBase, runBlocking {
|
|
userDataRepository.userData.first().languageConfig
|
|
}))
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
private fun shouldUseDarkTheme(
|
|
uiState: MainActivityUiState
|
|
): Boolean = when (uiState) {
|
|
MainActivityUiState.Loading -> isSystemInDarkTheme()
|
|
is MainActivityUiState.Success -> when (uiState.userData.darkThemeConfig) {
|
|
DarkThemeConfig.FollowSystem -> isSystemInDarkTheme()
|
|
DarkThemeConfig.Light -> false
|
|
DarkThemeConfig.Dark -> true
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
private fun shouldUseAndroidTheme(
|
|
uiState: MainActivityUiState
|
|
): Boolean = when (uiState) {
|
|
MainActivityUiState.Loading -> false
|
|
is MainActivityUiState.Success -> when (uiState.userData.themeBrandConfig) {
|
|
ThemeBrandConfig.Default -> false
|
|
ThemeBrandConfig.Android -> true
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
private fun shouldUseDynamicColor(
|
|
uiState: MainActivityUiState
|
|
): Boolean = when (uiState) {
|
|
MainActivityUiState.Loading -> true
|
|
is MainActivityUiState.Success -> uiState.userData.useDynamicColor
|
|
}
|
|
|
|
@Composable
|
|
private fun whatLocale(
|
|
uiState: MainActivityUiState
|
|
): LanguageConfig = when (uiState) {
|
|
MainActivityUiState.Loading -> LanguageConfig.FollowSystem
|
|
is MainActivityUiState.Success -> uiState.userData.languageConfig
|
|
}
|
|
|
|
@Composable
|
|
private fun whatLaunchPage(
|
|
uiState: MainActivityUiState
|
|
): LaunchPageConfig = when (uiState) {
|
|
MainActivityUiState.Loading -> LaunchPageConfig.Tools
|
|
is MainActivityUiState.Success -> uiState.userData.launchPageConfig
|
|
}
|