-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1344 from radixdlt/sp/add-factor
Add device factor source
- Loading branch information
Showing
45 changed files
with
2,251 additions
and
229 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
...in/java/com/babylon/wallet/android/data/repository/factors/DeviceMnemonicBuilderClient.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package com.babylon.wallet.android.data.repository.factors | ||
|
||
import com.babylon.wallet.android.di.coroutines.DefaultDispatcher | ||
import com.babylon.wallet.android.presentation.common.seedphrase.SeedPhraseWord | ||
import com.babylon.wallet.android.utils.callSafely | ||
import com.radixdlt.sargon.CommonException | ||
import com.radixdlt.sargon.DeviceMnemonicBuildOutcome | ||
import com.radixdlt.sargon.DeviceMnemonicBuilder | ||
import com.radixdlt.sargon.os.SargonOsManager | ||
import kotlinx.coroutines.CoroutineDispatcher | ||
import kotlinx.coroutines.withContext | ||
import rdx.works.core.mapWhen | ||
import javax.inject.Inject | ||
import javax.inject.Singleton | ||
|
||
@Singleton | ||
class DeviceMnemonicBuilderClient @Inject constructor( | ||
private val sargonOsManager: SargonOsManager, | ||
@DefaultDispatcher private val dispatcher: CoroutineDispatcher | ||
) { | ||
|
||
private var deviceMnemonicBuilder = DeviceMnemonicBuilder() | ||
|
||
suspend fun generateMnemonicWords(): List<SeedPhraseWord> = withContext(dispatcher) { | ||
executeMutating { generateNewMnemonic() } | ||
getWords(SeedPhraseWord.State.ValidDisabled) | ||
} | ||
|
||
suspend fun createMnemonicFromWords(words: List<SeedPhraseWord>): List<SeedPhraseWord> = withContext(dispatcher) { | ||
runCatching { | ||
executeMutating { createMnemonicFromWords(words.map { it.value }) } | ||
}.fold( | ||
onSuccess = { getWords(SeedPhraseWord.State.Valid) }, | ||
onFailure = { throwable -> | ||
val invalidIndices = (throwable as? CommonException.InvalidMnemonicWords)?.indicesInMnemonic?.map { | ||
it.toInt() | ||
} ?: List(words.size) { index -> index } | ||
words.mapWhen( | ||
predicate = { it.index in invalidIndices }, | ||
mutation = { it.copy(state = SeedPhraseWord.State.Invalid) } | ||
) | ||
} | ||
) | ||
} | ||
|
||
suspend fun isFactorAlreadyInUse(): Result<Boolean> = sargonOsManager.callSafely(dispatcher) { | ||
isFactorSourceAlreadyInUse(deviceMnemonicBuilder.getFactorSourceId()) | ||
} | ||
|
||
suspend fun generateConfirmationWords(): List<SeedPhraseWord> = withContext(dispatcher) { | ||
val indices = deviceMnemonicBuilder.getIndicesInMnemonicOfWordsToConfirm() | ||
val lastWordIndex = indices.lastIndex | ||
indices.mapIndexed { i, index -> | ||
SeedPhraseWord( | ||
index = index.toInt(), | ||
lastWord = i == lastWordIndex | ||
) | ||
} | ||
} | ||
|
||
suspend fun confirmWords(words: List<SeedPhraseWord>): DeviceMnemonicBuildOutcome = withContext(dispatcher) { | ||
deviceMnemonicBuilder.build(words.associate { it.index.toUByte() to it.value }) | ||
} | ||
|
||
suspend fun getWords(state: SeedPhraseWord.State): List<SeedPhraseWord> = withContext(dispatcher) { | ||
val bip39Words = deviceMnemonicBuilder.getWords() | ||
val lastWordIndex = bip39Words.lastIndex | ||
bip39Words.mapIndexed { index, bip39Word -> | ||
SeedPhraseWord( | ||
index = index, | ||
value = bip39Word.word, | ||
state = state, | ||
lastWord = index == lastWordIndex | ||
) | ||
} | ||
} | ||
|
||
private suspend fun executeMutating(function: suspend DeviceMnemonicBuilder.() -> DeviceMnemonicBuilder) = withContext(dispatcher) { | ||
deviceMnemonicBuilder = deviceMnemonicBuilder.function() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
...c/main/java/com/babylon/wallet/android/presentation/addfactorsource/AddFactorSourceNav.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package com.babylon.wallet.android.presentation.addfactorsource | ||
|
||
import androidx.navigation.NavController | ||
import androidx.navigation.NavGraphBuilder | ||
import androidx.navigation.NavOptionsBuilder | ||
import androidx.navigation.navigation | ||
import com.babylon.wallet.android.presentation.addfactorsource.device.confirmseedphrase.confirmDeviceSeedPhrase | ||
import com.babylon.wallet.android.presentation.addfactorsource.device.seedphrase.deviceSeedPhrase | ||
import com.babylon.wallet.android.presentation.addfactorsource.intro.ROUTE_ADD_FACTOR_INTRO | ||
import com.babylon.wallet.android.presentation.addfactorsource.intro.addFactorIntro | ||
import com.babylon.wallet.android.presentation.addfactorsource.name.setFactorName | ||
|
||
const val ROUTE_ADD_FACTOR_SOURCE_GRAPH = "add_factor_source_graph" | ||
|
||
fun NavController.addFactorSource( | ||
navOptionsBuilder: NavOptionsBuilder.() -> Unit = {} | ||
) { | ||
navigate(ROUTE_ADD_FACTOR_SOURCE_GRAPH, navOptionsBuilder) | ||
} | ||
|
||
fun NavGraphBuilder.addFactorSource( | ||
navController: NavController | ||
) { | ||
navigation( | ||
startDestination = ROUTE_ADD_FACTOR_INTRO, | ||
route = ROUTE_ADD_FACTOR_SOURCE_GRAPH | ||
) { | ||
addFactorIntro(navController) | ||
|
||
deviceSeedPhrase(navController) | ||
|
||
confirmDeviceSeedPhrase(navController) | ||
|
||
setFactorName(navController) | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
...a/com/babylon/wallet/android/presentation/addfactorsource/AddFactorSourceProxyContract.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package com.babylon.wallet.android.presentation.addfactorsource | ||
|
||
import com.radixdlt.sargon.FactorSourceId | ||
import com.radixdlt.sargon.FactorSourceKind | ||
|
||
interface AddFactorSourceProxy { | ||
|
||
suspend fun addFactorSource(kind: FactorSourceKind): AddFactorSourceOutput.Id | ||
} | ||
|
||
interface AddFactorSourceIOHandler { | ||
|
||
fun getInput(): AddFactorSourceInput | ||
|
||
suspend fun setOutput(output: AddFactorSourceOutput) | ||
} | ||
|
||
sealed interface AddFactorSourceInput { | ||
|
||
data class WithKind(val kind: FactorSourceKind) : AddFactorSourceInput | ||
|
||
data object Init : AddFactorSourceInput | ||
} | ||
|
||
sealed interface AddFactorSourceOutput { | ||
|
||
data class Id(val value: FactorSourceId) : AddFactorSourceOutput | ||
|
||
data object Init : AddFactorSourceOutput | ||
} |
41 changes: 41 additions & 0 deletions
41
.../java/com/babylon/wallet/android/presentation/addfactorsource/AddFactorSourceProxyImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.babylon.wallet.android.presentation.addfactorsource | ||
|
||
import com.babylon.wallet.android.utils.AppEvent | ||
import com.babylon.wallet.android.utils.AppEventBus | ||
import com.radixdlt.sargon.FactorSourceKind | ||
import kotlinx.coroutines.flow.MutableSharedFlow | ||
import kotlinx.coroutines.flow.first | ||
import javax.inject.Inject | ||
import javax.inject.Singleton | ||
|
||
@Singleton | ||
class AddFactorSourceProxyImpl @Inject constructor( | ||
private val appEventBus: AppEventBus | ||
) : AddFactorSourceProxy, AddFactorSourceIOHandler { | ||
|
||
private var input: AddFactorSourceInput = AddFactorSourceInput.Init | ||
private val _output = MutableSharedFlow<AddFactorSourceOutput>() | ||
|
||
override suspend fun addFactorSource(kind: FactorSourceKind): AddFactorSourceOutput.Id { | ||
input = AddFactorSourceInput.WithKind(kind) | ||
|
||
appEventBus.sendEvent(AppEvent.AddFactorSource) | ||
val result = _output.first() | ||
|
||
return result as AddFactorSourceOutput.Id | ||
} | ||
|
||
override fun getInput(): AddFactorSourceInput { | ||
return input | ||
} | ||
|
||
override suspend fun setOutput(output: AddFactorSourceOutput) { | ||
_output.emit(output) | ||
reset() | ||
} | ||
|
||
private suspend fun reset() { | ||
input = AddFactorSourceInput.Init | ||
_output.emit(AddFactorSourceOutput.Init) | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
...droid/presentation/addfactorsource/device/confirmseedphrase/ConfirmDeviceSeedPhraseNav.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.babylon.wallet.android.presentation.addfactorsource.device.confirmseedphrase | ||
|
||
import androidx.compose.animation.AnimatedContentTransitionScope | ||
import androidx.compose.animation.EnterTransition | ||
import androidx.compose.animation.ExitTransition | ||
import androidx.hilt.navigation.compose.hiltViewModel | ||
import androidx.navigation.NavController | ||
import androidx.navigation.NavGraphBuilder | ||
import androidx.navigation.compose.composable | ||
import com.babylon.wallet.android.presentation.addfactorsource.name.setFactorName | ||
|
||
private const val ROUTE_CONFIRM_DEVICE_SEED_PHRASE = "confirm_device_seed_phrase" | ||
|
||
fun NavController.confirmDeviceSeedPhrase() { | ||
navigate(ROUTE_CONFIRM_DEVICE_SEED_PHRASE) | ||
} | ||
|
||
fun NavGraphBuilder.confirmDeviceSeedPhrase( | ||
navController: NavController | ||
) { | ||
composable( | ||
route = ROUTE_CONFIRM_DEVICE_SEED_PHRASE, | ||
enterTransition = { slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Left) }, | ||
exitTransition = { ExitTransition.None }, | ||
popEnterTransition = { EnterTransition.None }, | ||
popExitTransition = { slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Right) } | ||
) { | ||
ConfirmDeviceSeedPhraseScreen( | ||
viewModel = hiltViewModel(), | ||
onDismiss = { navController.popBackStack() }, | ||
onConfirmed = { factorSourceKind, mnemonicWithPassphrase -> | ||
navController.setFactorName( | ||
factorSourceKind, | ||
mnemonicWithPassphrase | ||
) | ||
} | ||
) | ||
} | ||
} |
Oops, something went wrong.