commit 5a96d14b3ece9553ea45c1418fda0f2ba21811a8
parent d1da72fad71abb5f33e4e25dd8e49e87b2aa4d3c
Author: Iván Ávalos <avalos@disroot.org>
Date: Sat, 2 Nov 2024 00:05:40 +0100
[wallet] more UI improvements
Diffstat:
4 files changed, 103 insertions(+), 76 deletions(-)
diff --git a/wallet/src/main/java/net/taler/wallet/MainFragment.kt b/wallet/src/main/java/net/taler/wallet/MainFragment.kt
@@ -23,6 +23,7 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.appcompat.app.AppCompatActivity
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.draggable
import androidx.compose.foundation.gestures.rememberDraggableState
@@ -31,6 +32,7 @@ import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
@@ -58,6 +60,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
@@ -67,6 +70,7 @@ import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@@ -83,6 +87,7 @@ import net.taler.wallet.compose.GridMenuItem
import net.taler.wallet.compose.TalerSurface
import net.taler.wallet.compose.collectAsStateLifecycleAware
import net.taler.wallet.settings.SettingsFragment
+import kotlin.math.roundToInt
class MainFragment: Fragment() {
@@ -90,7 +95,7 @@ class MainFragment: Fragment() {
private val model: MainViewModel by activityViewModels()
- @OptIn(ExperimentalMaterial3Api::class)
+ @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -125,24 +130,39 @@ class MainFragment: Fragment() {
tooltip = { PlainTooltip { Text(stringResource(R.string.actions)) } },
state = rememberTooltipState(),
) {
+ var offsetY by remember { mutableFloatStateOf(0f) }
+
DemandAttention {
LargeFloatingActionButton(
modifier = Modifier
.requiredSize(86.dp)
.padding(8.dp)
+ .offset { IntOffset(0, offsetY.roundToInt() / 6) }
.draggable(
orientation = Orientation.Vertical,
- state = rememberDraggableState { },
- onDragStopped = { onScanQr() },
+ state = rememberDraggableState { delta ->
+ if (delta < 0) { offsetY += delta }
+ },
+ onDragStopped = {
+ offsetY = 0.0f
+ onScanQr()
+ },
),
shape = CircleShape,
onClick = { showSheet = true },
) {
- Icon(
- painterResource(R.drawable.ic_actions),
- modifier = Modifier.size(38.dp),
- contentDescription = stringResource(R.string.actions),
- )
+ if (offsetY == 0.0f) {
+ Icon(
+ painterResource(R.drawable.ic_actions),
+ modifier = Modifier.size(38.dp),
+ contentDescription = stringResource(R.string.actions),
+ )
+ } else {
+ Icon(
+ painterResource(R.drawable.ic_scan_qr),
+ contentDescription = stringResource(R.string.actions),
+ )
+ }
}
}
}
diff --git a/wallet/src/main/java/net/taler/wallet/compose/AmountInputFIeld.kt b/wallet/src/main/java/net/taler/wallet/compose/AmountInputFIeld.kt
@@ -81,13 +81,15 @@ fun AmountCurrencyField(
readOnly = readOnly,
)
- CurrencyDropdown(
- modifier = Modifier.weight(1f),
- currencies = currencies,
- onCurrencyChanged = { onAmountChanged(amount.copy(currency = it)) },
- initialCurrency = amount.currency,
- readOnly = !editableCurrency,
- )
+ if (editableCurrency) {
+ CurrencyDropdown(
+ modifier = Modifier.weight(1f),
+ currencies = currencies,
+ onCurrencyChanged = { onAmountChanged(amount.copy(currency = it)) },
+ initialCurrency = amount.currency,
+ readOnly = false,
+ )
+ }
}
}
diff --git a/wallet/src/main/java/net/taler/wallet/compose/SelectionModeTopAppBar.kt b/wallet/src/main/java/net/taler/wallet/compose/SelectionModeTopAppBar.kt
@@ -16,6 +16,7 @@
package net.taler.wallet.compose
+import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Close
import androidx.compose.material.icons.rounded.Delete
@@ -30,6 +31,7 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
import net.taler.wallet.R
@Composable
@@ -81,5 +83,7 @@ fun SelectionModeTopAppBar(
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.surfaceContainer,
),
+
+ windowInsets = WindowInsets(0.dp),
)
}
\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsComposable.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsComposable.kt
@@ -21,18 +21,15 @@ import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
-import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
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.consumeWindowInsets
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
@@ -42,7 +39,6 @@ import androidx.compose.material.icons.rounded.CheckCircle
import androidx.compose.material.icons.rounded.RadioButtonUnchecked
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Badge
-import androidx.compose.material3.Button
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
@@ -62,7 +58,9 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@@ -83,7 +81,6 @@ import net.taler.wallet.cleanExchange
import net.taler.wallet.compose.LoadingScreen
import net.taler.wallet.compose.SelectionModeTopAppBar
import net.taler.wallet.compose.TalerSurface
-import net.taler.wallet.launchInAppBrowser
import net.taler.wallet.transactions.AmountType.Negative
import net.taler.wallet.transactions.AmountType.Neutral
import net.taler.wallet.transactions.AmountType.Positive
@@ -157,68 +154,68 @@ fun TransactionsComposable(
}
}
- LazyColumn(
- Modifier
- .consumeWindowInsets(innerPadding)
- .fillMaxHeight(),
- contentPadding = innerPadding,
- ) {
- item {
- if (selectionMode) SelectionModeTopAppBar(
- selectedItems = selectedItems,
- resetSelectionMode = {
- selectionMode = false
- selectedItems.clear()
- },
- onSelectAllClicked = {
- selectedItems.clear()
- selectedItems += txResult.transactions.map { it.transactionId }
- },
- onDeleteClicked = {
- showDeleteDialog = true
- },
- )
- }
+ Column(Modifier.fillMaxSize()) {
+ if (selectionMode) SelectionModeTopAppBar(
+ selectedItems = selectedItems,
+ resetSelectionMode = {
+ selectionMode = false
+ selectedItems.clear()
+ },
+ onSelectAllClicked = {
+ selectedItems.clear()
+ selectedItems += txResult.transactions.map { it.transactionId }
+ },
+ onDeleteClicked = {
+ showDeleteDialog = true
+ },
+ )
- item {
- TransactionsHeader(
- balance = balance,
- spec = currencySpec,
- onShowBalancesClicked = onShowBalancesClicked,
- )
- }
+ LazyColumn(
+ Modifier
+ .consumeWindowInsets(innerPadding)
+ .fillMaxHeight(),
+ contentPadding = innerPadding,
+ ) {
+ item {
+ TransactionsHeader(
+ balance = balance,
+ spec = currencySpec,
+ onShowBalancesClicked = onShowBalancesClicked,
+ )
+ }
- items(txResult.transactions, key = { it.transactionId }) { tx ->
- val isSelected = selectedItems.contains(tx.transactionId)
-
- TransactionRow(
- tx, currencySpec,
- isSelected = isSelected,
- selectionMode = selectionMode,
- onTransactionClick = {
- if (selectionMode) {
- if (isSelected) {
- selectedItems.remove(tx.transactionId)
+ items(txResult.transactions, key = { it.transactionId }) { tx ->
+ val isSelected = selectedItems.contains(tx.transactionId)
+
+ TransactionRow(
+ tx, currencySpec,
+ isSelected = isSelected,
+ selectionMode = selectionMode,
+ onTransactionClick = {
+ if (selectionMode) {
+ if (isSelected) {
+ selectedItems.remove(tx.transactionId)
+ } else {
+ selectedItems.add(tx.transactionId)
+ }
} else {
- selectedItems.add(tx.transactionId)
+ onTransactionClick(tx)
}
- } else {
- onTransactionClick(tx)
- }
- },
- onTransactionSelect = {
- if (selectionMode) {
- if (isSelected) {
- selectedItems.remove(tx.transactionId)
+ },
+ onTransactionSelect = {
+ if (selectionMode) {
+ if (isSelected) {
+ selectedItems.remove(tx.transactionId)
+ } else {
+ selectedItems.add(tx.transactionId)
+ }
} else {
+ selectionMode = true
selectedItems.add(tx.transactionId)
}
- } else {
- selectionMode = true
- selectedItems.add(tx.transactionId)
- }
- },
- )
+ },
+ )
+ }
}
}
}
@@ -307,6 +304,7 @@ fun TransactionRow(
onTransactionSelect: () -> Unit,
) {
val context = LocalContext.current
+ val haptic = LocalHapticFeedback.current
Column {
ListItem(
@@ -314,7 +312,10 @@ fun TransactionRow(
.defaultMinSize(minHeight = 80.dp)
.combinedClickable(
onClick = onTransactionClick,
- onLongClick = onTransactionSelect,
+ onLongClick = {
+ haptic.performHapticFeedback(HapticFeedbackType.LongPress)
+ onTransactionSelect()
+ },
),
trailingContent = {
Box(