1package com.peachpasswords23import android.content.Intent4import android.graphics.Color as AndroidColor5import android.graphics.drawable.ColorDrawable6import android.os.Bundle7import android.view.WindowManager8import androidx.activity.compose.setContent9import androidx.activity.enableEdgeToEdge10import androidx.compose.runtime.SideEffect11import androidx.compose.ui.unit.dp12import androidx.compose.ui.unit.Density13import androidx.compose.ui.platform.LocalDensity14import androidx.compose.ui.Modifier15import androidx.compose.runtime.CompositionLocalProvider16import androidx.compose.runtime.Composable17import androidx.compose.foundation.layout.fillMaxSize18import androidx.compose.foundation.layout.BoxWithConstraints19import androidx.compose.runtime.collectAsState20import androidx.compose.runtime.getValue21import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen22import androidx.core.view.WindowCompat23import androidx.fragment.app.FragmentActivity24import dagger.hilt.android.AndroidEntryPoint25import javax.inject.Inject26import com.peachpasswords.autofill.AutofillIntents27import com.peachpasswords.autofill.AutofillNavRepository28import 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.updates.EXTRA_OPEN_UPDATE37import com.peachpasswords.updates.UpdateRepository38import com.peachpasswords.vault.VaultLockTimer39import com.peachpasswords.vault.VaultRepository404142@AndroidEntryPoint43class MainActivity : FragmentActivity() {44 @Inject lateinit var vault: VaultRepository45 @Inject lateinit var lockTimer: VaultLockTimer46 @Inject lateinit var updates: UpdateRepository47 @Inject lateinit var autofillNav: AutofillNavRepository4849 50 override fun onUserInteraction() {51 super.onUserInteraction()52 lockTimer.poke()53 }5455 56 57 58 override fun onNewIntent(intent: Intent) {59 super.onNewIntent(intent)60 setIntent(intent)61 routeIntent(intent)62 if (BuildConfig.DEBUG) {63 QaFlags.disableSecureCaptureForQa = intent.getBooleanExtra("qa_disable_secure_flag", false)64 }65 }6667 override fun onCreate(savedInstanceState: Bundle?) {68 installSplashScreen()69 super.onCreate(savedInstanceState)7071 72 routeIntent(intent)7374 75 76 window.setBackgroundDrawable(ColorDrawable(AndroidColor.parseColor("#0C0A06")))7778 enableEdgeToEdge()7980 81 if (!BuildConfig.DEBUG) {82 window.setFlags(83 WindowManager.LayoutParams.FLAG_SECURE,84 WindowManager.LayoutParams.FLAG_SECURE,85 )86 } else {87 88 89 90 QaFlags.disableSecureCaptureForQa = intent.getBooleanExtra("qa_disable_secure_flag", false)91 }9293 94 val onboarded = getSharedPreferences(ONBOARD_PREFS, MODE_PRIVATE)95 .getBoolean(ONBOARD_KEY, false)96 val start = onboardingStartDestination(hasVault = vault.hasVault(), onboarded = onboarded)9798 setContent {99 val settings by vault.settings.collectAsState()100 101 102 103 104 SideEffect {105 WindowCompat.getInsetsController(window, window.decorView).apply {106 isAppearanceLightStatusBars = false107 isAppearanceLightNavigationBars = false108 }109 }110 val accent = ACCENT_COLORS[settings.accentColor] ?: DEFAULT_ACCENT111 PeachTheme(112 accent = accent,113 reduceMotion = settings.reduceMotion,114 ) {115 WideScreenScale {116 PeachAppNavHost(startDestination = start, isUnlocked = vault.isUnlocked)117 }118 }119 }120 }121}122123124private val BASE_WIDTH = 411.dp125126127128129130131132133134135private fun MainActivity.routeIntent(intent: Intent) {136 if (intent.getBooleanExtra(EXTRA_OPEN_UPDATE, false)) updates.requestOpen()137 forwardNewEntryRequest(intent)138 routeAction(intent.action)?.let(PendingActionQueue::request)139}140141142143144145146private fun MainActivity.forwardNewEntryRequest(intent: Intent) {147 if (!intent.getBooleanExtra(AutofillIntents.EXTRA_OPEN_NEW_ENTRY, false)) return148 autofillNav.requestNewEntry(149 url = intent.getStringExtra(AutofillIntents.EXTRA_NEW_ENTRY_URL),150 username = intent.getStringExtra(AutofillIntents.EXTRA_NEW_ENTRY_USERNAME),151 email = intent.getStringExtra(AutofillIntents.EXTRA_NEW_ENTRY_EMAIL),152 )153}154155156private const val MAX_SCALE = 1.35f157158159160161162163164165166167168@Composable169private fun WideScreenScale(content: @Composable () -> Unit) {170 BoxWithConstraints(Modifier.fillMaxSize()) {171 val base = LocalDensity.current172 val scale = (maxWidth / BASE_WIDTH).coerceIn(1f, MAX_SCALE)173 if (scale == 1f) {174 content()175 } else {176 CompositionLocalProvider(177 LocalDensity provides Density(base.density * scale, base.fontScale),178 content = content,179 )180 }181 }182}