Skip to content

Commit 34daff4

Browse files
authored
Merge pull request #882 from synonymdev/feat/transfer-from-savings-button-on-empty-spending
feat: add transfer from savings button on empty spending screen
2 parents 18b4a23 + ced3109 commit 34daff4

4 files changed

Lines changed: 97 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- Show loading state on Spending tab when node is not running #875
1616

1717
### Added
18+
- Transfer from Savings button on empty Spending screen when savings balance exists #882
1819
- Connection issues overlay with connectivity fixes across Send, Receive, and Transfer flows #878
1920
- Lightning Connections empty state with onboarding screen #857
2021
- Unified PIN management screen (enable/disable/change in one place) #857

app/src/main/java/to/bitkit/ui/ContentView.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,7 @@ private fun NavGraphBuilder.home(
815815
}
816816
composableWithDefaultTransitions<Routes.Spending> {
817817
val hasSeenSavingsIntro by settingsViewModel.hasSeenSavingsIntro.collectAsStateWithLifecycle()
818+
val hasSeenSpendingIntro by settingsViewModel.hasSeenSpendingIntro.collectAsStateWithLifecycle()
818819
val lightningState by walletViewModel.lightningState.collectAsStateWithLifecycle()
819820
val lightningActivities by activityListViewModel.lightningActivities.collectAsStateWithLifecycle()
820821

@@ -831,6 +832,13 @@ private fun NavGraphBuilder.home(
831832
navController.navigateToTransferSavingsAvailability()
832833
}
833834
},
835+
onTransferFromSavingsClick = {
836+
if (!hasSeenSpendingIntro) {
837+
navController.navigateToTransferSpendingIntro()
838+
} else {
839+
navController.navigateToTransferSpendingAmount()
840+
}
841+
},
834842
onBackClick = { navController.popBackStack() },
835843
)
836844
}

