[#1134] Home screens UI improvements

* [#1134] Improve Home sub-screens paddings

* [#1134] Rework Home Scaffold to ConstraintLayout

* [#1134] Rework Home screen TextFields

Plus, unify Home sub-screens bottom action buttons position

* [#1134] Fix Textfiled height jumping

* Changelog update
This commit is contained in:
Honza Rychnovský 2023-12-21 16:15:20 +01:00 committed by GitHub
parent c813c54827
commit 90c982ac2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 239 additions and 137 deletions

View File

@ -14,6 +14,8 @@ directly impact users rather than highlighting other key architectural updates.*
- Re-enabled the possibility of installing different Zashi application build types on the same device simultaneously - Re-enabled the possibility of installing different Zashi application build types on the same device simultaneously
(i.e., Mainnet, Testnet, Production, Debug) (i.e., Mainnet, Testnet, Production, Debug)
- Send screen form now validates a maximum amount for sending with respect to the available balance - Send screen form now validates a maximum amount for sending with respect to the available balance
- Send form now supports software keyboard confirm actions
- And a few more miner UI improvements
## [0.2.0 (505)] - 2023-12-11 ## [0.2.0 (505)] - 2023-12-11

View File

@ -1,6 +1,10 @@
package co.electriccoin.zcash.ui.design.component package co.electriccoin.zcash.ui.design.component
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.relocation.bringIntoViewRequester
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -8,14 +12,19 @@ import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldColors import androidx.compose.material3.TextFieldColors
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusEvent
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import kotlinx.coroutines.launch
@OptIn(ExperimentalFoundationApi::class)
@Suppress("LongParameterList") @Suppress("LongParameterList")
@Composable @Composable
fun FormTextField( fun FormTextField(
@ -38,7 +47,29 @@ fun FormTextField(
shape: Shape = TextFieldDefaults.shape, shape: Shape = TextFieldDefaults.shape,
// To enable border around the TextField // To enable border around the TextField
withBorder: Boolean = true, withBorder: Boolean = true,
bringIntoViewRequester: BringIntoViewRequester = remember { BringIntoViewRequester() }
) { ) {
val coroutineScope = rememberCoroutineScope()
val composedModifier =
modifier
.defaultMinSize(minHeight = ZcashTheme.dimens.textFieldDefaultHeight)
.onFocusEvent { focusState ->
if (focusState.isFocused) {
coroutineScope.launch {
bringIntoViewRequester.bringIntoView()
}
}
}
.bringIntoViewRequester(bringIntoViewRequester)
.then(
if (withBorder) {
modifier.border(width = 1.dp, color = MaterialTheme.colorScheme.primary)
} else {
Modifier
}
)
TextField( TextField(
value = value, value = value,
onValueChange = onValueChange, onValueChange = onValueChange,
@ -46,14 +77,7 @@ fun FormTextField(
textStyle = textStyle, textStyle = textStyle,
keyboardOptions = keyboardOptions, keyboardOptions = keyboardOptions,
colors = colors, colors = colors,
modifier = modifier = composedModifier,
modifier.then(
if (withBorder) {
modifier.border(width = 1.dp, color = MaterialTheme.colorScheme.primary)
} else {
Modifier
}
),
leadingIcon = leadingIcon, leadingIcon = leadingIcon,
trailingIcon = trailingIcon, trailingIcon = trailingIcon,
keyboardActions = keyboardActions, keyboardActions = keyboardActions,

View File

@ -35,13 +35,15 @@ data class Dimens(
val topAppBarActionRippleCorner: Dp, val topAppBarActionRippleCorner: Dp,
// TextField: // TextField:
val textFieldDefaultHeight: Dp, val textFieldDefaultHeight: Dp,
val textFieldPanelDefaultHeight: Dp,
// Any Layout: // Any Layout:
val layoutStroke: Dp, val layoutStroke: Dp,
// Screen custom spacings: // Screen custom spacings:
val inScreenZcashLogoHeight: Dp, val inScreenZcashLogoHeight: Dp,
val inScreenZcashLogoWidth: Dp, val inScreenZcashLogoWidth: Dp,
val inScreenZcashTextLogoHeight: Dp, val inScreenZcashTextLogoHeight: Dp,
val screenHorizontalSpacing: Dp, val screenHorizontalSpacingBig: Dp,
val screenHorizontalSpacingRegular: Dp,
) )
private val defaultDimens = private val defaultDimens =
@ -64,12 +66,14 @@ private val defaultDimens =
circularScreenProgressWidth = 48.dp, circularScreenProgressWidth = 48.dp,
topAppBarZcashLogoHeight = 24.dp, topAppBarZcashLogoHeight = 24.dp,
topAppBarActionRippleCorner = 28.dp, topAppBarActionRippleCorner = 28.dp,
textFieldDefaultHeight = 215.dp, textFieldDefaultHeight = 64.dp,
textFieldPanelDefaultHeight = 215.dp,
layoutStroke = 1.dp, layoutStroke = 1.dp,
inScreenZcashLogoHeight = 100.dp, inScreenZcashLogoHeight = 100.dp,
inScreenZcashLogoWidth = 60.dp, inScreenZcashLogoWidth = 60.dp,
inScreenZcashTextLogoHeight = 30.dp, inScreenZcashTextLogoHeight = 30.dp,
screenHorizontalSpacing = 64.dp, screenHorizontalSpacingBig = 64.dp,
screenHorizontalSpacingRegular = 32.dp,
) )
private val normalDimens = defaultDimens private val normalDimens = defaultDimens

View File

@ -78,8 +78,8 @@ fun About(
.padding( .padding(
top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault, top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault,
bottom = paddingValues.calculateBottomPadding() + ZcashTheme.dimens.spacingDefault, bottom = paddingValues.calculateBottomPadding() + ZcashTheme.dimens.spacingDefault,
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingBig,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingBig
) )
) )
} }

View File

@ -77,8 +77,8 @@ fun Account(
Modifier.padding( Modifier.padding(
top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault, top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault,
bottom = paddingValues.calculateBottomPadding() + ZcashTheme.dimens.spacingHuge, bottom = paddingValues.calculateBottomPadding() + ZcashTheme.dimens.spacingHuge,
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingRegular,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingRegular
) )
) )
} }
@ -115,9 +115,7 @@ private fun AccountMainContent(
Column( Column(
Modifier Modifier
.fillMaxHeight() .fillMaxHeight()
.verticalScroll( .verticalScroll(rememberScrollState())
rememberScrollState()
)
.then(modifier), .then(modifier),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {

View File

@ -1,10 +1,14 @@
package co.electriccoin.zcash.ui.screen.balances.view package co.electriccoin.zcash.ui.screen.balances.view
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
@ -47,8 +51,8 @@ fun Balances(onSettings: () -> Unit) {
Modifier.padding( Modifier.padding(
top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault, top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault,
bottom = paddingValues.calculateBottomPadding() + ZcashTheme.dimens.spacingHuge, bottom = paddingValues.calculateBottomPadding() + ZcashTheme.dimens.spacingHuge,
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingRegular,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingRegular
) )
) )
} }
@ -74,11 +78,15 @@ private fun BalancesTopAppBar(onSettings: () -> Unit) {
@Composable @Composable
private fun BalancesMainContent(modifier: Modifier = Modifier) { private fun BalancesMainContent(modifier: Modifier = Modifier) {
Box( Column(
Modifier modifier =
.fillMaxSize() Modifier
.then(modifier), .imePadding()
contentAlignment = Alignment.Center .fillMaxSize()
.verticalScroll(rememberScrollState())
.then(modifier),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) { ) {
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault)) Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))

View File

@ -70,8 +70,8 @@ fun ExportPrivateData(
.padding( .padding(
top = paddingValues.calculateTopPadding(), top = paddingValues.calculateTopPadding(),
bottom = paddingValues.calculateBottomPadding(), bottom = paddingValues.calculateBottomPadding(),
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingBig,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingBig
) )
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) )

View File

@ -11,7 +11,6 @@ import androidx.compose.foundation.pager.PagerDefaults
import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.Divider import androidx.compose.material3.Divider
import androidx.compose.material3.DividerDefaults import androidx.compose.material3.DividerDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Tab import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow import androidx.compose.material3.TabRow
import androidx.compose.material3.TabRowDefaults import androidx.compose.material3.TabRowDefaults
@ -24,6 +23,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import co.electriccoin.zcash.spackle.Twig import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.design.component.GradientSurface import co.electriccoin.zcash.ui.design.component.GradientSurface
import co.electriccoin.zcash.ui.design.component.NavigationTabText import co.electriccoin.zcash.ui.design.component.NavigationTabText
@ -85,52 +86,9 @@ fun Home(
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
Scaffold( ConstraintLayout {
bottomBar = { val (pager, tabRow) = createRefs()
Column {
Divider(
thickness = DividerDefaults.Thickness,
color = ZcashTheme.colors.dividerColor
)
TabRow(
selectedTabIndex = pagerState.currentPage,
// Don't use the predefined divider, as it's fixed position is below the tabs bar
divider = {},
indicator = { tabPositions ->
TabRowDefaults.Indicator(
modifier =
Modifier
.tabIndicatorOffset(tabPositions[pagerState.currentPage])
.padding(horizontal = ZcashTheme.dimens.spacingDefault),
color = ZcashTheme.colors.complementaryColor
)
},
modifier =
Modifier
.navigationBarsPadding()
.padding(all = ZcashTheme.dimens.spacingDefault)
) {
subScreens.forEachIndexed { index, item ->
val selected = index == pagerState.currentPage
Tab(
selected = selected,
text = {
NavigationTabText(
text = item.title,
selected = selected
)
},
modifier =
Modifier
.padding(all = 0.dp)
.testTag(item.testTag),
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
)
}
}
}
}
) { paddingValues ->
HorizontalPager( HorizontalPager(
state = pagerState, state = pagerState,
pageSpacing = 0.dp, pageSpacing = 0.dp,
@ -147,10 +105,68 @@ fun Home(
}, },
beyondBoundsPageCount = 1, beyondBoundsPageCount = 1,
modifier = modifier =
Modifier Modifier.constrainAs(pager) {
.padding( top.linkTo(parent.top)
bottom = paddingValues.calculateBottomPadding() bottom.linkTo(tabRow.top)
) start.linkTo(parent.start)
end.linkTo(parent.end)
width = Dimension.fillToConstraints
height = Dimension.fillToConstraints
}
) )
Column(
modifier =
Modifier.constrainAs(tabRow) {
top.linkTo(pager.bottom)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
end.linkTo(parent.end)
width = Dimension.fillToConstraints
height = Dimension.wrapContent
}
) {
Divider(
thickness = DividerDefaults.Thickness,
color = ZcashTheme.colors.dividerColor
)
TabRow(
selectedTabIndex = pagerState.currentPage,
// Don't use the predefined divider, as it's fixed position is below the tabs bar
divider = {},
indicator = { tabPositions ->
TabRowDefaults.Indicator(
modifier =
Modifier
.tabIndicatorOffset(tabPositions[pagerState.currentPage])
.padding(horizontal = ZcashTheme.dimens.spacingDefault),
color = ZcashTheme.colors.complementaryColor
)
},
modifier =
Modifier
.navigationBarsPadding()
.padding(all = ZcashTheme.dimens.spacingDefault)
) {
subScreens.forEachIndexed { index, item ->
val selected = index == pagerState.currentPage
Tab(
selected = selected,
text = {
NavigationTabText(
text = item.title,
selected = selected
)
},
modifier =
Modifier
.padding(all = 0.dp)
.testTag(item.testTag),
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
)
}
}
}
} }
} }

View File

@ -139,7 +139,7 @@ private fun NewWalletRecoveryMainContent(
TopScreenLogoTitle( TopScreenLogoTitle(
title = stringResource(R.string.new_wallet_recovery_header), title = stringResource(R.string.new_wallet_recovery_header),
logoContentDescription = stringResource(R.string.zcash_logo_content_description), logoContentDescription = stringResource(R.string.zcash_logo_content_description),
modifier = Modifier.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacing) modifier = Modifier.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacingBig)
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge)) Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
@ -147,7 +147,7 @@ private fun NewWalletRecoveryMainContent(
BodySmall( BodySmall(
text = stringResource(R.string.new_wallet_recovery_description), text = stringResource(R.string.new_wallet_recovery_description),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
modifier = Modifier.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacing) modifier = Modifier.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacingBig)
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault)) Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
@ -174,8 +174,8 @@ private fun NewWalletRecoveryMainContent(
Modifier Modifier
.padding( .padding(
bottom = ZcashTheme.dimens.spacingHuge, bottom = ZcashTheme.dimens.spacingHuge,
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingBig,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingBig
) )
) )
} }

