Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@ import android.view.WindowManager
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.runtime.getValue
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.bitwarden.authenticator.data.platform.repository.SettingsRepository
import com.bitwarden.authenticator.ui.platform.composition.LocalManagerProvider
import com.bitwarden.authenticator.ui.platform.feature.debugmenu.manager.DebugMenuLaunchManager
import com.bitwarden.authenticator.ui.platform.feature.debugmenu.navigateToDebugMenuScreen
import com.bitwarden.authenticator.ui.platform.feature.rootnav.RootNavScreen
import com.bitwarden.authenticator.ui.platform.theme.AuthenticatorTheme
import com.bitwarden.ui.platform.theme.BitwardenTheme
import com.bitwarden.ui.platform.util.setupEdgeToEdge
import com.bitwarden.ui.platform.util.validate
import dagger.hilt.android.AndroidEntryPoint
Expand All @@ -39,6 +41,9 @@ class MainActivity : AppCompatActivity() {
@Inject
lateinit var debugLaunchManager: DebugMenuLaunchManager

@Inject
lateinit var settingsRepository: SettingsRepository

override fun onCreate(savedInstanceState: Bundle?) {
intent = intent.validate()
var shouldShowSplashScreen = true
Expand All @@ -53,13 +58,14 @@ class MainActivity : AppCompatActivity() {
)
}

AppCompatDelegate.setDefaultNightMode(settingsRepository.appTheme.osValue)
setupEdgeToEdge(appThemeFlow = mainViewModel.stateFlow.map { it.theme })
setContent {
val state by mainViewModel.stateFlow.collectAsStateWithLifecycle()
val navController = rememberNavController()
observeViewModelEvents(navController)
LocalManagerProvider {
AuthenticatorTheme(
BitwardenTheme(
theme = state.theme,
) {
RootNavScreen(
Expand Down Expand Up @@ -94,6 +100,9 @@ class MainActivity : AppCompatActivity() {
}

MainEvent.NavigateToDebugMenu -> navController.navigateToDebugMenuScreen()
is MainEvent.UpdateAppTheme -> {
AppCompatDelegate.setDefaultNightMode(event.osTheme)
}
}
}
.launchIn(lifecycleScope)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class MainViewModel @Inject constructor(

private fun handleThemeUpdated(action: MainAction.Internal.ThemeUpdate) {
mutableStateFlow.update { it.copy(theme = action.theme) }
sendEvent(MainEvent.UpdateAppTheme(osTheme = action.theme.osValue))
}

private fun handleFirstIntentReceived(action: MainAction.ReceiveFirstIntent) {
Expand Down Expand Up @@ -139,4 +140,9 @@ sealed class MainEvent {
* Event indicating a change in the screen capture setting.
*/
data class ScreenCaptureSettingChange(val isAllowed: Boolean) : MainEvent()

/**
* Indicates that the app theme has been updated.
*/
data class UpdateAppTheme(val osTheme: Int) : MainEvent()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ package com.bitwarden.authenticator.ui.auth.unlock

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -25,18 +24,16 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitwarden.authenticator.ui.platform.components.button.AuthenticatorFilledTonalButton
import com.bitwarden.authenticator.ui.platform.components.dialog.BasicDialogState
import com.bitwarden.authenticator.ui.platform.components.dialog.BitwardenBasicDialog
import com.bitwarden.authenticator.ui.platform.components.dialog.BitwardenLoadingDialog
import com.bitwarden.authenticator.ui.platform.components.dialog.LoadingDialogState
import com.bitwarden.authenticator.ui.platform.components.scaffold.BitwardenScaffold
import com.bitwarden.authenticator.ui.platform.composition.LocalBiometricsManager
import com.bitwarden.authenticator.ui.platform.manager.biometrics.BiometricsManager
import com.bitwarden.ui.platform.base.util.EventsEffect
import com.bitwarden.ui.platform.components.button.BitwardenFilledButton
import com.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
import com.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog
import com.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.util.asText
import com.bitwarden.ui.platform.theme.BitwardenTheme

/**
* Top level composable for the unlock screen.
Expand All @@ -60,10 +57,8 @@ fun UnlockScreen(

when (val dialog = state.dialog) {
is UnlockState.Dialog.Error -> BitwardenBasicDialog(
visibilityState = BasicDialogState.Shown(
title = BitwardenString.an_error_has_occurred.asText(),
message = dialog.message,
),
title = stringResource(id = BitwardenString.an_error_has_occurred),
message = dialog.message(),
onDismissRequest = remember(viewModel) {
{
viewModel.trySendAction(UnlockAction.DismissDialog)
Expand All @@ -72,7 +67,7 @@ fun UnlockScreen(
)

UnlockState.Dialog.Loading -> BitwardenLoadingDialog(
visibilityState = LoadingDialogState.Shown(BitwardenString.loading.asText()),
text = stringResource(id = BitwardenString.loading),
)

null -> Unit
Expand Down Expand Up @@ -107,45 +102,44 @@ fun UnlockScreen(
BitwardenScaffold(
modifier = Modifier
.fillMaxSize(),
) { innerPadding ->
Box {
Column(
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(
modifier = Modifier
.padding(innerPadding)
.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(
modifier = Modifier
.padding(horizontal = 16.dp)
.width(220.dp)
.height(74.dp)
.fillMaxWidth(),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primary),
painter = painterResource(id = BitwardenDrawable.ic_logo_horizontal),
contentDescription = stringResource(BitwardenString.bitwarden_authenticator),
)
Spacer(modifier = Modifier.height(32.dp))
AuthenticatorFilledTonalButton(
label = stringResource(id = BitwardenString.use_biometrics_to_unlock),
onClick = {
biometricsManager.promptBiometrics(
onSuccess = onBiometricsUnlock,
onCancel = {
// no-op
},
onError = {
// no-op
},
onLockOut = onBiometricsLockOut,
)
},
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
}
.padding(horizontal = 16.dp)
.width(220.dp)
.height(74.dp)
.fillMaxWidth(),
colorFilter = ColorFilter.tint(BitwardenTheme.colorScheme.icon.secondary),
painter = painterResource(id = BitwardenDrawable.ic_logo_horizontal),
contentDescription = stringResource(BitwardenString.bitwarden_authenticator),
)
Spacer(modifier = Modifier.height(32.dp))
BitwardenFilledButton(
label = stringResource(id = BitwardenString.use_biometrics_to_unlock),
onClick = {
biometricsManager.promptBiometrics(
onSuccess = onBiometricsUnlock,
onCancel = {
// no-op
},
onError = {
// no-op
},
onLockOut = onBiometricsLockOut,
)
},
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)

Spacer(modifier = Modifier.height(height = 12.dp))
Spacer(modifier = Modifier.navigationBarsPadding())
}
}
}
Loading