app/src/main/java/to/bitkit/ui/components/Button.kt

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.Box
99
import androidx.compose.foundation.layout.Column
1010
import androidx.compose.foundation.layout.PaddingValues
1111
import androidx.compose.foundation.layout.Row
12-
import androidx.compose.foundation.layout.fillMaxSize
1312
import androidx.compose.foundation.layout.fillMaxWidth
1413
import androidx.compose.foundation.layout.padding
1514
import androidx.compose.foundation.layout.requiredHeight
@@ -83,6 +82,7 @@ enum class ButtonSize {
8382
Small -> 8.dp
8483
Large -> 6.dp
8584
}
85+
8686
fun secondaryBorder(enabled: Boolean): BorderStroke = when (this) {
8787
Large -> BorderStroke(2.dp, if (enabled) Colors.Gray4 else Color.Transparent)
8888
Small -> BorderStroke(1.dp, if (enabled) Colors.White16 else Color.Transparent)
@@ -183,6 +183,7 @@ fun SecondaryButton(
183183
// and AFTER size modifiers (Haze needs to know dimensions)
184184
val buttonShape = MaterialTheme.shapes.extraLarge
185185
Box(
186+
propagateMinConstraints = true,
186187
modifier = modifier
187188
.then(if (fullWidth) Modifier.fillMaxWidth() else Modifier)
188189
.requiredHeight(size.height)
@@ -208,7 +209,6 @@ fun SecondaryButton(
208209
colors = AppButtonDefaults.secondaryColors.copy(contentColor = contentColor),
209210
contentPadding = contentPadding,
210211
border = border,
211-
modifier = if (fullWidth) Modifier.fillMaxSize() else Modifier,
212212
) {
213213
if (isLoading) {
214214
GradientCircularProgressIndicator(
@@ -488,6 +488,25 @@ private fun SecondaryButtonPreview() {
488488
)
489489
},
490490
)
491+
Row(
492+
modifier = Modifier.fillMaxWidth(),
493+
horizontalArrangement = Arrangement.spacedBy(8.dp)
494+
) {
495+
SecondaryButton(
496+
text = "Secondary",
497+
fullWidth = false,
498+
hazeState = hazeState,
499+
onClick = {},
500+
modifier = Modifier.weight(1f)
501+
)
502+
SecondaryButton(
503+
text = "Secondary",
504+
fullWidth = false,
505+
hazeState = hazeState,
506+
onClick = {},
507+
modifier = Modifier.weight(1f)
508+
)
509+
}
491510
SecondaryButton(
492511
text = "Secondary Small",
493512
size = ButtonSize.Small,
@@ -588,6 +607,23 @@ private fun TertiaryButtonPreview() {
588607
},
589608
onClick = {}
590609
)
610+
Row(
611+
modifier = Modifier.fillMaxWidth(),
612+
horizontalArrangement = Arrangement.spacedBy(8.dp)
613+
) {
614+
TertiaryButton(
615+
text = "Tertiary",
616+
fullWidth = false,
617+
onClick = {},
618+
modifier = Modifier.weight(1f)
619+
)
620+
TertiaryButton(
621+
text = "Tertiary",
622+
fullWidth = false,
623+
onClick = {},
624+
modifier = Modifier.weight(1f)
625+
)
626+
}
591627
TertiaryButton(
592628
text = "Tertiary Small",
593629
size = ButtonSize.Small,

app/src/main/java/to/bitkit/ui/screens/wallets/SpendingWalletScreen.kt

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@ import androidx.compose.foundation.Image
44
import androidx.compose.foundation.background
55
import androidx.compose.foundation.layout.Box
66
import androidx.compose.foundation.layout.Column
7-
import androidx.compose.foundation.layout.Spacer
87
import androidx.compose.foundation.layout.WindowInsets
98
import androidx.compose.foundation.layout.WindowInsetsSides
109
import androidx.compose.foundation.layout.fillMaxSize
1110
import androidx.compose.foundation.layout.fillMaxWidth
12-
import androidx.compose.foundation.layout.height
1311
import androidx.compose.foundation.layout.offset
1412
import androidx.compose.foundation.layout.only
1513
import androidx.compose.foundation.layout.padding
@@ -45,6 +43,7 @@ import to.bitkit.ui.components.EmptyStateView
4543
import to.bitkit.ui.components.IncomingTransfer
4644
import to.bitkit.ui.components.SecondaryButton
4745
import to.bitkit.ui.components.TabBar
46+
import to.bitkit.ui.components.VerticalSpacer
4847
import to.bitkit.ui.scaffold.AppTopBar
4948
import to.bitkit.ui.scaffold.DrawerNavIcon
5049
import to.bitkit.ui.scaffold.ScreenColumn
@@ -63,6 +62,7 @@ fun SpendingWalletScreen(
6362
onActivityItemClick: (String) -> Unit,
6463
onEmptyActivityRowClick: () -> Unit,
6564
onTransferToSavingsClick: () -> Unit,
65+
onTransferFromSavingsClick: () -> Unit,
6666
onBackClick: () -> Unit,
6767
balances: BalanceState = LocalBalances.current,
6868
) {
@@ -76,7 +76,9 @@ fun SpendingWalletScreen(
7676
val hasChannels = channels.isNotEmpty()
7777
mutableStateOf(hasLnBalance && hasChannels)
7878
}
79-
79+
val canTransferFromSavings by remember(showEmptyState, balances.totalOnchainSats) {
80+
mutableStateOf(showEmptyState && balances.totalOnchainSats > 0uL)
81+
}
8082
val hazeState = rememberHazeState()
8183
Box(
8284
modifier = Modifier
@@ -129,8 +131,26 @@ fun SpendingWalletScreen(
129131
)
130132
}
131133

134+
if (canTransferFromSavings) {
135+
VerticalSpacer(32.dp)
136+
137+
SecondaryButton(
138+
onClick = onTransferFromSavingsClick,
139+
text = stringResource(R.string.lightning__funding__button1),
140+
icon = {
141+
Icon(
142+
painter = painterResource(R.drawable.ic_transfer),
143+
contentDescription = null,
144+
modifier = Modifier.size(16.dp)
145+
)
146+
},
147+
hazeState = hazeState,
148+
modifier = Modifier.testTag("TransferFromSavings")
149+
)
150+
}
151+
132152
if (!showEmptyState) {
133-
Spacer(modifier = Modifier.height(32.dp))
153+
VerticalSpacer(32.dp)
134154

135155
if (canTransfer) {
136156
SecondaryButton(
@@ -160,8 +180,7 @@ fun SpendingWalletScreen(
160180
}
161181
if (showEmptyState) {
162182
EmptyStateView(
163-
text = stringResource(R.string.wallet__spending__onboarding)
164-
.withAccent(accentColor = Colors.Purple),
183+
text = stringResource(R.string.wallet__spending__onboarding).withAccent(accentColor = Colors.Purple),
165184
modifier = Modifier
166185
.systemBarsPadding()
167186
.align(Alignment.BottomCenter)
@@ -182,6 +201,7 @@ private fun Preview() {
182201
onActivityItemClick = {},
183202
onEmptyActivityRowClick = {},
184203
onTransferToSavingsClick = {},
204+
onTransferFromSavingsClick = {},
185205
onBackClick = {},
186206
balances = BalanceState(totalLightningSats = 50_000u),
187207
)
@@ -202,6 +222,7 @@ private fun PreviewTransfer() {
202222
onActivityItemClick = {},
203223
onEmptyActivityRowClick = {},
204224
onTransferToSavingsClick = {},
225+
onTransferFromSavingsClick = {},
205226
onBackClick = {},
206227
balances = BalanceState(
207228
totalLightningSats = 50_000u,
@@ -225,6 +246,7 @@ private fun PreviewNoActivity() {
225246
onActivityItemClick = {},
226247
onEmptyActivityRowClick = {},
227248
onTransferToSavingsClick = {},
249+
onTransferFromSavingsClick = {},
228250
onBackClick = {},
229251
balances = BalanceState(totalLightningSats = 50_000u),
230252
)
@@ -245,7 +267,29 @@ private fun PreviewEmpty() {
245267
onActivityItemClick = {},
246268
onEmptyActivityRowClick = {},
247269
onTransferToSavingsClick = {},
270+
onTransferFromSavingsClick = {},
271+
onBackClick = {},
272+
)
273+
TabBar()
274+
}
275+
}
276+
}
277+
278+
@Preview(showSystemUi = true)
279+
@Composable
280+
private fun PreviewEmptyWithSavings() {
281+
AppThemeSurface {
282+
Box {
283+
SpendingWalletScreen(
284+
channels = persistentListOf(),
285+
lightningActivities = persistentListOf(),
286+
onAllActivityButtonClick = {},
287+
onActivityItemClick = {},
288+
onEmptyActivityRowClick = {},
289+
onTransferToSavingsClick = {},
290+
onTransferFromSavingsClick = {},
248291
onBackClick = {},
292+
balances = BalanceState(totalOnchainSats = 100_000u),
249293
)
250294
TabBar()
251295
}

0 commit comments

Comments
 (0)