1package com.peachpasswords23import android.content.Intent4import android.content.res.Configuration5import android.graphics.Color as AndroidColor6import android.graphics.drawable.ColorDrawable7import android.os.Bundle8import android.view.WindowManager9import androidx.activity.compose.setContent10import androidx.activity.enableEdgeToEdge11import androidx.compose.foundation.isSystemInDarkTheme12import androidx.compose.runtime.SideEffect13import androidx.compose.ui.unit.dp14import androidx.compose.ui.unit.Density15import androidx.compose.ui.platform.LocalDensity16import androidx.compose.ui.Modifier17import androidx.compose.runtime.CompositionLocalProvider18import androidx.compose.runtime.Composable19import androidx.compose.foundation.layout.fillMaxSize20import androidx.compose.foundation.layout.BoxWithConstraints21import androidx.compose.runtime.collectAsState22import androidx.compose.runtime.getValue23import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen24import androidx.core.view.WindowCompat25import androidx.fragment.app.FragmentActivity26import dagger.hilt.android.AndroidEntryPoint27import javax.inject.Inject28import com.peachpasswords.ui.PeachAppNavHost29import com.peachpasswords.ui.components.QaFlags30import com.peachpasswords.ui.onboarding.ONBOARD_KEY31import com.peachpasswords.ui.onboarding.ONBOARD_PREFS32import com.peachpasswords.ui.onboarding.onboardingStartDestination33import com.peachpasswords.ui.theme.ACCENT_COLORS34import com.peachpasswords.ui.theme.DEFAULT_ACCENT35import com.peachpasswords.ui.theme.PeachTheme36import com.peachpasswords.vault.VaultLockTimer37import com.peachpasswords.vault.VaultRepository383940@AndroidEntryPoint41class MainActivity : FragmentActivity() {42 @Inject lateinit var vault: VaultRepository43 @Inject lateinit var lockTimer: VaultLockTimer4445 46 override fun onUserInteraction() {47 super.onUserInteraction()48 lockTimer.poke()49 }5051 52 53 54 override fun onNewIntent(intent: Intent) {55 super.onNewIntent(intent)56 setIntent(intent)57 if (BuildConfig.DEBUG) {58 QaFlags.disableSecureCaptureForQa = intent.getBooleanExtra("qa_disable_secure_flag", false)59 }60 }6162 override fun onCreate(savedInstanceState: Bundle?) {63 installSplashScreen()64 super.onCreate(savedInstanceState)6566 67 68 69 val initialTheme = vault.settings.value.theme70 val initialDark = when (initialTheme) {71 "light" -> false72 "system" -> (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) ==73 Configuration.UI_MODE_NIGHT_YES74 else -> true75 }76 window.setBackgroundDrawable(77 ColorDrawable(AndroidColor.parseColor(if (initialDark) "#0C0A06" else "#EFEEE9")),78 )7980 enableEdgeToEdge()8182 83 if (!BuildConfig.DEBUG) {84 window.setFlags(85 WindowManager.LayoutParams.FLAG_SECURE,86 WindowManager.LayoutParams.FLAG_SECURE,87 )88 } else {89 90 91 92 QaFlags.disableSecureCaptureForQa = intent.getBooleanExtra("qa_disable_secure_flag", false)93 }9495 96 val onboarded = getSharedPreferences(ONBOARD_PREFS, MODE_PRIVATE)97 .getBoolean(ONBOARD_KEY, false)98 val start = onboardingStartDestination(hasVault = vault.hasVault(), onboarded = onboarded)99100 setContent {101 val settings by vault.settings.collectAsState()102 val darkTheme = when (settings.theme) {103 "light" -> false104 "system" -> isSystemInDarkTheme()105 else -> true106 }107 108 109 110 111 112 113 114 115 SideEffect {116 WindowCompat.getInsetsController(window, window.decorView).apply {117 isAppearanceLightStatusBars = !darkTheme118 isAppearanceLightNavigationBars = !darkTheme119 }120 }121 val accent = ACCENT_COLORS[settings.accentColor] ?: DEFAULT_ACCENT122 PeachTheme(123 darkTheme = darkTheme,124 accent = accent,125 reduceMotion = settings.reduceMotion,126 ) {127 WideScreenScale {128 PeachAppNavHost(startDestination = start, isUnlocked = vault.isUnlocked)129 }130 }131 }132 }133}134135136private val BASE_WIDTH = 411.dp137138139private const val MAX_SCALE = 1.35f140141142143144145146147148149150151@Composable152private fun WideScreenScale(content: @Composable () -> Unit) {153 BoxWithConstraints(Modifier.fillMaxSize()) {154 val base = LocalDensity.current155 val scale = (maxWidth / BASE_WIDTH).coerceIn(1f, MAX_SCALE)156 if (scale == 1f) {157 content()158 } else {159 CompositionLocalProvider(160 LocalDensity provides Density(base.density * scale, base.fontScale),161 content = content,162 )163 }164 }165}