View File

@ -115,8 +115,8 @@ fun ShortOnboarding(
.padding( .padding(
top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingHuge, top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingHuge,
bottom = paddingValues.calculateBottomPadding(), bottom = paddingValues.calculateBottomPadding(),
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingBig,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingBig
) )
.height(screenHeight.contentHeight - paddingValues.calculateBottomPadding()) .height(screenHeight.contentHeight - paddingValues.calculateBottomPadding())
) )

View File

@ -4,7 +4,6 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
@ -15,6 +14,7 @@ import androidx.compose.material.icons.filled.BrightnessLow
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -70,8 +70,7 @@ fun Receive(
) { ) {
val (brightness, setBrightness) = rememberSaveable { mutableStateOf(false) } val (brightness, setBrightness) = rememberSaveable { mutableStateOf(false) }
// Rework this into Scaffold Scaffold(topBar = {
Column {
ReceiveTopAppBar( ReceiveTopAppBar(
adjustBrightness = brightness, adjustBrightness = brightness,
onSettings = onSettings, onSettings = onSettings,
@ -80,19 +79,18 @@ fun Receive(
setBrightness(!brightness) setBrightness(!brightness)
} }
) )
}) { paddingValues ->
ReceiveContents( ReceiveContents(
walletAddress = walletAddress, walletAddress = walletAddress,
onAddressDetails = onAddressDetails, onAddressDetails = onAddressDetails,
adjustBrightness = brightness, adjustBrightness = brightness,
modifier = modifier =
Modifier Modifier.padding(
.fillMaxHeight() top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault,
.verticalScroll(rememberScrollState()) bottom = paddingValues.calculateBottomPadding() + ZcashTheme.dimens.spacingHuge,
.padding( start = ZcashTheme.dimens.screenHorizontalSpacingRegular,
top = ZcashTheme.dimens.spacingDefault, end = ZcashTheme.dimens.screenHorizontalSpacingRegular
start = ZcashTheme.dimens.screenHorizontalSpacing, )
end = ZcashTheme.dimens.screenHorizontalSpacing
)
) )
} }
} }
@ -144,7 +142,11 @@ private fun ReceiveContents(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Column( Column(
modifier = modifier.fillMaxWidth(), modifier =
Modifier
.fillMaxHeight()
.verticalScroll(rememberScrollState())
.then(modifier),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
QrCode( QrCode(
@ -181,14 +183,12 @@ private fun ReceiveContents(
.weight(MINIMAL_WEIGHT) .weight(MINIMAL_WEIGHT)
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge)) Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
PrimaryButton( PrimaryButton(
onClick = onAddressDetails, onClick = onAddressDetails,
text = stringResource(id = R.string.receive_see_address_details) text = stringResource(id = R.string.receive_see_address_details)
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
} }
} }

View File

@ -77,8 +77,8 @@ fun Request(
Modifier.padding( Modifier.padding(
top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault, top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault,
bottom = paddingValues.calculateTopPadding(), bottom = paddingValues.calculateTopPadding(),
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingRegular,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingRegular
) )
) )
} }

