secant-android-wallet/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/restore/viewmodel/RestoreViewModel.kt

71 lines
2.4 KiB
Kotlin

package co.electriccoin.zcash.ui.screen.restore.viewmodel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import cash.z.ecc.android.bip39.Mnemonics
import cash.z.ecc.android.sdk.ext.collectWith
import co.electriccoin.zcash.ui.common.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.ui.screen.restore.state.WordList
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.toPersistentSet
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
import java.util.Locale
class RestoreViewModel(application: Application, savedStateHandle: SavedStateHandle) : AndroidViewModel(application) {
/**
* The complete word list that the user can choose from; useful for autocomplete
*/
// This is a hack to prevent disk IO on the main thread
val completeWordList = flow<CompleteWordSetState> {
// Using IO context because of https://github.com/zcash/kotlin-bip39/issues/13
val completeWordList = withContext(Dispatchers.IO) {
Mnemonics.getCachedWords(Locale.ENGLISH.language)
}
emit(CompleteWordSetState.Loaded(completeWordList.toPersistentSet()))
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
CompleteWordSetState.Loading
)
val userWordList: WordList = run {
val initialValue = if (savedStateHandle.contains(KEY_WORD_LIST)) {
savedStateHandle.get<ArrayList<String>>(KEY_WORD_LIST)
} else {
null
}
if (null == initialValue) {
WordList()
} else {
WordList(initialValue)
}
}
init {
// viewModelScope is constructed with Dispatchers.Main.immediate, so this will
// update the save state as soon as a change occurs.
userWordList.current.collectWith(viewModelScope) {
savedStateHandle[KEY_WORD_LIST] = ArrayList(it)
}
}
companion object {
private const val KEY_WORD_LIST = "word_list" // $NON-NLS
}
}
sealed class CompleteWordSetState {
object Loading : CompleteWordSetState()
data class Loaded(val list: ImmutableSet<String>) : CompleteWordSetState()
}