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 if (intent.getBooleanExtra(EXTRA_OPEN_UPDATE, false)) updates.requestOpen()62 forwardNewEntryRequest(intent)63 if (BuildConfig.DEBUG) {64 QaFlags.disableSecureCaptureForQa = intent.getBooleanExtra("qa_disable_secure_flag", false)65 }66 }6768 override fun onCreate(savedInstanceState: Bundle?) {69 installSplashScreen()70 super.onCreate(savedInstanceState)7172 73 if (intent.getBooleanExtra(EXTRA_OPEN_UPDATE, false)) updates.requestOpen()74 forwardNewEntryRequest(intent)7576 77 78 window.setBackgroundDrawable(ColorDrawable(AndroidColor.parseColor("#0C0A06")))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 103 104 105 106 SideEffect {107 WindowCompat.getInsetsController(window, window.decorView).apply {108 isAppearanceLightStatusBars = false109 isAppearanceLightNavigationBars = false110 }111 }112 val accent = ACCENT_COLORS[settings.accentColor] ?: DEFAULT_ACCENT113 PeachTheme(114 accent = accent,115 reduceMotion = settings.reduceMotion,116 ) {117 WideScreenScale {118 PeachAppNavHost(startDestination = start, isUnlocked = vault.isUnlocked)119 }120 }121 }122 }123}124125126private val BASE_WIDTH = 411.dp127128129130131132133private fun MainActivity.forwardNewEntryRequest(intent: Intent) {134 if (!intent.getBooleanExtra(AutofillIntents.EXTRA_OPEN_NEW_ENTRY, false)) return135 autofillNav.requestNewEntry(136 url = intent.getStringExtra(AutofillIntents.EXTRA_NEW_ENTRY_URL),137 username = intent.getStringExtra(AutofillIntents.EXTRA_NEW_ENTRY_USERNAME),138 email = intent.getStringExtra(AutofillIntents.EXTRA_NEW_ENTRY_EMAIL),139 )140}141142143private const val MAX_SCALE = 1.35f144145146147148149150151152153154155@Composable156private fun WideScreenScale(content: @Composable () -> Unit) {157 BoxWithConstraints(Modifier.fillMaxSize()) {158 val base = LocalDensity.current159 val scale = (maxWidth / BASE_WIDTH).coerceIn(1f, MAX_SCALE)160 if (scale == 1f) {161 content()162 } else {163 CompositionLocalProvider(164 LocalDensity provides Density(base.density * scale, base.fontScale),165 content = content,166 )167 }168 }169}