View File

@ -4,6 +4,7 @@ package co.electriccoin.zcash.ui.screen.restore.view
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -236,8 +237,8 @@ fun RestoreWallet(
.padding( .padding(
top = paddingValues.calculateTopPadding(), top = paddingValues.calculateTopPadding(),
bottom = paddingValues.calculateBottomPadding(), bottom = paddingValues.calculateBottomPadding(),
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingBig,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingBig
) )
when (currentStage) { when (currentStage) {
@ -487,7 +488,7 @@ private fun SeedGridWithText(
) )
) )
.fillMaxWidth() .fillMaxWidth()
.defaultMinSize(minHeight = ZcashTheme.dimens.textFieldDefaultHeight) .defaultMinSize(minHeight = ZcashTheme.dimens.textFieldPanelDefaultHeight)
.then(modifier) .then(modifier)
.testTag(RestoreTag.CHIP_LAYOUT) .testTag(RestoreTag.CHIP_LAYOUT)
) { ) {
@ -674,6 +675,7 @@ private fun Warn(
} }
} }
@OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
@Suppress("LongMethod") @Suppress("LongMethod")
private fun RestoreBirthdayMainContent( private fun RestoreBirthdayMainContent(

View File

@ -302,7 +302,7 @@ private fun ScanMainContent(
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
vertical = ZcashTheme.dimens.spacingHuge, vertical = ZcashTheme.dimens.spacingHuge,
horizontal = ZcashTheme.dimens.screenHorizontalSpacing horizontal = ZcashTheme.dimens.screenHorizontalSpacingBig
) )
) )
} }

