[#1467] Activity resizing according to soft keyboard (#1506)

* [#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:
Milan 2024-07-19 12:00:50 +02:00 committed by GitHub
parent 0bc7757aa2
commit 741601b65f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 35 additions and 22 deletions

View File

@ -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
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
### Added

View File

@ -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 Restore Success dialog has been reworked into a separate screen, allowing users to opt out of the Keep screen
on while restoring option
### Fixed
- Support Screen now shows the Send button above keyboard instead of overlaying it

View File

@ -15,9 +15,10 @@
<activity
android:name=".MainActivity"
android:exported="false"
android:windowSoftInputMode="adjustResize"
android:label="@string/app_name"
android:theme="@style/Theme.App.Starting" />
</application>
</manifest>
</manifest>

View File

@ -11,6 +11,7 @@ import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
@ -133,6 +134,7 @@ class MainActivity : AppCompatActivity() {
Modifier
.fillMaxWidth()
.fillMaxHeight()
.imePadding()
) {
BindCompLocalProvider {
MainContent()

View File

@ -30,14 +30,11 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
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.saveable.rememberSaveable
import androidx.compose.runtime.setValue
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.layout.onSizeChanged
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
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 kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.persistentHashSetOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.delay
@Preview
@Composable
@ -224,7 +220,6 @@ fun RestoreWallet(
paste: () -> String?,
onFinished: () -> Unit
) {
val scope = rememberCoroutineScope()
var text by rememberSaveable { mutableStateOf("") }
val parseResult = ParseResult.new(completeWordList, text)
@ -237,10 +232,16 @@ fun RestoreWallet(
}
// To avoid unnecessary recompositions that this flow produces
SideEffect {
scope.launch {
userWordList.wordValidation().collect {
isSeedValid = it is SeedPhraseValidation.Valid
LaunchedEffect(Unit) {
userWordList.wordValidation().collect {
if (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 -> {
RestoreSeedBirthdayTopAppBar(
onBack = {
@ -287,6 +289,7 @@ fun RestoreWallet(
.fillMaxWidth()
)
}
RestoreStage.Birthday -> {
// No content. The action button is part of scrollable content.
}
@ -318,6 +321,7 @@ fun RestoreWallet(
modifier = commonModifier
)
}
RestoreStage.Birthday -> {
RestoreBirthdayMainContent(
zcashNetwork = zcashNetwork,
@ -400,7 +404,7 @@ private fun RestoreSeedMainContent(
goNext: () -> Unit,
modifier: Modifier = Modifier,
) {
val scope = rememberCoroutineScope()
val focusManager = LocalFocusManager.current
val scrollState = rememberScrollState()
val focusRequester = remember { FocusRequester() }
val textFieldScrollToHeight = rememberSaveable { mutableIntStateOf(0) }
@ -468,24 +472,21 @@ private fun RestoreSeedMainContent(
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
}
if (isSeedValid) {
// Clear focus and hide keyboard to make it easier for users to see the next button
LocalSoftwareKeyboardController.current?.hide()
LocalFocusManager.current.clearFocus()
LaunchedEffect(isSeedValid) {
if (isSeedValid) {
// Clear focus and hide keyboard to make it easier for users to see the next button
focusManager.clearFocus()
}
}
DisposableEffect(parseResult) {
LaunchedEffect(parseResult) {
// Causes the TextFiled to refocus
if (!isSeedValid) {
focusRequester.requestFocus()
}
// Causes scroll to the TextField after the first type action
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 -> {
Pair(false, parseResult.suggestions)
}
is ParseResult.Warn -> {
return
}
else -> {
Pair(false, null)
}