Skip to content

Commit a037886

Browse files
committed
fixes for the issues
when user cancel app getting closed #1114 when user cancel we dont need to show error messgae #1113
1 parent 0c53597 commit a037886

File tree

10 files changed

+201
-73
lines changed

10 files changed

+201
-73
lines changed

core/src/androidMain/kotlin/com/ustadmobile/core/domain/credentials/passkey/CreatePasskeyUseCaseImpl.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import android.content.Context
55
import androidx.credentials.CreatePublicKeyCredentialRequest
66
import androidx.credentials.CreatePublicKeyCredentialResponse
77
import androidx.credentials.CredentialManager
8+
import androidx.credentials.exceptions.CreateCredentialCancellationException
89
import androidx.credentials.exceptions.CreateCredentialException
910
import com.ustadmobile.core.domain.credentials.CreatePasskeyUseCase
11+
import com.ustadmobile.core.domain.credentials.CreatePasskeyUseCase.CreateCredentialResult
1012
import io.github.aakira.napier.Napier
1113
import com.ustadmobile.core.domain.credentials.passkey.request.CreatePublicKeyCredentialCreationOptionsJsonUseCase
1214
import com.ustadmobile.core.domain.credentials.passkey.model.AuthenticationResponseJSON
@@ -31,10 +33,10 @@ class CreatePasskeyUseCaseImpl(
3133
* @throws CreateCredentialException if CredentialManager throws an exception
3234
*/
3335
@SuppressLint("PublicKeyCredential")
34-
override suspend fun invoke(username:String): AuthenticationResponseJSON {
36+
override suspend fun invoke(username: String): CreateCredentialResult {
3537
val credentialManager = CredentialManager.create(context)
3638

37-
try {
39+
return try {
3840
val request = CreatePublicKeyCredentialRequest(
3941
requestJson = json.encodeToString(
4042
createPublicKeyJsonUseCase(username)
@@ -47,15 +49,22 @@ class CreatePasskeyUseCaseImpl(
4749
) as CreatePublicKeyCredentialResponse
4850

4951
Napier.d { "passkey response: ${response.registrationResponseJson}" }
50-
val passkeyResponse = json.decodeFromString<AuthenticationResponseJSON>(response.registrationResponseJson)
52+
val passkeyResponse =
53+
json.decodeFromString<AuthenticationResponseJSON>(response.registrationResponseJson)
54+
55+
CreatePasskeyUseCase.CreatePasskeyResult(passkeyResponse)
56+
} catch (e: CreateCredentialCancellationException) {
57+
CreatePasskeyUseCase.UserCanceledResult()
5158

52-
return passkeyResponse
5359
} catch (e: CreateCredentialException) {
5460
// See https://codelabs.developers.google.com/credential-manager-api-for-android#1
61+
5562
Napier.e(
5663
message = "CreatePassKeyUseCaseImpl: exception", throwable = e
5764
)
58-
throw e
65+
CreatePasskeyUseCase.Error(e.message)
66+
67+
5968
}
6069
}
6170
}

core/src/androidMain/kotlin/com/ustadmobile/core/domain/credentials/passkey/GetCredentialUseCaseImpl.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import androidx.credentials.GetPasswordOption
77
import androidx.credentials.GetPublicKeyCredentialOption
88
import androidx.credentials.PasswordCredential
99
import androidx.credentials.PublicKeyCredential
10+
import androidx.credentials.exceptions.GetCredentialCancellationException
1011
import androidx.credentials.exceptions.GetCredentialException
1112
import androidx.credentials.exceptions.NoCredentialException
1213
import com.ustadmobile.core.domain.credentials.GetCredentialUseCase
@@ -69,7 +70,10 @@ class GetCredentialUseCaseImpl(
6970
}
7071
} catch (e: NoCredentialException) {
7172
GetCredentialUseCase.NoCredentialAvailableResult()
72-
} catch (e: GetCredentialException) {
73+
}
74+
catch (e: GetCredentialCancellationException) {
75+
GetCredentialUseCase.UserCanceledResult()
76+
}catch (e: GetCredentialException) {
7377
GetCredentialUseCase.Error("Failed to get credential: ${e.message}")
7478
}
7579
}

core/src/commonMain/kotlin/com/ustadmobile/core/domain/credentials/CreatePasskeyUseCase.kt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,28 @@ import com.ustadmobile.core.domain.credentials.passkey.model.AuthenticationRespo
44

55
interface CreatePasskeyUseCase {
66

7-
suspend operator fun invoke(username:String): AuthenticationResponseJSON
7+
sealed class CreateCredentialResult()
8+
9+
data class CreatePasskeyResult(
10+
val authenticationResponseJSON : AuthenticationResponseJSON
11+
) : CreateCredentialResult()
12+
13+
class UserCanceledResult : CreateCredentialResult(){
14+
override fun equals(other: Any?): Boolean {
15+
if (this === other) return true
16+
if (other !is GetCredentialUseCase.UserCanceledResult) return false
17+
return true
18+
}
19+
20+
override fun hashCode(): Int {
21+
return this::class.hashCode()
22+
}
23+
}
24+
25+
data class Error(
26+
val message: String?
27+
) : CreateCredentialResult()
28+
29+
suspend operator fun invoke(username:String): CreateCredentialResult
830

931
}

core/src/commonMain/kotlin/com/ustadmobile/core/domain/credentials/GetCredentialUseCase.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ interface GetCredentialUseCase {
4646
}
4747
}
4848

49+
/**
50+
* when user cancelled the passkey bottom sheet then no need to show it as error
51+
*/
52+
class UserCanceledResult : CredentialResult(){
53+
override fun equals(other: Any?): Boolean {
54+
if (this === other) return true
55+
if (other !is UserCanceledResult) return false
56+
return true
57+
}
58+
59+
override fun hashCode(): Int {
60+
return this::class.hashCode()
61+
}
62+
}
63+
4964
data class Error(
5065
val message: String?
5166
) : CredentialResult()

core/src/commonMain/kotlin/com/ustadmobile/core/viewmodel/account/addaccountselectneworexisting/AddAccountSelectNewOrExistingViewModel.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,9 @@ class AddAccountSelectNewOrExistingViewModel(
151151
is GetCredentialUseCase.NoCredentialAvailableResult -> {
152152
//Do nothing
153153
}
154-
154+
is GetCredentialUseCase.UserCanceledResult -> {
155+
//Do nothing
156+
}
155157
null -> {
156158
//Do nothing
157159
}

core/src/commonMain/kotlin/com/ustadmobile/core/viewmodel/login/LoginViewModel.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,9 @@ class LoginViewModel(
382382
is GetCredentialUseCase.NoCredentialAvailableResult -> {
383383
//do nothing
384384
}
385+
is GetCredentialUseCase.UserCanceledResult -> {
386+
//Do nothing
387+
}
385388
}
386389
} catch (e: Exception) {
387390
Napier.e { "Error occurred: ${e.message}"}

core/src/commonMain/kotlin/com/ustadmobile/core/viewmodel/person/manageaccount/ManageAccountViewModel.kt

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.ustadmobile.core.db.UmAppDatabase
77
import com.ustadmobile.core.domain.credentials.CreatePasskeyUseCase
88
import com.ustadmobile.core.domain.credentials.SavePersonPasskeyUseCase
99
import com.ustadmobile.core.impl.appstate.AppUiState
10+
import com.ustadmobile.core.impl.appstate.Snack
1011
import com.ustadmobile.core.impl.config.SystemUrlConfig
1112
import com.ustadmobile.core.impl.nav.UstadSavedStateHandle
1213
import com.ustadmobile.core.view.ListViewMode
@@ -127,20 +128,39 @@ class ManageAccountViewModel(
127128
fun onCreatePasskeyClick() {
128129
viewModelScope.launch {
129130
val passkeyCreated = createPasskeyUseCase?.invoke(
130-
username = accountManager.currentUserSession.person.username.toString(),
131+
username = accountManager.currentUserSession.person.username.toString(),
131132
)
132133
if (passkeyCreated != null) {
133-
savePassKeyUseCase?.invoke(
134-
passkeyResult = passkeyCreated,
135-
person = accountManager.currentUserSession.person
136-
)
134+
when (passkeyCreated) {
135+
is CreatePasskeyUseCase.CreatePasskeyResult -> {
136+
savePassKeyUseCase?.invoke(
137+
passkeyResult = passkeyCreated.authenticationResponseJSON,
138+
person = accountManager.currentUserSession.person
139+
)
140+
}
141+
142+
is CreatePasskeyUseCase.Error -> {
143+
snackDispatcher.showSnackBar(Snack(message = passkeyCreated.message.toString()))
144+
145+
146+
}
147+
148+
is CreatePasskeyUseCase.UserCanceledResult -> {
149+
//do nothing
150+
}
151+
152+
null -> {
153+
//do nothing
154+
}
155+
156+
157+
}
158+
137159
}
138160

139161
}
140-
141162
}
142163

143-
144164
companion object {
145165

146166
const val DEST_NAME = "ManageAccount"

core/src/commonMain/kotlin/com/ustadmobile/core/viewmodel/signup/OtherSignUpOptionSelectionViewModel.kt

Lines changed: 69 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.ustadmobile.core.account.LearningSpace
55
import com.ustadmobile.core.domain.invite.EnrollToCourseFromInviteCodeUseCase
66
import com.ustadmobile.core.domain.localaccount.GetLocalAccountsSupportedUseCase
77
import com.ustadmobile.core.domain.credentials.CreatePasskeyUseCase
8+
import com.ustadmobile.core.domain.credentials.passkey.model.AuthenticationResponseJSON
89
import com.ustadmobile.core.impl.UstadMobileSystemCommon
910
import com.ustadmobile.core.impl.appstate.AppUiState
1011
import com.ustadmobile.core.impl.appstate.LoadingUiState
@@ -18,9 +19,7 @@ import com.ustadmobile.core.viewmodel.clazz.list.ClazzListViewModel
1819
import com.ustadmobile.core.viewmodel.contententry.list.ContentEntryListViewModel
1920
import com.ustadmobile.core.viewmodel.person.child.AddChildProfilesViewModel
2021
import com.ustadmobile.core.viewmodel.signup.SignUpViewModel.Companion.REGISTRATION_ARGS_TO_PASS
21-
import com.ustadmobile.door.ext.doorIdentityHashCode
2222
import com.ustadmobile.door.ext.doorPrimaryKeyManager
23-
import com.ustadmobile.door.util.systemTimeInMillis
2423
import com.ustadmobile.lib.db.entities.Person
2524
import com.ustadmobile.lib.db.entities.PersonPicture
2625
import io.github.aakira.napier.Napier
@@ -41,6 +40,7 @@ data class OtherSignUpOptionSelectionUiState(
4140
val person: Person? = null,
4241
val personPicture: PersonPicture? = null,
4342
val passkeySupported: Boolean = true,
43+
val errorText: String? = null,
4444
)
4545

4646
class OtherSignUpOptionSelectionViewModel(
@@ -115,47 +115,80 @@ class OtherSignUpOptionSelectionViewModel(
115115
val passkeyCreated = createPasskeyUseCase?.invoke(
116116
username = savePerson.username.toString()
117117
)
118-
passkeyCreated?.let {
119-
accountManager.registerWithPasskey(
120-
serverUrl,
121-
it,
122-
savePerson,
123-
_uiState.value.personPicture
124-
)
125-
}
126-
if (passkeyCreated == null) {
127-
snackDispatcher.showSnackBar(Snack(message = systemImpl.getString(MR.strings.sorry_something_went_wrong)))
128-
Napier.e { "Error occurred during creating passkey" }
129-
return@launch
130-
}
131-
if (isParent) {
132-
navController.navigate(
133-
AddChildProfilesViewModel.DEST_NAME,
134-
args = buildMap {
135-
put(ARG_NEXT, nextDestination)
136-
putAllFromSavedStateIfPresent(REGISTRATION_ARGS_TO_PASS)
137-
putFromSavedStateIfPresent(ARG_NEXT)
118+
when(passkeyCreated){
119+
is CreatePasskeyUseCase.CreatePasskeyResult -> {
120+
viewModelScope.launch {
121+
onReceivedCreatePasskeyResult(
122+
passkeyCreated.authenticationResponseJSON,
123+
savePerson
124+
)
138125
}
139-
)
140-
141-
} else {
142-
enrollToCourseFromInviteUid(savePerson.personUid)
143-
val goOptions = UstadMobileSystemCommon.UstadGoOptions(clearStack = true)
144-
Napier.d { "AddSignUpPresenter: go to next destination: $nextDestination" }
145-
navController.navigateToViewUri(
146-
nextDestination.appendSelectedAccount(
147-
savePerson.personUid,
148-
LearningSpace(accountManager.activeLearningSpace.url)
149-
),
150-
goOptions
151-
)
152126

127+
}
128+
is CreatePasskeyUseCase.Error ->{
129+
_uiState.update { prev ->
130+
prev.copy(
131+
errorText = passkeyCreated.message,
132+
)
133+
}
134+
}
135+
is CreatePasskeyUseCase.UserCanceledResult ->{
136+
//do nothing
137+
}
138+
139+
null -> {
140+
//do nothing
141+
}
153142
}
143+
154144
}
155145

156-
// navController.popBackStack(SignUpViewModel.DEST_NAME,false)
157146

158147
}
148+
149+
150+
private suspend fun onReceivedCreatePasskeyResult(
151+
passkeyCreated: AuthenticationResponseJSON,
152+
savePerson: Person
153+
) {
154+
passkeyCreated?.let {
155+
accountManager.registerWithPasskey(
156+
serverUrl,
157+
it,
158+
savePerson,
159+
_uiState.value.personPicture
160+
)
161+
}
162+
if (passkeyCreated == null) {
163+
snackDispatcher.showSnackBar(Snack(message = systemImpl.getString(MR.strings.sorry_something_went_wrong)))
164+
Napier.e { "Error occurred during creating passkey" }
165+
return
166+
}
167+
if (isParent) {
168+
navController.navigate(
169+
AddChildProfilesViewModel.DEST_NAME,
170+
args = buildMap {
171+
put(ARG_NEXT, nextDestination)
172+
putAllFromSavedStateIfPresent(REGISTRATION_ARGS_TO_PASS)
173+
putFromSavedStateIfPresent(ARG_NEXT)
174+
}
175+
)
176+
177+
} else {
178+
enrollToCourseFromInviteUid(savePerson.personUid)
179+
val goOptions = UstadMobileSystemCommon.UstadGoOptions(clearStack = true)
180+
Napier.d { "AddSignUpPresenter: go to next destination: $nextDestination" }
181+
navController.navigateToViewUri(
182+
nextDestination.appendSelectedAccount(
183+
savePerson.personUid,
184+
LearningSpace(accountManager.activeLearningSpace.url)
185+
),
186+
goOptions
187+
)
188+
189+
}
190+
}
191+
159192
fun onClickCreateLocalAccount() {
160193
loadingState = LoadingUiState.INDETERMINATE
161194

0 commit comments

Comments
 (0)