From a8a65496dbedd1c1521e26376032b3646710c4d3 Mon Sep 17 00:00:00 2001
From: Taras Smakula <tarassmakula@gmail.com>
Date: Thu, 21 Mar 2024 16:39:59 +0200
Subject: [PATCH] Add savig password with password manager

---
 .../circles/auth/feature/uia/UIADataSource.kt |  3 ++
 .../feature/uia/flow/LoginStagesDataSource.kt |  2 +-
 .../uia/stages/password/PasswordFragment.kt   |  6 +++-
 .../uia/stages/password/PasswordViewModel.kt  | 32 +++++++++++++++----
 4 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/auth/src/main/java/org/futo/circles/auth/feature/uia/UIADataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/uia/UIADataSource.kt
index 01a620e78..0f790b86e 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/uia/UIADataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/uia/UIADataSource.kt
@@ -95,6 +95,8 @@ abstract class UIADataSource {
         else -> LoginFlowTypes.TERMS
     }
 
+    fun getUserId() = "@${userName}:${domain}"
+
     private fun isStageRetry(result: RegistrationResult?): Boolean {
         val nextStageType =
             ((result as? RegistrationResult.FlowResponse)?.flowResult?.missingStages?.firstOrNull() as? Stage.Other)?.type
@@ -129,6 +131,7 @@ abstract class UIADataSource {
         SUBSCRPTION_GOOGLE_TYPE -> UIANavigationEvent.Subscription
         LOGIN_EMAIL_REQUEST_TOKEN_TYPE,
         ENROLL_EMAIL_REQUEST_TOKEN_TYPE -> UIANavigationEvent.ValidateEmail
+
         LOGIN_EMAIL_SUBMIT_TOKEN_TYPE,
         ENROLL_EMAIL_SUBMIT_TOKEN_TYPE -> null //stay on same screen
         ENROLL_USERNAME_TYPE -> UIANavigationEvent.Username
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/uia/flow/LoginStagesDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/uia/flow/LoginStagesDataSource.kt
index b685d2782..2de99217e 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/uia/flow/LoginStagesDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/uia/flow/LoginStagesDataSource.kt
@@ -53,7 +53,7 @@ class LoginStagesDataSource @Inject constructor(
     }
 
     private fun getIdentifier() = mapOf(
-        USER_PARAM_KEY to "@$userName:$domain",
+        USER_PARAM_KEY to getUserId(),
         TYPE_PARAM_KEY to LOGIN_PASSWORD_USER_ID_TYPE
     )
 }
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/uia/stages/password/PasswordFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/uia/stages/password/PasswordFragment.kt
index 33884332d..ed079c87c 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/uia/stages/password/PasswordFragment.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/uia/stages/password/PasswordFragment.kt
@@ -49,7 +49,11 @@ class PasswordFragment : ParentBackPressOwnerFragment(R.layout.fragment_password
                 setText(getString(if (isSignupMode()) R.string.set_password else R.string.log_in))
                 setOnClickListener {
                     startLoading(btnLogin)
-                    viewModel.processPasswordStage(tilPassword.getText())
+                    viewModel.processPasswordStage(
+                        tilPassword.getText(),
+                        isSignupMode(),
+                        requireContext()
+                    )
                 }
             }
             tilPassword.editText?.apply {
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/uia/stages/password/PasswordViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/uia/stages/password/PasswordViewModel.kt
index febaa25ce..f656588a5 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/uia/stages/password/PasswordViewModel.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/uia/stages/password/PasswordViewModel.kt
@@ -1,6 +1,7 @@
 package org.futo.circles.auth.feature.uia.stages.password
 
 import android.content.Context
+import androidx.credentials.CreatePasswordRequest
 import androidx.credentials.CredentialManager
 import androidx.credentials.GetCredentialRequest
 import androidx.credentials.GetPasswordOption
@@ -23,17 +24,17 @@ class PasswordViewModel @Inject constructor(
     val passwordResponseLiveData = SingleEventLiveData<Response<Unit>>()
     val passwordSelectedEventLiveData = SingleEventLiveData<String>()
 
-    fun processPasswordStage(password: String) {
-        launchBg { handlePasswordRequest(password) }
+    fun processPasswordStage(password: String, isSignup: Boolean, activityContext: Context) {
+        launchBg { handlePasswordRequest(password, isSignup, activityContext) }
     }
 
     fun getCredentials(activityContext: Context) {
         launchBg {
             tryOrNull {
                 val credentialManager = CredentialManager.create(activityContext)
-                val userName = UIADataSourceProvider.getDataSourceOrThrow().userName
+                val userId = UIADataSourceProvider.getDataSourceOrThrow().getUserId()
                 val request = GetCredentialRequest(
-                    listOf(GetPasswordOption(allowedUserIds = setOf(userName)))
+                    listOf(GetPasswordOption(allowedUserIds = setOf(userId)))
                 )
 
                 val result = credentialManager.getCredential(
@@ -44,17 +45,36 @@ class PasswordViewModel @Inject constructor(
                 if (result is PasswordCredential) {
                     val password = result.password
                     passwordSelectedEventLiveData.postValue(password)
-                    handlePasswordRequest(password)
+                    handlePasswordRequest(password, false, activityContext)
                 }
             }
         }
     }
 
-    private suspend fun handlePasswordRequest(password: String) {
+    private suspend fun handlePasswordRequest(
+        password: String,
+        isSignup: Boolean,
+        activityContext: Context
+    ) {
+        if (isSignup) registerPassword(activityContext, password)
         val result = passwordDataSource.processPasswordStage(password)
         passwordResponseLiveData.postValue(result)
     }
 
+    private suspend fun registerPassword(activityContext: Context, password: String) {
+        tryOrNull {
+            val uiaDataSource = UIADataSourceProvider.getDataSourceOrThrow()
+            val createPasswordRequest = CreatePasswordRequest(
+                id = uiaDataSource.getUserId(),
+                password = password
+            )
+            CredentialManager.create(activityContext).createCredential(
+                activityContext,
+                createPasswordRequest
+            )
+        }
+    }
+
     fun isPasswordWarningConfirmed() = isPasswordWarningConfirmed
     fun confirmPasswordWarning() {
         isPasswordWarningConfirmed = true
-- 
GitLab