View File

@ -82,8 +82,8 @@ fun SecurityWarning(
.padding( .padding(
top = paddingValues.calculateTopPadding(), top = paddingValues.calculateTopPadding(),
bottom = paddingValues.calculateBottomPadding(), bottom = paddingValues.calculateBottomPadding(),
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingBig,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingBig
) )
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) )

View File

@ -146,7 +146,7 @@ private fun SeedRecoveryMainContent(
TopScreenLogoTitle( TopScreenLogoTitle(
title = stringResource(R.string.seed_recovery_header), title = stringResource(R.string.seed_recovery_header),
logoContentDescription = stringResource(R.string.zcash_logo_content_description), logoContentDescription = stringResource(R.string.zcash_logo_content_description),
modifier = Modifier.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacing) modifier = Modifier.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacingBig)
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge)) Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
@ -154,7 +154,7 @@ private fun SeedRecoveryMainContent(
BodySmall( BodySmall(
text = stringResource(R.string.seed_recovery_description), text = stringResource(R.string.seed_recovery_description),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
modifier = Modifier.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacing) modifier = Modifier.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacingBig)
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault)) Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
@ -181,8 +181,8 @@ private fun SeedRecoveryMainContent(
Modifier Modifier
.padding( .padding(
bottom = ZcashTheme.dimens.spacingHuge, bottom = ZcashTheme.dimens.spacingHuge,
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingBig,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingBig
) )
) )
} }

