Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ internal fun WordInputGrid(
onWordsChanged: (List<List<String>>) -> Unit,
onFocusChanged: (Int) -> Unit,
onPasteMnemonic: ((String) -> Unit)? = null,
modifier: Modifier = Modifier,
) {
val wordCount =
when (numberOfWords) {
Expand All @@ -74,7 +75,7 @@ internal fun WordInputGrid(
val rightIndices = (pageStart + wordsPerColumn until (pageStart + pageSize).coerceAtMost(wordCount))

Card(
modifier = Modifier.fillMaxWidth(),
modifier = modifier.fillMaxWidth(),
colors =
CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.bitcoinppl.cove.flows.NewWalletFlow.hot_wallet

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
Expand All @@ -14,6 +15,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
Expand All @@ -39,6 +42,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -54,6 +58,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.bitcoinppl.cove.AppManager
import org.bitcoinppl.cove.ImportWalletManager
import org.bitcoinppl.cove.Log
Expand Down Expand Up @@ -92,7 +97,7 @@ private fun HotWalletImportScreenPreview() {
)
}

@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
fun HotWalletImportScreen(
app: AppManager,
Expand All @@ -111,15 +116,29 @@ fun HotWalletImportScreen(
}

val numberOfGroups = wordCount / GROUPS_OF
var enteredWords by remember(currentNumberOfWords) {
var enteredWords by remember {
mutableStateOf(List(numberOfGroups) { List(GROUPS_OF) { "" } })
}

var alertState by remember { mutableStateOf(AlertState.None) }
var duplicateWalletId by remember { mutableStateOf<WalletId?>(null) }
var genericErrorMessage by remember { mutableStateOf("") }
var focusedField by remember(currentNumberOfWords) { mutableIntStateOf(0) }
var tabIndex by remember(currentNumberOfWords) { mutableIntStateOf(0) }
var focusedField by remember { mutableIntStateOf(0) }
var tabIndex by remember { mutableIntStateOf(0) }
val pagerState = rememberPagerState(pageCount = { enteredWords.size })
val scope = rememberCoroutineScope()

// sync tabIndex from pager swipes
LaunchedEffect(pagerState.currentPage) {
tabIndex = pagerState.currentPage
}

// scroll pager when tabIndex changes from focus
LaunchedEffect(tabIndex) {
if (pagerState.currentPage != tabIndex) {
pagerState.animateScrollToPage(tabIndex)
}
}

// auto-switch page when focus changes to a word on a different page
LaunchedEffect(focusedField, enteredWords) {
Expand Down Expand Up @@ -328,21 +347,26 @@ fun HotWalletImportScreen(
Column(
modifier =
Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp),
.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
Spacer(Modifier.height(24.dp))

WordInputGrid(
enteredWords = enteredWords,
numberOfWords = currentNumberOfWords,
focusedField = focusedField,
tabIndex = tabIndex,
onWordsChanged = { newWords -> enteredWords = newWords },
onFocusChanged = { field -> focusedField = field },
onPasteMnemonic = ::handlePasteMnemonic,
)
HorizontalPager(
state = pagerState,
modifier = Modifier.fillMaxWidth(),
) { page ->
WordInputGrid(
enteredWords = enteredWords,
numberOfWords = currentNumberOfWords,
focusedField = focusedField,
tabIndex = page,
onWordsChanged = { newWords -> enteredWords = newWords },
onFocusChanged = { field -> focusedField = field },
onPasteMnemonic = ::handlePasteMnemonic,
modifier = Modifier.padding(horizontal = 20.dp),
)
}

// page indicator dots for multi-page import
if (enteredWords.size > 1) {
Expand All @@ -365,7 +389,9 @@ fun HotWalletImportScreen(
} else {
Color.White.copy(alpha = 0.33f)
},
).clickable { tabIndex = i },
).clickable {
scope.launch { pagerState.animateScrollToPage(i) }
},
)
}
}
Expand Down
14 changes: 11 additions & 3 deletions ios/Cove/Flows/NewWalletFlow/HotWallet/HotWalletImportCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,8 @@ private struct AutocompleteField: View {
}
}
.onAppear {
if !text.isEmpty, autocomplete.isBip39Word(word: text) {
state = .valid
if !text.isEmpty {
state = autocomplete.isValidWord(word: text, allWords: allEnteredWords) ? .valid : .invalid
}
}
.frame(maxWidth: .infinity)
Expand Down Expand Up @@ -342,9 +342,17 @@ private struct AutocompleteField: View {
textField.delegate = handler
}
}
.onChange(of: text, initial: false) { oldText, newText in
.onChange(of: text, initial: true) { oldText, newText in
text = newText.trimmingCharacters(in: .whitespacesAndNewlines)

// handle programmatic text changes (e.g., paste)
if oldText == newText {
if !newText.isEmpty {
state = autocomplete.isValidWord(word: newText, allWords: allEnteredWords) ? .valid : .invalid
}
return
}

filteredSuggestions = autocomplete.autocomplete(
word: newText, allWords: allEnteredWords
)
Expand Down