Skip to content

Commit df98c25

Browse files
authored
Merge pull request #164 from synonymdev/feat/backup-intro
Backup Intro
2 parents 726fab3 + 88621e6 commit df98c25

File tree

5 files changed

+292
-3
lines changed

5 files changed

+292
-3
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package to.bitkit.ui.settings.backups
2+
3+
import androidx.compose.ui.test.junit4.createComposeRule
4+
import androidx.compose.ui.test.onNodeWithTag
5+
import androidx.compose.ui.test.performClick
6+
import org.junit.Rule
7+
import org.junit.Test
8+
import to.bitkit.ui.theme.AppThemeSurface
9+
10+
class BackupIntroScreenTest {
11+
12+
@get:Rule
13+
val composeTestRule = createComposeRule()
14+
15+
@Test
16+
fun testBackupIntroScreenWithFunds() {
17+
// Arrange
18+
var closeClicked = false
19+
var confirmClicked = false
20+
21+
// Act
22+
composeTestRule.setContent {
23+
AppThemeSurface {
24+
BackupIntroScreen(
25+
hasFunds = true,
26+
onClose = { closeClicked = true },
27+
onConfirm = { confirmClicked = true }
28+
)
29+
}
30+
}
31+
32+
// Assert
33+
composeTestRule.onNodeWithTag("backup_intro_screen").assertExists()
34+
composeTestRule.onNodeWithTag("backup_image").assertExists()
35+
composeTestRule.onNodeWithTag("backup_title").assertExists()
36+
37+
// Verify buttons
38+
composeTestRule.onNodeWithTag("buttons_row").assertExists()
39+
composeTestRule.onNodeWithTag("later_button").assertExists().performClick()
40+
assert(closeClicked)
41+
42+
composeTestRule.onNodeWithTag("backup_button").assertExists().performClick()
43+
assert(confirmClicked)
44+
}
45+
46+
@Test
47+
fun testBackupIntroScreenWithoutFunds() {
48+
// Arrange
49+
var closeClicked = false
50+
var confirmClicked = false
51+
52+
// Act
53+
composeTestRule.setContent {
54+
AppThemeSurface {
55+
BackupIntroScreen(
56+
hasFunds = false,
57+
onClose = { closeClicked = true },
58+
onConfirm = { confirmClicked = true }
59+
)
60+
}
61+
}
62+
63+
// Assert
64+
composeTestRule.onNodeWithTag("backup_intro_screen").assertExists()
65+
66+
// Verify buttons
67+
composeTestRule.onNodeWithTag("later_button").assertExists().performClick()
68+
assert(closeClicked)
69+
70+
composeTestRule.onNodeWithTag("backup_button").assertExists().performClick()
71+
assert(confirmClicked)
72+
}
73+
74+
@Test
75+
fun testAllElementsExist() {
76+
// Arrange
77+
composeTestRule.setContent {
78+
AppThemeSurface {
79+
BackupIntroScreen(
80+
hasFunds = true,
81+
onClose = {},
82+
onConfirm = {}
83+
)
84+
}
85+
}
86+
87+
// Assert
88+
composeTestRule.onNodeWithTag("backup_intro_screen").assertExists()
89+
composeTestRule.onNodeWithTag("backup_image").assertExists()
90+
composeTestRule.onNodeWithTag("backup_title").assertExists()
91+
composeTestRule.onNodeWithTag("backup_description").assertExists()
92+
composeTestRule.onNodeWithTag("buttons_row").assertExists()
93+
composeTestRule.onNodeWithTag("later_button").assertExists()
94+
composeTestRule.onNodeWithTag("backup_button").assertExists()
95+
}
96+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ sealed class BottomSheetType {
2929
data class Send(val route: SendRoute = SendRoute.Options) : BottomSheetType()
3030
data object Receive : BottomSheetType()
3131
data object PinSetup : BottomSheetType()
32+
data object Backup : BottomSheetType()
3233
data object ActivityDateRangeSelector : BottomSheetType()
3334
data object ActivityTagSelector : BottomSheetType()
3435
}

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package to.bitkit.ui.screens.wallets
22

33
import android.Manifest
4-
import android.content.Intent
54
import android.os.Build
65
import androidx.activity.compose.rememberLauncherForActivityResult
76
import androidx.activity.result.contract.ActivityResultContracts
@@ -83,6 +82,7 @@ import to.bitkit.ui.screens.wallets.activity.TagSelectorSheet
8382
import to.bitkit.ui.screens.wallets.activity.components.ActivityListSimple
8483
import to.bitkit.ui.screens.wallets.receive.ReceiveQrSheet
8584
import to.bitkit.ui.screens.wallets.send.SendOptionsView
85+
import to.bitkit.ui.settings.backups.BackupSheet
8686
import to.bitkit.ui.settings.pin.PinNavigationSheet
8787
import to.bitkit.ui.settingsViewModel
8888
import to.bitkit.ui.shared.util.clickableAlpha
@@ -143,6 +143,10 @@ fun HomeScreen(
143143
onDismiss = { appViewModel.hideSheet() },
144144
)
145145

146+
BottomSheetType.Backup -> BackupSheet(
147+
onDismiss = { appViewModel.hideSheet() },
148+
walletViewModel = walletViewModel
149+
)
146150
null -> Unit
147151
}
148152
}
@@ -188,8 +192,8 @@ fun HomeScreen(
188192
}
189193
}
190194