View File

@ -2,15 +2,19 @@
package co.electriccoin.zcash.ui.screen.send.view package co.electriccoin.zcash.ui.screen.send.view
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@ -26,10 +30,13 @@ 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
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@ -176,15 +183,11 @@ fun Send(
hasCameraFeature = hasCameraFeature, hasCameraFeature = hasCameraFeature,
modifier = modifier =
Modifier Modifier
.fillMaxHeight()
.verticalScroll(
rememberScrollState()
)
.padding( .padding(
top = paddingValues.calculateTopPadding() + dimens.spacingDefault, top = paddingValues.calculateTopPadding() + dimens.spacingDefault,
bottom = paddingValues.calculateBottomPadding() + dimens.spacingHuge, bottom = paddingValues.calculateBottomPadding() + dimens.spacingHuge,
start = dimens.screenHorizontalSpacing, start = dimens.screenHorizontalSpacingRegular,
end = dimens.screenHorizontalSpacing end = dimens.screenHorizontalSpacingRegular
) )
) )
} }
@ -249,6 +252,7 @@ private fun SendMainContent(
hasCameraFeature = hasCameraFeature, hasCameraFeature = hasCameraFeature,
modifier = modifier modifier = modifier
) )
// TestSend(modifier)
} }
(sendStage == SendStage.Confirmation) -> { (sendStage == SendStage.Confirmation) -> {
SendConfirmation( SendConfirmation(
@ -286,6 +290,7 @@ private fun SendMainContent(
// TODO [#217]: Need to handle changing of Locale after user input, but before submitting the button. // TODO [#217]: Need to handle changing of Locale after user input, but before submitting the button.
// TODO [#288]: TextField component can't do long-press backspace. // TODO [#288]: TextField component can't do long-press backspace.
// TODO [#294]: DetektAll failed LongMethod // TODO [#294]: DetektAll failed LongMethod
@OptIn(ExperimentalFoundationApi::class)
@Suppress("LongMethod", "LongParameterList", "CyclomaticComplexMethod") @Suppress("LongMethod", "LongParameterList", "CyclomaticComplexMethod")
@Composable @Composable
private fun SendForm( private fun SendForm(
@ -300,6 +305,7 @@ private fun SendForm(
val context = LocalContext.current val context = LocalContext.current
val monetarySeparators = MonetarySeparators.current() val monetarySeparators = MonetarySeparators.current()
val allowedCharacters = ZecString.allowedCharacters(monetarySeparators) val allowedCharacters = ZecString.allowedCharacters(monetarySeparators)
val focusManager = LocalFocusManager.current
// TODO [#809]: Fix ZEC balance on Send screen // TODO [#809]: Fix ZEC balance on Send screen
// TODO [#809]: https://github.com/Electric-Coin-Company/zashi-android/issues/809 // TODO [#809]: https://github.com/Electric-Coin-Company/zashi-android/issues/809
@ -328,7 +334,12 @@ private fun SendForm(
} }
Column( Column(
modifier = modifier, modifier =
Modifier
.imePadding()
.fillMaxSize()
.verticalScroll(rememberScrollState())
.then(modifier),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Header( Header(
@ -346,9 +357,13 @@ private fun SendForm(
FormTextField( FormTextField(
value = recipientAddressString, value = recipientAddressString,
onValueChange = { recipientAddressString = it }, onValueChange = {
recipientAddressString = it
},
label = { Text(stringResource(id = R.string.send_to)) }, label = { Text(stringResource(id = R.string.send_to)) },
modifier = Modifier.fillMaxWidth(), modifier =
Modifier
.fillMaxWidth(),
trailingIcon = trailingIcon =
if (hasCameraFeature) { if (hasCameraFeature) {
{ {
@ -364,7 +379,18 @@ private fun SendForm(
} }
} else { } else {
null null
} },
keyboardOptions =
KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions =
KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Down)
}
)
) )
Spacer(Modifier.size(dimens.spacingSmall)) Spacer(Modifier.size(dimens.spacingSmall))
@ -377,7 +403,17 @@ private fun SendForm(
} }
amountZecString = newValue.filter { allowedCharacters.contains(it) } amountZecString = newValue.filter { allowedCharacters.contains(it) }
}, },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), keyboardOptions =
KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Next
),
keyboardActions =
KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Down)
}
),
label = { Text(stringResource(id = R.string.send_amount)) }, label = { Text(stringResource(id = R.string.send_amount)) },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
@ -393,17 +429,21 @@ private fun SendForm(
memoString = it memoString = it
} }
}, },
keyboardOptions =
KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Done
),
keyboardActions =
KeyboardActions(
onNext = {
focusManager.clearFocus(true)
}
),
label = { Text(stringResource(id = R.string.send_memo)) }, label = { Text(stringResource(id = R.string.send_memo)) },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
Spacer(
modifier =
Modifier
.fillMaxHeight()
.weight(MINIMAL_WEIGHT)
)
if (validation.isNotEmpty()) { if (validation.isNotEmpty()) {
/* /*
* Note: this is not localized in that it uses the enum constant name and joins the string * Note: this is not localized in that it uses the enum constant name and joins the string
@ -416,6 +456,13 @@ private fun SendForm(
) )
} }
Spacer(
modifier =
Modifier
.fillMaxHeight()
.weight(MINIMAL_WEIGHT)
)
Spacer(modifier = Modifier.height(dimens.spacingDefault)) Spacer(modifier = Modifier.height(dimens.spacingDefault))
// Create a send amount that is continuously checked for validity // Create a send amount that is continuously checked for validity
@ -448,7 +495,6 @@ private fun SendForm(
}, },
text = stringResource(id = R.string.send_create), text = stringResource(id = R.string.send_create),
enabled = sendButtonEnabled, enabled = sendButtonEnabled,
outerPaddingValues = PaddingValues(top = dimens.spacingNone),
modifier = Modifier.testTag(SendTag.SEND_FORM_BUTTON) modifier = Modifier.testTag(SendTag.SEND_FORM_BUTTON)
) )
} }

View File

@ -102,8 +102,8 @@ fun Settings(
.padding( .padding(
top = paddingValues.calculateTopPadding() + dimens.spacingHuge, top = paddingValues.calculateTopPadding() + dimens.spacingHuge,
bottom = paddingValues.calculateBottomPadding(), bottom = paddingValues.calculateBottomPadding(),
start = dimens.screenHorizontalSpacing, start = dimens.screenHorizontalSpacingBig,
end = dimens.screenHorizontalSpacing end = dimens.screenHorizontalSpacingBig
), ),
onSeedRecovery = onSeedRecovery, onSeedRecovery = onSeedRecovery,
onDocumentation = onDocumentation, onDocumentation = onDocumentation,

View File

@ -1,5 +1,6 @@
package co.electriccoin.zcash.ui.screen.support.view package co.electriccoin.zcash.ui.screen.support.view
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
@ -86,8 +87,8 @@ fun Support(
Modifier.padding( Modifier.padding(
top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault, top = paddingValues.calculateTopPadding() + ZcashTheme.dimens.spacingDefault,
bottom = paddingValues.calculateBottomPadding(), bottom = paddingValues.calculateBottomPadding(),
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingRegular,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingRegular
) )
) )
@ -118,6 +119,7 @@ private fun SupportTopAppBar(onBack: () -> Unit) {
) )
} }
@OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
private fun SupportMainContent( private fun SupportMainContent(
message: String, message: String,

View File

@ -79,8 +79,8 @@ fun Update(
.padding( .padding(
top = ZcashTheme.dimens.spacingDefault, top = ZcashTheme.dimens.spacingDefault,
bottom = ZcashTheme.dimens.spacingHuge, bottom = ZcashTheme.dimens.spacingHuge,
start = ZcashTheme.dimens.screenHorizontalSpacing, start = ZcashTheme.dimens.screenHorizontalSpacingBig,
end = ZcashTheme.dimens.screenHorizontalSpacing end = ZcashTheme.dimens.screenHorizontalSpacingBig
) )
) )
} }