package com.peachpasswords import android.content.Intent import android.content.res.Configuration import android.graphics.Color as AndroidColor import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.WindowManager import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.fragment.app.FragmentActivity import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject import com.peachpasswords.ui.PeachAppNavHost import com.peachpasswords.ui.components.QaFlags import com.peachpasswords.ui.onboarding.ONBOARD_KEY import com.peachpasswords.ui.onboarding.ONBOARD_PREFS import com.peachpasswords.ui.onboarding.onboardingStartDestination import com.peachpasswords.ui.theme.ACCENT_COLORS import com.peachpasswords.ui.theme.DEFAULT_ACCENT import com.peachpasswords.ui.theme.PeachTheme import com.peachpasswords.vault.VaultLockTimer import com.peachpasswords.vault.VaultRepository // FragmentActivity (not ComponentActivity) so androidx BiometricPrompt can attach. @AndroidEntryPoint class MainActivity : FragmentActivity() { @Inject lateinit var vault: VaultRepository @Inject lateinit var lockTimer: VaultLockTimer // Every touch/key event resets the idle auto-lock countdown (CF-1). override fun onUserInteraction() { super.onUserInteraction() lockTimer.poke() } // launchMode="singleTask" reuses this instance across `adb shell am start` // relaunches, so the QA capture-bypass extra (see onCreate) needs to be // re-read here too, not just once at process start. override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) if (BuildConfig.DEBUG) { QaFlags.disableSecureCaptureForQa = intent.getBooleanExtra("qa_disable_secure_flag", false) } } override fun onCreate(savedInstanceState: Bundle?) { installSplashScreen() super.onCreate(savedInstanceState) // Match the splash/window fill to the resolved theme's --bg so launch // never flashes the wrong colour before Compose draws. Resolved from the // persisted setting synchronously (system mode reads the device night mode). val initialTheme = vault.settings.value.theme val initialDark = when (initialTheme) { "light" -> false "system" -> (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES else -> true } window.setBackgroundDrawable( ColorDrawable(AndroidColor.parseColor(if (initialDark) "#0C0A06" else "#EFEEE9")), ) enableEdgeToEdge() // Block screenshots / recents thumbnails of the vault in release builds. if (!BuildConfig.DEBUG) { window.setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE, ) } else { // QA-only, debug-build-only: `adb shell am start -n /.MainActivity // --ez qa_disable_secure_flag true` lets automated visual QA screenshot // otherwise-FLAG_SECURE screens (SecureFlagEffect). Off unless asked. QaFlags.disableSecureCaptureForQa = intent.getBooleanExtra("qa_disable_secure_flag", false) } // Onboarding runs once, only on a fresh install with no vault yet. val onboarded = getSharedPreferences(ONBOARD_PREFS, MODE_PRIVATE) .getBoolean(ONBOARD_KEY, false) val start = onboardingStartDestination(hasVault = vault.hasVault(), onboarded = onboarded) setContent { val settings by vault.settings.collectAsState() val darkTheme = when (settings.theme) { "light" -> false "system" -> isSystemInDarkTheme() else -> true } val accent = ACCENT_COLORS[settings.accentColor] ?: DEFAULT_ACCENT PeachTheme( darkTheme = darkTheme, accent = accent, reduceMotion = settings.reduceMotion, ) { PeachAppNavHost(startDestination = start, isUnlocked = vault.isUnlocked) } } } }