191-
Suggestion.BACK_UP -> { //TODO IMPLEMENT BOTTOM SHEET
192-
rootNavController.navigate(Routes.BackupWalletSettings)
195+
Suggestion.BACK_UP -> {
196+
appViewModel.showSheet(BottomSheetType.Backup)
193197
}
194198

195199
Suggestion.SECURE -> {
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package to.bitkit.ui.settings.backups
2+
3+
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.Spacer
8+
import androidx.compose.foundation.layout.fillMaxSize
9+
import androidx.compose.foundation.layout.fillMaxWidth
10+
import androidx.compose.foundation.layout.height
11+
import androidx.compose.foundation.layout.navigationBarsPadding
12+
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.runtime.Composable
14+
import androidx.compose.ui.Alignment
15+
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.platform.testTag
17+
import androidx.compose.ui.res.painterResource
18+
import androidx.compose.ui.res.stringResource
19+
import androidx.compose.ui.tooling.preview.Preview
20+
import androidx.compose.ui.unit.dp
21+
import to.bitkit.R
22+
import to.bitkit.ui.components.BodyM
23+
import to.bitkit.ui.components.Display
24+
import to.bitkit.ui.components.PrimaryButton
25+
import to.bitkit.ui.components.SecondaryButton
26+
import to.bitkit.ui.scaffold.SheetTopBar
27+
import to.bitkit.ui.shared.util.gradientBackground
28+
import to.bitkit.ui.theme.AppThemeSurface
29+
import to.bitkit.ui.theme.Colors
30+
import to.bitkit.ui.utils.withAccent
31+
32+
33+
@Composable
34+
fun BackupIntroScreen(
35+
hasFunds: Boolean,
36+
onClose: () -> Unit,
37+
onConfirm: () -> Unit,
38+
) {
39+
Column(
40+
modifier = Modifier
41+
.fillMaxSize()
42+
.gradientBackground()
43+
.navigationBarsPadding()
44+
.testTag("backup_intro_screen")
45+
) {
46+
SheetTopBar(stringResource(R.string.security__backup_wallet))
47+
48+
Column(
49+
modifier = Modifier.padding(horizontal = 16.dp),
50+
horizontalAlignment = Alignment.CenterHorizontally
51+
) {
52+
Image(
53+
painter = painterResource(R.drawable.safe),
54+
contentDescription = null,
55+
modifier = Modifier
56+
.fillMaxWidth()
57+
.weight(1f)
58+
.testTag("backup_image")
59+
)
60+
61+
Display(
62+
text = stringResource(R.string.security__backup_title).withAccent(accentColor = Colors.Blue),
63+
color = Colors.White,
64+
modifier = Modifier
65+
.testTag("backup_title")
66+
)
67+
Spacer(Modifier.height(8.dp))
68+
BodyM(
69+
text = if (hasFunds) {
70+
stringResource(R.string.security__backup_funds)
71+
} else {
72+
stringResource(R.string.security__backup_funds_no)
73+
},
74+
color = Colors.White64,
75+
modifier = Modifier
76+
.testTag("backup_description")
77+
)
78+
Spacer(Modifier.height(32.dp))
79+
Row(
80+
modifier = Modifier
81+
.fillMaxWidth()
82+
.testTag("buttons_row"),
83+
horizontalArrangement = Arrangement.spacedBy(16.dp)
84+
) {
85+
SecondaryButton(
86+
text = stringResource(R.string.common__later),
87+
fullWidth = false,
88+
onClick = onClose,
89+
modifier = Modifier
90+
.weight(1f)
91+
.testTag("later_button"),
92+
)
93+
94+
PrimaryButton(
95+
text = stringResource(R.string.security__backup_button),
96+
fullWidth = false,
97+
onClick = onConfirm,
98+
modifier = Modifier
99+
.weight(1f)
100+
.testTag("backup_button"),
101+
)
102+
}
103+
Spacer(Modifier.height(16.dp))
104+
}
105+
}
106+
}
107+
108+
@Preview(showBackground = true, name = "has funds")
109+
@Composable
110+
private fun Preview() {
111+
AppThemeSurface {
112+
BackupIntroScreen(
113+
onClose = {},
114+
onConfirm = {},
115+
hasFunds = true
116+
)
117+
}
118+
}
119+
120+
@Preview(showBackground = true, name = "no funds")
121+
@Composable
122+
private fun Preview2() {
123+
AppThemeSurface {
124+
BackupIntroScreen(
125+
onClose = {},
126+
onConfirm = {},
127+
hasFunds = false
128+
)
129+
}
130+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package to.bitkit.ui.settings.backups
2+
3+
import androidx.compose.foundation.layout.Column
4+
import androidx.compose.foundation.layout.fillMaxHeight
5+
import androidx.compose.foundation.layout.fillMaxWidth
6+
import androidx.compose.runtime.Composable
7+
import androidx.compose.ui.Modifier
8+
import androidx.navigation.compose.NavHost
9+
import androidx.navigation.compose.rememberNavController
10+
import kotlinx.serialization.Serializable
11+
import to.bitkit.models.BalanceState
12+
import to.bitkit.ui.utils.composableWithDefaultTransitions
13+
import to.bitkit.viewmodels.WalletViewModel
14+
import androidx.compose.runtime.getValue
15+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
16+
17+
@Composable
18+
fun BackupSheet(
19+
onDismiss: () -> Unit,
20+
walletViewModel: WalletViewModel,
21+
) {
22+
val navController = rememberNavController()
23+
24+
Column(
25+
modifier = Modifier
26+
.fillMaxWidth()
27+
.fillMaxHeight(.775f)
28+
) {
29+
NavHost(
30+
navController = navController,
31+
startDestination = BackupRoute.Intro,
32+
) {
33+
composableWithDefaultTransitions<BackupRoute.Intro> {
34+
val balance : BalanceState by walletViewModel.balanceState.collectAsStateWithLifecycle()
35+
BackupIntroScreen(
36+
hasFunds = balance.totalSats > 0u,
37+
onClose = onDismiss,
38+
onConfirm = {
39+
navController.navigate(BackupRoute.Backup)
40+
}
41+
)
42+
}
43+
composableWithDefaultTransitions<BackupRoute.Backup> {
44+
BackupWalletScreen(
45+
navController = navController
46+
)
47+
}
48+
}
49+
}
50+
}
51+
52+
object BackupRoute {
53+
@Serializable
54+
data object Intro
55+
56+
@Serializable
57+
data object Backup
58+
}

0 commit comments

Comments
 (0)