[#789] Fix Send Screen Layout
* [#804][Design system] Paddings - Dimens - Initial commit to ensure it meets our requirements - This solution is now in parallel with a simpler existing Paddings solution - Four spacing groups defined - Provides a way to define default and custom spacing values - Distinguished by screen size, but other metrics also available (e.g. orientation, aspect ratio, layout direction or screen shape) * Fix spacing value * Move spacings change logic to comment - We've decided to have only one regular spacing group for now, which is suitable for most of current phone devices * Move Dimens out of internal package * Link TODO for later Paddings remove * Link issue of Use Dimens across the app to TODO * Add vertical scrolling feature to SendForm screen * Add vertical scrolling feature to Settings screen + Switched from Paddings to Dimens spacing system * Add paddings, vertical scrolling, move modifiers - As part of this is also move modifiers to the caller side where it makes sense * Improve Send screen layout - Added header view to the screen - Added spacers between some UI parts of the screen - Fixed background colors - And improved textfields sizes * Link Fix ZEC balance number formatting issue * Link Disable Memo UI field in case of Transparent address issue * Replace all .dp with predefined Dimens spacing in SendView * Create custom FormTextField UI component * Re-write paddings to spacers in list
This commit is contained in:
parent
5cfa3a99e3
commit
d37310a935
|
@ -17,10 +17,12 @@ import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
|||
fun Header(
|
||||
text: String,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = ZcashTheme.colors.onBackgroundHeader
|
||||
textAlign: TextAlign = TextAlign.Start,
|
||||
color: Color = ZcashTheme.colors.onBackgroundHeader,
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
textAlign = textAlign,
|
||||
style = MaterialTheme.typography.headlineLarge,
|
||||
color = color,
|
||||
modifier = modifier
|
||||
|
@ -46,8 +48,8 @@ fun Body(
|
|||
@Composable
|
||||
fun Small(
|
||||
text: String,
|
||||
textAlign: TextAlign,
|
||||
modifier: Modifier = Modifier
|
||||
modifier: Modifier = Modifier,
|
||||
textAlign: TextAlign = TextAlign.Start
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package co.electriccoin.zcash.ui.design.component
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldColors
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun FormTextField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
label: @Composable (() -> Unit)? = null,
|
||||
keyboardOptions: KeyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
|
||||
colors: TextFieldColors = TextFieldDefaults.textFieldColors(
|
||||
containerColor = Color.Transparent
|
||||
)
|
||||
) {
|
||||
TextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
label = label,
|
||||
keyboardOptions = keyboardOptions,
|
||||
colors = colors,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
|
@ -2,14 +2,15 @@ package co.electriccoin.zcash.ui.screen.send.view
|
|||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
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.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
|
@ -17,7 +18,6 @@ import androidx.compose.material3.Icon
|
|||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
|
@ -29,8 +29,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cash.z.ecc.android.sdk.model.Memo
|
||||
import cash.z.ecc.android.sdk.model.MonetarySeparators
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
|
@ -42,10 +42,14 @@ import cash.z.ecc.android.sdk.model.toZecString
|
|||
import cash.z.ecc.sdk.fixture.ZatoshiFixture
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||
import co.electriccoin.zcash.ui.design.component.Body
|
||||
import co.electriccoin.zcash.ui.design.component.FormTextField
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.Header
|
||||
import co.electriccoin.zcash.ui.design.component.PrimaryButton
|
||||
import co.electriccoin.zcash.ui.design.component.TimedButton
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme.dimens
|
||||
import co.electriccoin.zcash.ui.screen.send.ext.ABBREVIATION_INDEX
|
||||
import co.electriccoin.zcash.ui.screen.send.ext.Saver
|
||||
import co.electriccoin.zcash.ui.screen.send.ext.abbreviated
|
||||
|
@ -92,12 +96,21 @@ fun Send(
|
|||
})
|
||||
}) { paddingValues ->
|
||||
SendMainContent(
|
||||
paddingValues,
|
||||
mySpendableBalance,
|
||||
sendStage,
|
||||
pressAndHoldInteractionSource,
|
||||
setSendStage,
|
||||
onCreateAndSend = onCreateAndSend
|
||||
myBalance = mySpendableBalance,
|
||||
sendStage = sendStage,
|
||||
pressAndHoldInteractionSource = pressAndHoldInteractionSource,
|
||||
setSendStage = setSendStage,
|
||||
onCreateAndSend = onCreateAndSend,
|
||||
modifier = Modifier
|
||||
.verticalScroll(
|
||||
rememberScrollState()
|
||||
)
|
||||
.padding(
|
||||
top = paddingValues.calculateTopPadding() + dimens.spacingDefault,
|
||||
bottom = dimens.spacingDefault,
|
||||
start = dimens.spacingDefault,
|
||||
end = dimens.spacingDefault
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -123,32 +136,34 @@ private fun SendTopAppBar(onBack: () -> Unit) {
|
|||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun SendMainContent(
|
||||
paddingValues: PaddingValues,
|
||||
myBalance: Zatoshi,
|
||||
sendStage: SendStage,
|
||||
pressAndHoldInteractionSource: MutableInteractionSource,
|
||||
setSendStage: (SendStage) -> Unit,
|
||||
onCreateAndSend: (ZecSend) -> Unit
|
||||
onCreateAndSend: (ZecSend) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val (zecSend, setZecSend) = rememberSaveable(stateSaver = ZecSend.Saver) { mutableStateOf(null) }
|
||||
|
||||
if (sendStage == SendStage.Form || null == zecSend) {
|
||||
SendForm(
|
||||
paddingValues,
|
||||
myBalance = myBalance,
|
||||
previousZecSend = zecSend
|
||||
) {
|
||||
setSendStage(SendStage.Confirmation)
|
||||
setZecSend(it)
|
||||
}
|
||||
previousZecSend = zecSend,
|
||||
onCreateAndSend = {
|
||||
setSendStage(SendStage.Confirmation)
|
||||
setZecSend(it)
|
||||
},
|
||||
modifier = modifier
|
||||
)
|
||||
} else {
|
||||
Confirmation(
|
||||
paddingValues,
|
||||
zecSend,
|
||||
pressAndHoldInteractionSource
|
||||
) {
|
||||
onCreateAndSend(zecSend)
|
||||
}
|
||||
zecSend = zecSend,
|
||||
pressAndHoldInteractionSource = pressAndHoldInteractionSource,
|
||||
onConfirmation = {
|
||||
onCreateAndSend(zecSend)
|
||||
},
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,15 +174,17 @@ private fun SendMainContent(
|
|||
@Composable
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
private fun SendForm(
|
||||
paddingValues: PaddingValues,
|
||||
myBalance: Zatoshi,
|
||||
previousZecSend: ZecSend?,
|
||||
onCreateAndSend: (ZecSend) -> Unit
|
||||
onCreateAndSend: (ZecSend) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val monetarySeparators = MonetarySeparators.current()
|
||||
val allowedCharacters = ZecString.allowedCharacters(monetarySeparators)
|
||||
|
||||
// TODO [#809]: Fix ZEC balance on Send screen
|
||||
// TODO [#809]: https://github.com/zcash/secant-android-wallet/issues/809
|
||||
var amountZecString by rememberSaveable {
|
||||
mutableStateOf(previousZecSend?.amount?.toZecString() ?: "")
|
||||
}
|
||||
|
@ -181,41 +198,58 @@ private fun SendForm(
|
|||
}
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
modifier
|
||||
.fillMaxHeight()
|
||||
.padding(top = paddingValues.calculateTopPadding())
|
||||
) {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Text(text = myBalance.toZecString())
|
||||
}
|
||||
Header(
|
||||
text = stringResource(id = R.string.send_balance, myBalance.toZecString()),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
Body(
|
||||
text = stringResource(id = R.string.send_balance_subtitle),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
TextField(
|
||||
Spacer(modifier = Modifier.height(dimens.spacingLarge))
|
||||
|
||||
FormTextField(
|
||||
value = amountZecString,
|
||||
onValueChange = { newValue ->
|
||||
if (!ZecStringExt.filterContinuous(context, monetarySeparators, newValue)) {
|
||||
return@TextField
|
||||
return@FormTextField
|
||||
}
|
||||
amountZecString = newValue.filter { allowedCharacters.contains(it) }
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
label = { Text(stringResource(id = R.string.send_amount)) }
|
||||
label = { Text(stringResource(id = R.string.send_amount)) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(Modifier.size(8.dp))
|
||||
Spacer(Modifier.size(dimens.spacingSmall))
|
||||
|
||||
TextField(
|
||||
FormTextField(
|
||||
value = recipientAddressString,
|
||||
onValueChange = { recipientAddressString = it },
|
||||
label = { Text(stringResource(id = R.string.send_to)) }
|
||||
label = { Text(stringResource(id = R.string.send_to)) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(Modifier.size(8.dp))
|
||||
Spacer(Modifier.size(dimens.spacingSmall))
|
||||
|
||||
TextField(value = memoString, onValueChange = {
|
||||
if (Memo.isWithinMaxLength(it)) {
|
||||
memoString = it
|
||||
}
|
||||
}, label = { Text(stringResource(id = R.string.send_memo)) })
|
||||
// TODO [#810]: Disable Memo UI field in case of Transparent address
|
||||
// TODO [#810]: https://github.com/zcash/secant-android-wallet/issues/810
|
||||
FormTextField(
|
||||
value = memoString,
|
||||
onValueChange = {
|
||||
if (Memo.isWithinMaxLength(it)) {
|
||||
memoString = it
|
||||
}
|
||||
},
|
||||
label = { Text(stringResource(id = R.string.send_memo)) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(Modifier.fillMaxHeight(MINIMAL_WEIGHT))
|
||||
|
||||
|
@ -225,9 +259,14 @@ private fun SendForm(
|
|||
* without regard for RTL. This will get resolved once we do proper validation for
|
||||
* the fields.
|
||||
*/
|
||||
Text(validation.joinToString(", "))
|
||||
Text(
|
||||
text = validation.joinToString(", "),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingDefault))
|
||||
|
||||
PrimaryButton(
|
||||
onClick = {
|
||||
val zecSendValidation = ZecSendExt.new(
|
||||
|
@ -253,15 +292,12 @@ private fun SendForm(
|
|||
|
||||
@Composable
|
||||
private fun Confirmation(
|
||||
paddingValues: PaddingValues,
|
||||
zecSend: ZecSend,
|
||||
pressAndHoldInteractionSource: MutableInteractionSource,
|
||||
onConfirmation: () -> Unit
|
||||
onConfirmation: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(top = paddingValues.calculateTopPadding())
|
||||
) {
|
||||
Column(modifier) {
|
||||
Text(
|
||||
stringResource(
|
||||
R.string.send_amount_and_address_format,
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package co.electriccoin.zcash.ui.screen.settings.view
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
|
@ -25,7 +29,7 @@ import co.electriccoin.zcash.ui.R
|
|||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.SwitchWithLabel
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme.paddings
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme.dimens
|
||||
|
||||
@Preview("Settings")
|
||||
@Composable
|
||||
|
@ -75,10 +79,16 @@ fun Settings(
|
|||
onBackgroundSyncSettingsChanged = onBackgroundSyncSettingsChanged,
|
||||
onIsKeepScreenOnDuringSyncSettingsChanged = onIsKeepScreenOnDuringSyncSettingsChanged,
|
||||
onAnalyticsSettingsChanged = onAnalyticsSettingsChanged,
|
||||
modifier = Modifier.padding(
|
||||
top = paddingValues.calculateTopPadding() + paddings.padding,
|
||||
bottom = paddings.padding
|
||||
)
|
||||
modifier = Modifier
|
||||
.verticalScroll(
|
||||
rememberScrollState()
|
||||
)
|
||||
.padding(
|
||||
top = paddingValues.calculateTopPadding() + dimens.spacingDefault,
|
||||
bottom = dimens.spacingDefault,
|
||||
start = dimens.spacingDefault,
|
||||
end = dimens.spacingDefault
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -150,20 +160,23 @@ private fun SettingsMainContent(
|
|||
SwitchWithLabel(
|
||||
label = stringResource(id = R.string.settings_enable_background_sync),
|
||||
state = isBackgroundSyncEnabled,
|
||||
onStateChange = { onBackgroundSyncSettingsChanged(!isBackgroundSyncEnabled) },
|
||||
modifier = Modifier.padding(paddings.padding)
|
||||
onStateChange = { onBackgroundSyncSettingsChanged(!isBackgroundSyncEnabled) }
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingXlarge))
|
||||
|
||||
SwitchWithLabel(
|
||||
label = stringResource(id = R.string.settings_enable_keep_screen_on),
|
||||
state = isKeepScreenOnDuringSyncEnabled,
|
||||
onStateChange = { onIsKeepScreenOnDuringSyncSettingsChanged(!isKeepScreenOnDuringSyncEnabled) },
|
||||
modifier = Modifier.padding(paddings.padding)
|
||||
onStateChange = { onIsKeepScreenOnDuringSyncSettingsChanged(!isKeepScreenOnDuringSyncEnabled) }
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingXlarge))
|
||||
|
||||
SwitchWithLabel(
|
||||
label = stringResource(id = R.string.settings_enable_analytics),
|
||||
state = isAnalyticsEnabled,
|
||||
onStateChange = { onAnalyticsSettingsChanged(!isAnalyticsEnabled) },
|
||||
modifier = Modifier.padding(paddings.padding)
|
||||
onStateChange = { onAnalyticsSettingsChanged(!isAnalyticsEnabled) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<string name="send_title">Send ZEC</string>
|
||||
<string name="send_back_content_description">Back</string>
|
||||
<string name="send_scan_content_description">Scan</string>
|
||||
<string name="send_balance" formatted="true"><xliff:g id="balance" example="12.345">%1$s</xliff:g> ZEC Available</string>
|
||||
<string name="send_balance_subtitle">Additional funds may be in transit.</string>
|
||||
<string name="send_to">Who would you like to send ZEC to?</string>
|
||||
<string name="send_amount">How much?</string>
|
||||
<string name="send_memo">Memo</string>
|
||||
|
|
Loading…
Reference in New Issue