adding MainViewModel navigation to LoginApprovalViewModel

This commit is contained in:
Andre Rosado 2024-11-20 18:56:46 +00:00
parent 5ea17700b3
commit 114982d64a
No known key found for this signature in database
GPG key ID: 99F68267CCD45AA9
6 changed files with 65 additions and 17 deletions

View file

@ -25,6 +25,7 @@ import com.x8bit.bitwarden.ui.platform.composition.LocalManagerProvider
import com.x8bit.bitwarden.ui.platform.feature.debugmenu.manager.DebugMenuLaunchManager
import com.x8bit.bitwarden.ui.platform.feature.debugmenu.navigateToDebugMenuScreen
import com.x8bit.bitwarden.ui.platform.feature.rootnav.RootNavScreen
import com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.loginapproval.navigateToLoginApproval
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@ -94,6 +95,13 @@ class MainActivity : AppCompatActivity() {
)
.show()
}
is MainEvent.NavigateToLoginApproval -> {
navController.navigateToLoginApproval(
fingerprint = "",
requestId = event.requestId,
)
}
}
}
updateScreenCapture(isScreenCaptureAllowed = state.isScreenCaptureAllowed)

View file

@ -273,13 +273,16 @@ class MainViewModel @Inject constructor(
authRepository.switchAccount(passwordlessRequestData.userId)
}
}
specialCircumstanceManager.specialCircumstance =
SpecialCircumstance.PasswordlessRequest(
passwordlessRequestData = passwordlessRequestData,
// Allow users back into the already-running app when completing the
// autofill task when this is not the first intent.
shouldFinishWhenComplete = isFirstIntent,
)
sendEvent(MainEvent.NavigateToLoginApproval(passwordlessRequestData.loginRequestId))
// specialCircumstanceManager.specialCircumstance =
// SpecialCircumstance.PasswordlessRequest(
// passwordlessRequestData = passwordlessRequestData,
// // Allow users back into the already-running app when completing the
// // autofill task when this is not the first intent.
// shouldFinishWhenComplete = isFirstIntent,
// )
}
completeRegistrationData != null -> {
@ -518,4 +521,11 @@ sealed class MainEvent {
* Show a toast with the given [message].
*/
data class ShowToast(val message: Text) : MainEvent()
/**
* Navigates to the Login Approval screen with the given fingerprint.
*/
data class NavigateToLoginApproval(
val requestId: String,
) : MainEvent()
}

View file

@ -12,8 +12,10 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.auth.util.createPasswordlessRequestDataIntent
import com.x8bit.bitwarden.data.autofill.util.toPendingIntentMutabilityFlag
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
import com.x8bit.bitwarden.data.platform.manager.AppStateManager
import com.x8bit.bitwarden.data.platform.manager.PushManager
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
import com.x8bit.bitwarden.data.platform.manager.model.AppForegroundState
import com.x8bit.bitwarden.data.platform.manager.model.PasswordlessRequestData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
@ -28,6 +30,7 @@ class AuthRequestNotificationManagerImpl(
private val authDiskSource: AuthDiskSource,
pushManager: PushManager,
dispatcherManager: DispatcherManager,
private val appStateManager: AppStateManager,
) : AuthRequestNotificationManager {
private val ioScope = CoroutineScope(dispatcherManager.io)
@ -40,6 +43,13 @@ class AuthRequestNotificationManagerImpl(
@SuppressLint("MissingPermission")
private fun handlePasswordlessRequestData(data: PasswordlessRequestData) {
val pendingIntent = createContentIntent(data)
if (appStateManager.appForegroundStateFlow.value == AppForegroundState.FOREGROUNDED) {
pendingIntent.send()
return
}
val notificationManager = NotificationManagerCompat.from(context)
// Construct the channel, calling this more than once is safe
notificationManager.createNotificationChannel(
@ -54,7 +64,7 @@ class AuthRequestNotificationManagerImpl(
if (!notificationManager.areNotificationsEnabled(NOTIFICATION_CHANNEL_ID)) return
// Create the notification
val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
.setContentIntent(createContentIntent(data))
.setContentIntent(pendingIntent)
.setContentTitle(context.getString(R.string.log_in_requested))
.setContentText(
authDiskSource

View file

@ -21,6 +21,7 @@ import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager
import com.x8bit.bitwarden.data.auth.manager.UserLogoutManagerImpl
import com.x8bit.bitwarden.data.platform.datasource.disk.PushDiskSource
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
import com.x8bit.bitwarden.data.platform.manager.AppStateManager
import com.x8bit.bitwarden.data.platform.manager.PushManager
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.GeneratorDiskSource
@ -49,12 +50,14 @@ object AuthManagerModule {
authDiskSource: AuthDiskSource,
pushManager: PushManager,
dispatcherManager: DispatcherManager,
appStateManager: AppStateManager,
): AuthRequestNotificationManager =
AuthRequestNotificationManagerImpl(
context = context,
authDiskSource = authDiskSource,
pushManager = pushManager,
dispatcherManager = dispatcherManager,
appStateManager = appStateManager,
)
@Provides

View file

@ -10,16 +10,19 @@ import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
import com.x8bit.bitwarden.ui.platform.base.util.composableWithSlideTransitions
private const val FINGERPRINT: String = "fingerprint"
private const val REQUEST_ID: String = "requestId"
private const val LOGIN_APPROVAL_PREFIX = "login_approval"
private const val LOGIN_APPROVAL_ROUTE = "$LOGIN_APPROVAL_PREFIX?$FINGERPRINT={$FINGERPRINT}"
private const val LOGIN_APPROVAL_ROUTE =
"$LOGIN_APPROVAL_PREFIX?$FINGERPRINT={$FINGERPRINT}&$REQUEST_ID={$REQUEST_ID}"
/**
* Class to retrieve login approval arguments from the [SavedStateHandle].
*/
@OmitFromCoverage
data class LoginApprovalArgs(val fingerprint: String?) {
data class LoginApprovalArgs(val fingerprint: String?, val requestId: String?) {
constructor(savedStateHandle: SavedStateHandle) : this(
fingerprint = savedStateHandle.get<String>(FINGERPRINT),
requestId = savedStateHandle.get<String>(REQUEST_ID),
)
}
@ -37,6 +40,11 @@ fun NavGraphBuilder.loginApprovalDestination(
nullable = true
defaultValue = null
},
navArgument(REQUEST_ID) {
type = NavType.StringType
nullable = true
defaultValue = null
},
),
) {
LoginApprovalScreen(
@ -50,7 +58,8 @@ fun NavGraphBuilder.loginApprovalDestination(
*/
fun NavController.navigateToLoginApproval(
fingerprint: String?,
requestId: String? = null,
navOptions: NavOptions? = null,
) {
navigate("$LOGIN_APPROVAL_PREFIX?$FINGERPRINT=$fingerprint", navOptions)
navigate("$LOGIN_APPROVAL_PREFIX?$FINGERPRINT=$fingerprint&$REQUEST_ID=$requestId", navOptions)
}

View file

@ -48,7 +48,7 @@ class LoginApprovalViewModel @Inject constructor(
?: requireNotNull(LoginApprovalArgs(savedStateHandle).fingerprint),
masterPasswordHash = null,
publicKey = "",
requestId = "",
requestId = LoginApprovalArgs(savedStateHandle).requestId.orEmpty(),
viewState = LoginApprovalState.ViewState.Loading,
dialogState = null,
)
@ -86,11 +86,19 @@ class LoginApprovalViewModel @Inject constructor(
}
}
?: run {
if (state.requestId.isNotEmpty()) {
authRepository
.getAuthRequestByFingerprintFlow(state.fingerprint)
.getAuthRequestByIdFlow(state.requestId)
.map { LoginApprovalAction.Internal.AuthRequestResultReceive(it) }
.onEach(::sendAction)
.launchIn(viewModelScope)
} else {
authRepository
.getAuthRequestByIdFlow(state.fingerprint)
.map { LoginApprovalAction.Internal.AuthRequestResultReceive(it) }
.onEach(::sendAction)
.launchIn(viewModelScope)
}
}
}