Updated on 2026-08-14
This commit is contained in:
parent
8f845111f3
commit
3a20cd143c
3 changed files with 105 additions and 0 deletions
|
|
@ -0,0 +1,49 @@
|
|||
package com.tangem.feature.onboarding.domain
|
||||
|
||||
import com.tangem.utils.extensions.isNotWhitespace
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class PartWordFinder {
|
||||
|
||||
fun getLeadPartOfWord(text: String, cursorPosition: Int): String? {
|
||||
val charText = text.toCharArray().asList()
|
||||
if (cursorPosition > charText.size || cursorPosition < 0) {
|
||||
// cursorPosition is out of text size
|
||||
return null
|
||||
}
|
||||
if (cursorPosition == 0) {
|
||||
// cursorPosition at start of text
|
||||
return null
|
||||
}
|
||||
if (charText[cursorPosition - 1].isWhitespace()) {
|
||||
// white space to the left of cursorPosition
|
||||
return null
|
||||
}
|
||||
if (charText.size > cursorPosition && charText[cursorPosition].isNotWhitespace()) {
|
||||
// cursorPosition in the middle of a word
|
||||
return null
|
||||
}
|
||||
|
||||
for (charIndex in cursorPosition - 1 downTo 0) {
|
||||
val char = charText[charIndex]
|
||||
when {
|
||||
charIndex == 0 -> {
|
||||
return text.substring(charIndex, cursorPosition)
|
||||
}
|
||||
char.isWhitespace() -> {
|
||||
return text.substring(charIndex + 1, cursorPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun getLastPartOfWord(text: String, word: String, cursorPosition: Int): String {
|
||||
val leadPart = getLeadPartOfWord(text, cursorPosition) ?: return ""
|
||||
|
||||
return word.substring(leadPart.length, word.length)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.feature.onboarding.presentation.wallet2.ui
|
||||
|
||||
import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.tangem.feature.onboarding.domain.InsertSuggestionResult
|
||||
import com.tangem.feature.onboarding.domain.SeedPhraseError
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.model.OnboardingSeedPhraseState
|
||||
|
||||
|
|
@ -42,6 +44,26 @@ class ImportSeedPhraseStateBuilder {
|
|||
),
|
||||
)
|
||||
|
||||
fun updateSuggestions(
|
||||
uiState: OnboardingSeedPhraseState,
|
||||
suggestions: List<String>,
|
||||
): OnboardingSeedPhraseState = uiState.copy(
|
||||
importSeedPhraseState = uiState.importSeedPhraseState.copy(
|
||||
suggestionsList = suggestions,
|
||||
),
|
||||
)
|
||||
|
||||
fun insertSuggestionWord(
|
||||
uiState: OnboardingSeedPhraseState,
|
||||
insertResult: InsertSuggestionResult,
|
||||
): OnboardingSeedPhraseState {
|
||||
val newTextFieldValue = uiState.importSeedPhraseState.tvSeedPhrase.textFieldValue.copy(
|
||||
text = insertResult.text,
|
||||
selection = TextRange(insertResult.cursorPosition, insertResult.cursorPosition),
|
||||
)
|
||||
return updateTextField(uiState, newTextFieldValue)
|
||||
}
|
||||
|
||||
fun updateError(
|
||||
uiState: OnboardingSeedPhraseState,
|
||||
error: SeedPhraseError?,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
|
@ -51,6 +52,7 @@ class SeedPhraseViewModel @Inject constructor(
|
|||
get() = uiState.step
|
||||
|
||||
private val textFieldsDebouncers = mutableMapOf<String, Debouncer>()
|
||||
private var suggestionWordInserted: AtomicBoolean = AtomicBoolean(false)
|
||||
|
||||
override fun onCleared() {
|
||||
textFieldsDebouncers.forEach { entry -> entry.value.release() }
|
||||
|
|
@ -138,18 +140,25 @@ class SeedPhraseViewModel @Inject constructor(
|
|||
val inputMnemonic = fieldState.textFieldValue.text
|
||||
|
||||
when {
|
||||
suggestionWordInserted.getAndSet(false) -> {
|
||||
validateMnemonic(inputMnemonic)
|
||||
return@launchSingle
|
||||
}
|
||||
isSameText && !isCursorMoved -> {
|
||||
return@launchSingle
|
||||
}
|
||||
isSameText && isCursorMoved -> {
|
||||
updateSuggestions(fieldState)
|
||||
return@launchSingle
|
||||
}
|
||||
}
|
||||
|
||||
val isPasteFromClipboard = textFieldValue.text.length - oldTextFieldValue.text.length > 1
|
||||
if (isPasteFromClipboard) {
|
||||
updateSuggestions(fieldState)
|
||||
validateMnemonic(inputMnemonic)
|
||||
} else {
|
||||
updateSuggestions(fieldState)
|
||||
val debouncer = createOrGetDebouncer(MNEMONIC_DEBOUNCER)
|
||||
debouncer.debounce(viewModelScope, MNEMONIC_DEBOUNCE_DELAY, dispatchers.io) {
|
||||
validateMnemonic(inputMnemonic)
|
||||
|
|
@ -180,6 +189,15 @@ class SeedPhraseViewModel @Inject constructor(
|
|||
updateUi { uiBuilder.importSeedPhrase.updateError(mediateState, error) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateSuggestions(fieldState: TextFieldState) {
|
||||
val suggestions = interactor.getSuggestions(
|
||||
text = fieldState.textFieldValue.text,
|
||||
hasSelection = !fieldState.textFieldValue.selection.collapsed,
|
||||
cursorPosition = fieldState.textFieldValue.selection.end,
|
||||
)
|
||||
updateUi { uiBuilder.importSeedPhrase.updateSuggestions(uiState, suggestions) }
|
||||
}
|
||||
// endregion ImportSeedPhrase
|
||||
|
||||
// region ButtonClickHandlers
|
||||
|
|
@ -250,6 +268,22 @@ class SeedPhraseViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun buttonSuggestedPhraseClick(suggestionIndex: Int) {
|
||||
viewModelScope.launchSingle {
|
||||
suggestionWordInserted.set(true)
|
||||
val textFieldValue = uiState.importSeedPhraseState.tvSeedPhrase.textFieldValue
|
||||
val word = uiState.importSeedPhraseState.suggestionsList[suggestionIndex]
|
||||
val cursorPosition = textFieldValue.selection.end
|
||||
|
||||
val insertResult = interactor.insertSuggestionWord(
|
||||
text = textFieldValue.text,
|
||||
suggestion = word,
|
||||
cursorPosition = cursorPosition,
|
||||
)
|
||||
updateUi {
|
||||
val mediateState = uiBuilder.importSeedPhrase.insertSuggestionWord(uiState, insertResult)
|
||||
uiBuilder.importSeedPhrase.updateSuggestions(mediateState, emptyList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun menuChatClick() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue