* [#1467] Activity resizing according to soft keyboard Closes #1467 * [#1467] Seed keyboard handling * [#1467] Seed keyboard handling Closes #1467 * [#1467] Documentation update * TODO reference * [#1467] Documentation update Closes #1467 * [#1467] Detekt fix Closes #1467 --------- Co-authored-by: Honza <rychnovsky.honza@gmail.com>
This commit is contained in:
parent
0bc7757aa2
commit
741601b65f
|
@ -17,6 +17,10 @@ and this application adheres to [Semantic Versioning](https://semver.org/spec/v2
|
||||||
- The Restore Success dialog has been reworked into a separate screen, allowing users to opt out of the Keep screen
|
- The Restore Success dialog has been reworked into a separate screen, allowing users to opt out of the Keep screen
|
||||||
on while restoring option
|
on while restoring option
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- Support Screen now shows the Send button above keyboard instead of overlaying it. This was achieved by setting
|
||||||
|
`adjustResize` to `MainActivity` and adding `imePadding` to top level composable
|
||||||
|
|
||||||
## [1.1.3 (682)] - 2024-07-03
|
## [1.1.3 (682)] - 2024-07-03
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -16,3 +16,6 @@ directly impact users rather than highlighting other key architectural updates.*
|
||||||
- The About screen has been redesigned to align with the new design guidelines
|
- The About screen has been redesigned to align with the new design guidelines
|
||||||
- The Restore Success dialog has been reworked into a separate screen, allowing users to opt out of the Keep screen
|
- The Restore Success dialog has been reworked into a separate screen, allowing users to opt out of the Keep screen
|
||||||
on while restoring option
|
on while restoring option
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Support Screen now shows the Send button above keyboard instead of overlaying it
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.App.Starting" />
|
android:theme="@style/Theme.App.Starting" />
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import androidx.annotation.VisibleForTesting
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
@ -133,6 +134,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
|
.imePadding()
|
||||||
) {
|
) {
|
||||||
BindCompLocalProvider {
|
BindCompLocalProvider {
|
||||||
MainContent()
|
MainContent()
|
||||||
|
|
|
@ -30,14 +30,11 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextField
|
import androidx.compose.material3.TextField
|
||||||
import androidx.compose.material3.TextFieldDefaults
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.SideEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
@ -47,7 +44,6 @@ import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.onSizeChanged
|
import androidx.compose.ui.layout.onSizeChanged
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextRange
|
import androidx.compose.ui.text.TextRange
|
||||||
|
@ -84,7 +80,7 @@ import co.electriccoin.zcash.ui.screen.restore.state.WordList
|
||||||
import co.electriccoin.zcash.ui.screen.restore.state.wordValidation
|
import co.electriccoin.zcash.ui.screen.restore.state.wordValidation
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
import kotlinx.collections.immutable.persistentHashSetOf
|
import kotlinx.collections.immutable.persistentHashSetOf
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -224,7 +220,6 @@ fun RestoreWallet(
|
||||||
paste: () -> String?,
|
paste: () -> String?,
|
||||||
onFinished: () -> Unit
|
onFinished: () -> Unit
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
var text by rememberSaveable { mutableStateOf("") }
|
var text by rememberSaveable { mutableStateOf("") }
|
||||||
val parseResult = ParseResult.new(completeWordList, text)
|
val parseResult = ParseResult.new(completeWordList, text)
|
||||||
|
|
||||||
|
@ -237,10 +232,16 @@ fun RestoreWallet(
|
||||||
}
|
}
|
||||||
|
|
||||||
// To avoid unnecessary recompositions that this flow produces
|
// To avoid unnecessary recompositions that this flow produces
|
||||||
SideEffect {
|
LaunchedEffect(Unit) {
|
||||||
scope.launch {
|
userWordList.wordValidation().collect {
|
||||||
userWordList.wordValidation().collect {
|
if (it is SeedPhraseValidation.Valid) {
|
||||||
isSeedValid = it is SeedPhraseValidation.Valid
|
// TODO [#1522]: temporary fix to wait for other states to update first
|
||||||
|
// TODO [#1522]: https://github.com/Electric-Coin-Company/zashi-android/issues/1522
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
delay(100)
|
||||||
|
isSeedValid = true
|
||||||
|
} else {
|
||||||
|
isSeedValid = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,6 +259,7 @@ fun RestoreWallet(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
RestoreStage.Birthday -> {
|
RestoreStage.Birthday -> {
|
||||||
RestoreSeedBirthdayTopAppBar(
|
RestoreSeedBirthdayTopAppBar(
|
||||||
onBack = {
|
onBack = {
|
||||||
|
@ -287,6 +289,7 @@ fun RestoreWallet(
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
RestoreStage.Birthday -> {
|
RestoreStage.Birthday -> {
|
||||||
// No content. The action button is part of scrollable content.
|
// No content. The action button is part of scrollable content.
|
||||||
}
|
}
|
||||||
|
@ -318,6 +321,7 @@ fun RestoreWallet(
|
||||||
modifier = commonModifier
|
modifier = commonModifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
RestoreStage.Birthday -> {
|
RestoreStage.Birthday -> {
|
||||||
RestoreBirthdayMainContent(
|
RestoreBirthdayMainContent(
|
||||||
zcashNetwork = zcashNetwork,
|
zcashNetwork = zcashNetwork,
|
||||||
|
@ -400,7 +404,7 @@ private fun RestoreSeedMainContent(
|
||||||
goNext: () -> Unit,
|
goNext: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val focusManager = LocalFocusManager.current
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
val textFieldScrollToHeight = rememberSaveable { mutableIntStateOf(0) }
|
val textFieldScrollToHeight = rememberSaveable { mutableIntStateOf(0) }
|
||||||
|
@ -468,24 +472,21 @@ private fun RestoreSeedMainContent(
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSeedValid) {
|
LaunchedEffect(isSeedValid) {
|
||||||
// Clear focus and hide keyboard to make it easier for users to see the next button
|
if (isSeedValid) {
|
||||||
LocalSoftwareKeyboardController.current?.hide()
|
// Clear focus and hide keyboard to make it easier for users to see the next button
|
||||||
LocalFocusManager.current.clearFocus()
|
focusManager.clearFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DisposableEffect(parseResult) {
|
LaunchedEffect(parseResult) {
|
||||||
// Causes the TextFiled to refocus
|
// Causes the TextFiled to refocus
|
||||||
if (!isSeedValid) {
|
if (!isSeedValid) {
|
||||||
focusRequester.requestFocus()
|
focusRequester.requestFocus()
|
||||||
}
|
}
|
||||||
// Causes scroll to the TextField after the first type action
|
|
||||||
if (text.isNotEmpty() && userWordList.current.value.isEmpty()) {
|
if (text.isNotEmpty() && userWordList.current.value.isEmpty()) {
|
||||||
scope.launch {
|
scrollState.animateScrollTo(textFieldScrollToHeight.intValue)
|
||||||
scrollState.animateScrollTo(textFieldScrollToHeight.intValue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
onDispose { /* Nothing to dispose */ }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,9 +675,11 @@ private fun Autocomplete(
|
||||||
is ParseResult.Autocomplete -> {
|
is ParseResult.Autocomplete -> {
|
||||||
Pair(false, parseResult.suggestions)
|
Pair(false, parseResult.suggestions)
|
||||||
}
|
}
|
||||||
|
|
||||||
is ParseResult.Warn -> {
|
is ParseResult.Warn -> {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Pair(false, null)
|
Pair(false, null)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue