Skip to content

Commit f6be482

Browse files
committed
refactor: split hardware sheet screens into files
1 parent be3eb93 commit f6be482

3 files changed

Lines changed: 245 additions & 202 deletions

File tree

Lines changed: 2 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,17 @@
11
package to.bitkit.ui.sheets
22

3-
import androidx.compose.foundation.Image
4-
import androidx.compose.foundation.layout.Arrangement
5-
import androidx.compose.foundation.layout.Box
6-
import androidx.compose.foundation.layout.BoxWithConstraints
73
import androidx.compose.foundation.layout.Column
8-
import androidx.compose.foundation.layout.Row
9-
import androidx.compose.foundation.layout.fillMaxSize
104
import androidx.compose.foundation.layout.fillMaxWidth
11-
import androidx.compose.foundation.layout.navigationBarsPadding
12-
import androidx.compose.foundation.layout.offset
13-
import androidx.compose.foundation.layout.padding
14-
import androidx.compose.foundation.layout.size
15-
import androidx.compose.foundation.layout.width
165
import androidx.compose.runtime.Composable
17-
import androidx.compose.runtime.DisposableEffect
18-
import androidx.compose.runtime.getValue
19-
import androidx.compose.runtime.mutableStateOf
20-
import androidx.compose.runtime.remember
21-
import androidx.compose.runtime.setValue
22-
import androidx.compose.ui.Alignment
236
import androidx.compose.ui.Modifier
247
import androidx.compose.ui.platform.testTag
25-
import androidx.compose.ui.res.painterResource
26-
import androidx.compose.ui.res.stringResource
27-
import androidx.compose.ui.tooling.preview.Preview
28-
import androidx.compose.ui.unit.dp
298
import androidx.navigation.compose.NavHost
309
import androidx.navigation.compose.rememberNavController
3110
import kotlinx.serialization.Serializable
32-
import to.bitkit.R
33-
import to.bitkit.ui.components.BodyM
34-
import to.bitkit.ui.components.BottomSheetPreview
35-
import to.bitkit.ui.components.Display
36-
import to.bitkit.ui.components.FillHeight
37-
import to.bitkit.ui.components.KEY_DELETE
38-
import to.bitkit.ui.components.NumberPad
39-
import to.bitkit.ui.components.PrimaryButton
40-
import to.bitkit.ui.components.SecondaryButton
4111
import to.bitkit.ui.components.Sheet
4212
import to.bitkit.ui.components.SheetSize
43-
import to.bitkit.ui.components.VerticalSpacer
44-
import to.bitkit.ui.scaffold.SheetTopBar
4513
import to.bitkit.ui.shared.modifiers.sheetHeight
46-
import to.bitkit.ui.shared.util.gradientBackground
47-
import to.bitkit.ui.theme.AppThemeSurface
48-
import to.bitkit.ui.theme.Colors
4914
import to.bitkit.ui.utils.composableWithDefaultTransitions
50-
import to.bitkit.ui.utils.withAccent
5115

5216
/**
5317
* Entry point for the hardware-wallet connect flow opened from the home suggestion
@@ -68,18 +32,17 @@ fun HardwareSheet(
6832
modifier = Modifier
6933
.fillMaxWidth()
7034
.sheetHeight(SheetSize.LARGE)
71-
.gradientBackground()
7235
.testTag("hardware_sheet")
7336
) {
7437
NavHost(
7538
navController = navController,
7639
startDestination = sheet.route,
7740
) {
7841
composableWithDefaultTransitions<HardwareRoute.Intro> {
79-
HardwareIntro(onClose = onDismiss)
42+
HwIntroSheet(onDismiss)
8043
}
8144
composableWithDefaultTransitions<HardwareRoute.PairingCode> {
82-
HardwarePairing(
45+
HwPairSheet(
8346
onSubmit = onSubmitPairingCode,
8447
onCancel = onCancelPairingCode,
8548
)
@@ -88,173 +51,10 @@ fun HardwareSheet(
8851
}
8952
}
9053

91-
@Composable
92-
private fun HardwareIntro(onClose: () -> Unit) {
93-
Column(modifier = Modifier.fillMaxSize()) {
94-
SheetTopBar(titleText = stringResource(R.string.hardware__intro_title))
95-
BoxWithConstraints(
96-
modifier = Modifier
97-
.fillMaxWidth()
98-
.weight(1f)
99-
) {
100-
val imageSize = maxWidth * INTRO_IMAGE_SIZE_RATIO
101-
val staggerY = maxWidth * INTRO_IMAGE_STAGGER_RATIO
102-
Image(
103-
painter = painterResource(R.drawable.trezor),
104-
contentDescription = null,
105-
modifier = Modifier
106-
.size(imageSize)
107-
.align(Alignment.CenterStart)
108-
.offset(x = -maxWidth * INTRO_TREZOR_BLEED_RATIO, y = staggerY)
109-
)
110-
Image(
111-
painter = painterResource(R.drawable.ledger),
112-
contentDescription = null,
113-
modifier = Modifier
114-
.size(imageSize)
115-
.align(Alignment.CenterEnd)
116-
.offset(x = maxWidth * INTRO_LEDGER_BLEED_RATIO, y = -staggerY)
117-
)
118-
}
119-
Column(
120-
modifier = Modifier
121-
.fillMaxWidth()
122-
.padding(horizontal = 32.dp)
123-
.navigationBarsPadding()
124-
) {
125-
Display(stringResource(R.string.hardware__intro_header).withAccent(accentColor = Colors.Blue))
126-
VerticalSpacer(8.dp)
127-
BodyM(stringResource(R.string.hardware__intro_text), color = Colors.White64)
128-
VerticalSpacer(32.dp)
129-
Row(
130-
horizontalArrangement = Arrangement.spacedBy(16.dp),
131-
modifier = Modifier.fillMaxWidth(),
132-
) {
133-
SecondaryButton(
134-
text = stringResource(R.string.common__cancel),
135-
onClick = onClose,
136-
modifier = Modifier.weight(1f)
137-
)
138-
PrimaryButton(
139-
text = stringResource(R.string.common__continue),
140-
onClick = {},
141-
enabled = false,
142-
modifier = Modifier.weight(1f)
143-
)
144-
}
145-
VerticalSpacer(16.dp)
146-
}
147-
}
148-
}
149-
150-
@Composable
151-
private fun HardwarePairing(
152-
onSubmit: (String) -> Unit,
153-
onCancel: () -> Unit,
154-
) {
155-
var code by remember { mutableStateOf("") }
156-
var submitted by remember { mutableStateOf(false) }
157-
158-
// Dismissing the sheet without submitting (e.g. swipe down) cancels the pending
159-
// pairing request so the connect attempt does not hang until its timeout.
160-
DisposableEffect(Unit) {
161-
onDispose { if (!submitted) onCancel() }
162-
}
163-
164-
Column(modifier = Modifier.fillMaxSize()) {
165-
SheetTopBar(titleText = stringResource(R.string.hardware__pairing_title))
166-
Column(
167-
horizontalAlignment = Alignment.CenterHorizontally,
168-
modifier = Modifier
169-
.fillMaxWidth()
170-
.weight(1f)
171-
.padding(horizontal = 32.dp)
172-
) {
173-
BodyM(stringResource(R.string.hardware__pairing_text), color = Colors.White64)
174-
FillHeight()
175-
// Fixed-width cells so digits replace dots without the row shifting.
176-
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
177-
repeat(PAIRING_CODE_LENGTH) { index ->
178-
val digit = code.getOrNull(index)?.toString()
179-
Box(
180-
contentAlignment = Alignment.Center,
181-
modifier = Modifier.width(PAIRING_CELL_WIDTH)
182-
) {
183-
Display(
184-
text = digit ?: "",
185-
color = if (digit != null) Colors.White else Colors.White32,
186-
)
187-
}
188-
}
189-
}
190-
FillHeight()
191-
}
192-
NumberPad(
193-
onPress = { key ->
194-
when {
195-
key == KEY_DELETE -> code = code.dropLast(1)
196-
code.length < PAIRING_CODE_LENGTH -> {
197-
code += key
198-
if (code.length == PAIRING_CODE_LENGTH) {
199-
submitted = true
200-
onSubmit(code)
201-
}
202-
}
203-
}
204-
},
205-
includeNavigationBarsPadding = true,
206-
)
207-
}
208-
}
209-
21054
sealed interface HardwareRoute {
21155
@Serializable
21256
data object Intro : HardwareRoute
21357

21458
@Serializable
21559
data object PairingCode : HardwareRoute
21660
}
217-
218-
private const val PAIRING_CODE_LENGTH = 6
219-
private val PAIRING_CELL_WIDTH = 32.dp
220-
221-
// Proportions taken from the 375dp-wide Figma frame: 256dp visuals bleeding
222-
// 84dp off the left edge and 53dp off the right, staggered by 12dp vertically.
223-
private const val INTRO_IMAGE_SIZE_RATIO = 256f / 375f
224-
private const val INTRO_TREZOR_BLEED_RATIO = 84f / 375f
225-
private const val INTRO_LEDGER_BLEED_RATIO = 53f / 375f
226-
private const val INTRO_IMAGE_STAGGER_RATIO = 12f / 375f
227-
228-
@Preview(showSystemUi = true)
229-
@Composable
230-
private fun Preview() {
231-
AppThemeSurface {
232-
BottomSheetPreview {
233-
Column(
234-
modifier = Modifier
235-
.fillMaxWidth()
236-
.sheetHeight(SheetSize.LARGE, isModal = true)
237-
.gradientBackground()
238-
) {
239-
HardwareIntro(onClose = {})
240-
}
241-
}
242-
}
243-
}
244-
245-
@Preview(showSystemUi = true)
246-
@Composable
247-
private fun PairingPreview() {
248-
AppThemeSurface {
249-
BottomSheetPreview {
250-
Column(
251-
modifier = Modifier
252-
.fillMaxWidth()
253-
.sheetHeight(SheetSize.LARGE, isModal = true)
254-
.gradientBackground()
255-
) {
256-
HardwarePairing(onSubmit = {}, onCancel = {})
257-
}
258-
}
259-
}
260-
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package to.bitkit.ui.sheets
2+
3+
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.BoxWithConstraints
6+
import androidx.compose.foundation.layout.BoxWithConstraintsScope
7+
import androidx.compose.foundation.layout.Column
8+
import androidx.compose.foundation.layout.Row
9+
import androidx.compose.foundation.layout.fillMaxSize
10+
import androidx.compose.foundation.layout.fillMaxWidth
11+
import androidx.compose.foundation.layout.navigationBarsPadding
12+
import androidx.compose.foundation.layout.offset
13+
import androidx.compose.foundation.layout.padding
14+
import androidx.compose.foundation.layout.size
15+
import androidx.compose.runtime.Composable
16+
import androidx.compose.ui.Alignment
17+
import androidx.compose.ui.Modifier
18+
import androidx.compose.ui.draw.blur
19+
import androidx.compose.ui.res.painterResource
20+
import androidx.compose.ui.res.stringResource
21+
import androidx.compose.ui.tooling.preview.Preview
22+
import androidx.compose.ui.unit.Dp
23+
import androidx.compose.ui.unit.dp
24+
import to.bitkit.R
25+
import to.bitkit.ui.components.BodyM
26+
import to.bitkit.ui.components.BottomSheetPreview
27+
import to.bitkit.ui.components.Display
28+
import to.bitkit.ui.components.PrimaryButton
29+
import to.bitkit.ui.components.SecondaryButton
30+
import to.bitkit.ui.components.VerticalSpacer
31+
import to.bitkit.ui.scaffold.SheetTopBar
32+
import to.bitkit.ui.shared.util.gradientBackground
33+
import to.bitkit.ui.theme.AppThemeSurface
34+
import to.bitkit.ui.theme.Colors
35+
import to.bitkit.ui.utils.withAccent
36+
37+
// Proportions from Figma v61 frame
38+
private const val INTRO_IMAGE_SIZE_RATIO = 256f / 375f
39+
private const val INTRO_TREZOR_BLEED_RATIO = 84f / 375f
40+
private const val INTRO_LEDGER_BLEED_RATIO = 53f / 375f
41+
private const val INTRO_IMAGE_STAGGER_RATIO = 12f / 375f
42+
43+
@Composable
44+
fun HwIntroSheet(
45+
onDismiss: () -> Unit = {},
46+
) {
47+
Column(
48+
modifier = Modifier
49+
.fillMaxSize()
50+
.gradientBackground()
51+
) {
52+
SheetTopBar(titleText = stringResource(R.string.hardware__intro_title))
53+
BoxWithConstraints(
54+
modifier = Modifier
55+
.fillMaxWidth()
56+
.weight(1f)
57+
) {
58+
val imageSize = maxWidth * INTRO_IMAGE_SIZE_RATIO
59+
val staggerY = maxWidth * INTRO_IMAGE_STAGGER_RATIO
60+
TrezorImage(imageSize, staggerY)
61+
LedgerImage(imageSize, staggerY, modifier = Modifier.blur(32.dp))
62+
}
63+
Column(
64+
modifier = Modifier
65+
.fillMaxWidth()
66+
.padding(horizontal = 32.dp)
67+
.navigationBarsPadding()
68+
) {
69+
Display(stringResource(R.string.hardware__intro_header).withAccent(accentColor = Colors.Blue))
70+
VerticalSpacer(8.dp)
71+
BodyM(stringResource(R.string.hardware__intro_text), color = Colors.White64)
72+
VerticalSpacer(32.dp)
73+
Row(
74+
horizontalArrangement = Arrangement.spacedBy(16.dp),
75+
modifier = Modifier.fillMaxWidth(),
76+
) {
77+
SecondaryButton(
78+
text = stringResource(R.string.common__cancel),
79+
onClick = onDismiss,
80+
modifier = Modifier.weight(1f)
81+
)
82+
PrimaryButton(
83+
text = stringResource(R.string.common__continue),
84+
onClick = {},
85+
enabled = false,
86+
modifier = Modifier.weight(1f)
87+
)
88+
}
89+
VerticalSpacer(16.dp)
90+
}
91+
}
92+
}
93+
94+
@Composable
95+
private fun BoxWithConstraintsScope.TrezorImage(
96+
imageSize: Dp,
97+
staggerY: Dp,
98+
modifier: Modifier = Modifier,
99+
) {
100+
Image(
101+
painter = painterResource(R.drawable.trezor),
102+
contentDescription = null,
103+
modifier = modifier
104+
.size(imageSize)
105+
.align(Alignment.CenterStart)
106+
.offset(x = -maxWidth * INTRO_TREZOR_BLEED_RATIO, y = staggerY)
107+
)
108+
}
109+
110+
@Composable
111+
private fun BoxWithConstraintsScope.LedgerImage(
112+
imageSize: Dp,
113+
staggerY: Dp,
114+
modifier: Modifier = Modifier,
115+
) {
116+
Image(
117+
painter = painterResource(R.drawable.ledger),
118+
contentDescription = null,
119+
modifier = modifier
120+
.size(imageSize)
121+
.align(Alignment.CenterEnd)
122+
.offset(x = maxWidth * INTRO_LEDGER_BLEED_RATIO, y = -staggerY)
123+
)
124+
}
125+
126+
@Preview(showSystemUi = true)
127+
@Composable
128+
private fun Preview() {
129+
AppThemeSurface {
130+
BottomSheetPreview {
131+
HwIntroSheet()
132+
}
133+
}
134+
}

0 commit comments

Comments
 (0)