Skip to content

Commit 25b2a4e

Browse files
authored
Merge pull request #495 from synonymdev/feat/buttons-v59
Primary, Secondary and Tertiary Buttons v59
2 parents c086a6c + e83f1c8 commit 25b2a4e

File tree

6 files changed

+186
-49
lines changed

6 files changed

+186
-49
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fun BottomSheet(
5353
contentAlignment = Alignment.Center,
5454
modifier = Modifier
5555
.fillMaxWidth()
56-
.background(color = Colors.Gray6)
56+
.background(color = Colors.White08)
5757
) {
5858
SheetDragHandle()
5959
}

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

Lines changed: 99 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@ import androidx.compose.material.icons.filled.Home
1616
import androidx.compose.material3.Button
1717
import androidx.compose.material3.CircularProgressIndicator
1818
import androidx.compose.material3.Icon
19+
import androidx.compose.material3.MaterialTheme
1920
import androidx.compose.material3.OutlinedButton
2021
import androidx.compose.material3.Text
2122
import androidx.compose.material3.TextButton
2223
import androidx.compose.runtime.Composable
2324
import androidx.compose.ui.Alignment
2425
import androidx.compose.ui.Modifier
25-
import androidx.compose.ui.draw.alpha
2626
import androidx.compose.ui.graphics.Color
27+
import androidx.compose.ui.graphics.ColorFilter
28+
import androidx.compose.ui.graphics.graphicsLayer
2729
import androidx.compose.ui.text.style.TextOverflow
2830
import androidx.compose.ui.tooling.preview.Preview
2931
import androidx.compose.ui.unit.Dp
3032
import androidx.compose.ui.unit.dp
33+
import to.bitkit.ui.shared.util.primaryButtonStyle
3134
import to.bitkit.ui.theme.AppButtonDefaults
3235
import to.bitkit.ui.theme.AppThemeSurface
3336
import to.bitkit.ui.theme.Colors
@@ -57,41 +60,68 @@ fun PrimaryButton(
5760
size: ButtonSize = ButtonSize.Large,
5861
enabled: Boolean = true,
5962
fullWidth: Boolean = true,
60-
color: Color = Colors.White16,
63+
color: Color? = null,
6164
) {
6265
val contentPadding = PaddingValues(horizontal = size.horizontalPadding.takeIf { text != null } ?: 0.dp)
66+
val buttonShape = MaterialTheme.shapes.large
67+
6368
Button(
6469
onClick = onClick,
6570
enabled = enabled && !isLoading,
66-
colors = AppButtonDefaults.primaryColors.copy(containerColor = color),
67-
contentPadding = contentPadding,
71+
colors = AppButtonDefaults.primaryColors.copy(
72+
containerColor = Color.Transparent,
73+
disabledContainerColor = Color.Transparent
74+
),
75+
contentPadding = PaddingValues(0.dp),
76+
shape = buttonShape,
6877
modifier = Modifier
6978
.then(if (fullWidth) Modifier.fillMaxWidth() else Modifier)
7079
.requiredHeight(size.height)
7180
.then(modifier)
7281
) {
73-
if (isLoading) {
74-
CircularProgressIndicator(
75-
color = Colors.White32,
76-
strokeWidth = 2.dp,
77-
modifier = Modifier.size(size.height / 2)
78-
)
79-
} else {
80-
Row(
81-
verticalAlignment = Alignment.CenterVertically,
82-
horizontalArrangement = Arrangement.spacedBy(8.dp),
83-
) {
84-
if (icon != null) {
85-
Box(modifier = if (enabled) Modifier else Modifier.alpha(0.5f)) {
86-
icon()
82+
Box(
83+
contentAlignment = Alignment.Center,
84+
modifier = Modifier
85+
.then(if (fullWidth) Modifier.fillMaxWidth() else Modifier)
86+
.requiredHeight(size.height)
87+
.primaryButtonStyle(
88+
isEnabled = enabled && !isLoading,
89+
shape = buttonShape,
90+
primaryColor = color
91+
)
92+
.padding(contentPadding)
93+
) {
94+
if (isLoading) {
95+
CircularProgressIndicator(
96+
color = Colors.White32,
97+
strokeWidth = 2.dp,
98+
modifier = Modifier.size(size.height / 2)
99+
)
100+
} else {
101+
Row(
102+
verticalAlignment = Alignment.CenterVertically,
103+
horizontalArrangement = Arrangement.spacedBy(8.dp),
104+
) {
105+
if (icon != null) {
106+
Box(
107+
modifier = if (enabled) {
108+
Modifier
109+
} else {
110+
Modifier.graphicsLayer {
111+
colorFilter = ColorFilter.tint(Colors.White32)
112+
}
113+
}
114+
) {
115+
icon()
116+
}
117+
}
118+
text?.let {
119+
Text(
120+
text = text,
121+
maxLines = 1,
122+
overflow = TextOverflow.Ellipsis,
123+
)
87124
}
88-
}
89-
text?.let {
90-
Text(
91-
text = text,
92-
maxLines = 1,
93-
overflow = TextOverflow.Ellipsis,
94-
)
95125
}
96126
}
97127
}
@@ -110,7 +140,7 @@ fun SecondaryButton(
110140
fullWidth: Boolean = true,
111141
) {
112142
val contentPadding = PaddingValues(horizontal = size.horizontalPadding.takeIf { text != null } ?: 0.dp)
113-
val border = BorderStroke(2.dp, if (enabled) Colors.White16 else Color.Transparent)
143+
val border = BorderStroke(2.dp, if (enabled) Colors.Gray4 else Color.Transparent)
114144
OutlinedButton(
115145
onClick = onClick,
116146
enabled = enabled && !isLoading,
@@ -134,7 +164,15 @@ fun SecondaryButton(
134164
horizontalArrangement = Arrangement.spacedBy(8.dp),
135165
) {
136166
if (icon != null) {
137-
Box(modifier = if (enabled) Modifier else Modifier.alpha(0.5f)) {
167+
Box(
168+
modifier = if (enabled) {
169+
Modifier
170+
} else {
171+
Modifier.graphicsLayer {
172+
colorFilter = ColorFilter.tint(Colors.White32)
173+
}
174+
}
175+
) {
138176
icon()
139177
}
140178
}
@@ -179,17 +217,30 @@ fun TertiaryButton(
179217
modifier = Modifier.size(size.height / 2)
180218
)
181219
} else {
182-
if (icon != null) {
183-
Box(modifier = if (enabled) Modifier else Modifier.alpha(0.5f)) {
184-
icon()
220+
Row(
221+
verticalAlignment = Alignment.CenterVertically,
222+
horizontalArrangement = Arrangement.spacedBy(8.dp),
223+
) {
224+
if (icon != null) {
225+
Box(
226+
modifier = if (enabled) {
227+
Modifier
228+
} else {
229+
Modifier.graphicsLayer {
230+
colorFilter = ColorFilter.tint(Colors.White32)
231+
}
232+
}
233+
) {
234+
icon()
235+
}
236+
}
237+
text?.let {
238+
Text(
239+
text = text,
240+
maxLines = 1,
241+
overflow = TextOverflow.Ellipsis,
242+
)
185243
}
186-
}
187-
text?.let {
188-
Text(
189-
text = text,
190-
maxLines = 1,
191-
overflow = TextOverflow.Ellipsis,
192-
)
193244
}
194245
}
195246
}
@@ -237,6 +288,7 @@ private fun PrimaryButtonPreview() {
237288
)
238289
PrimaryButton(
239290
text = "Primary Small",
291+
fullWidth = false,
240292
size = ButtonSize.Small,
241293
onClick = {},
242294
)
@@ -339,6 +391,7 @@ private fun SecondaryButtonPreview() {
339391
SecondaryButton(
340392
text = "Secondary Small",
341393
size = ButtonSize.Small,
394+
fullWidth = false,
342395
onClick = {},
343396
)
344397
SecondaryButton(
@@ -421,11 +474,20 @@ private fun TertiaryButtonPreview() {
421474
TertiaryButton(
422475
text = "Tertiary Disabled",
423476
enabled = false,
477+
icon = {
478+
Icon(
479+
imageVector = Icons.Filled.Favorite,
480+
contentDescription = "",
481+
tint = Colors.Brand,
482+
modifier = Modifier.size(16.dp)
483+
)
484+
},
424485
onClick = {}
425486
)
426487
TertiaryButton(
427488
text = "Tertiary Small",
428489
size = ButtonSize.Small,
490+
fullWidth = false,
429491
onClick = {}
430492
)
431493
TertiaryButton(

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.compose.runtime.Stable
2121
import androidx.compose.runtime.getValue
2222
import androidx.compose.runtime.rememberCoroutineScope
2323
import androidx.compose.ui.Modifier
24+
import androidx.compose.ui.graphics.Color
2425
import androidx.compose.ui.unit.dp
2526
import kotlinx.coroutines.launch
2627
import to.bitkit.ui.sheets.BackupRoute
@@ -31,6 +32,8 @@ import to.bitkit.ui.theme.Colors
3132

3233
enum class SheetSize { LARGE, MEDIUM, SMALL, CALENDAR; }
3334

35+
private val sheetContainerColor = Color(0xFF141414) // Equivalent to White08 on a Black background
36+
3437
@Stable
3538
sealed interface Sheet {
3639
data class Send(val route: SendRoute = SendRoute.Recipient) : Sheet
@@ -92,7 +95,7 @@ fun SheetHost(
9295
sheetShape = AppShapes.sheet,
9396
sheetContent = sheets,
9497
sheetDragHandle = { SheetDragHandle() },
95-
sheetContainerColor = Colors.Gray6,
98+
sheetContainerColor = sheetContainerColor,
9699
sheetContentColor = MaterialTheme.colorScheme.onSurface,
97100
) {
98101
content()

app/src/main/java/to/bitkit/ui/settings/backups/ShowMnemonicScreen.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ private fun ShowMnemonicContent(
168168
text = stringResource(R.string.security__mnemonic_reveal),
169169
fullWidth = false,
170170
onClick = onRevealClick,
171-
color = Colors.Black50,
172171
modifier = Modifier
173172
.alpha(buttonAlpha)
174173
.testTag("TapToReveal")

app/src/main/java/to/bitkit/ui/shared/util/Modifiers.kt

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,17 @@ import androidx.compose.runtime.mutableStateOf
1717
import androidx.compose.runtime.remember
1818
import androidx.compose.ui.Modifier
1919
import androidx.compose.ui.composed
20+
import androidx.compose.ui.draw.clip
21+
import androidx.compose.ui.draw.drawWithContent
22+
import androidx.compose.ui.draw.shadow
23+
import androidx.compose.ui.geometry.Offset
24+
import androidx.compose.ui.geometry.Size
2025
import androidx.compose.ui.graphics.Brush
2126
import androidx.compose.ui.graphics.Color
27+
import androidx.compose.ui.graphics.Shape
2228
import androidx.compose.ui.graphics.graphicsLayer
2329
import androidx.compose.ui.input.pointer.pointerInput
30+
import androidx.compose.ui.unit.dp
2431
import to.bitkit.ui.theme.Colors
2532

2633
/**
@@ -71,12 +78,17 @@ fun Modifier.clickableAlpha(
7178
)
7279
}
7380

74-
fun Modifier.gradientBackground(startColor: Color = Colors.Gray6, endColor: Color = Colors.Black): Modifier {
75-
return this.background(
76-
brush = Brush.verticalGradient(
77-
colors = listOf(startColor, endColor)
81+
fun Modifier.gradientBackground(
82+
startColor: Color = Colors.White08,
83+
endColor: Color = Color.White.copy(alpha = 0.012f),
84+
): Modifier {
85+
return this
86+
.background(Color.Black)
87+
.background(
88+
brush = Brush.verticalGradient(
89+
colors = listOf(startColor, endColor)
90+
)
7891
)
79-
)
8092
}
8193

8294
fun Modifier.blockPointerInputPassthrough(): Modifier {
@@ -97,3 +109,63 @@ fun Modifier.screen(
97109
.fillMaxSize()
98110
.then(if (noBackground) Modifier else Modifier.background(MaterialTheme.colorScheme.background))
99111
.then(if (insets == null) Modifier else Modifier.windowInsetsPadding(insets))
112+
113+
fun Modifier.primaryButtonStyle(
114+
isEnabled: Boolean,
115+
shape: Shape,
116+
primaryColor: Color? = null,
117+
): Modifier {
118+
return this
119+
// Step 1: Add shadow (only when enabled)
120+
.then(
121+
if (isEnabled) {
122+
Modifier.shadow(
123+
elevation = 16.dp,
124+
shape = shape,
125+
clip = false // Don't clip content, just add shadow
126+
)
127+
} else {
128+
Modifier
129+
}
130+
)
131+
// Step 2: Clip to shape first
132+
.clip(shape)
133+
// Step 3: Apply gradient background with border overlay
134+
.then(
135+
if (isEnabled) {
136+
Modifier.drawWithContent {
137+
// Draw the main gradient background filling entire button
138+
val mainBrush = Brush.verticalGradient(
139+
colors = listOf(primaryColor ?: Colors.Gray5, Colors.Gray6),
140+
startY = 0f,
141+
endY = size.height
142+
)
143+
drawRect(
144+
brush = mainBrush,
145+
topLeft = Offset.Zero,
146+
size = size
147+
)
148+
149+
// Draw top border highlight (2dp gradient fade)
150+
val borderHeight = 2.dp.toPx()
151+
drawRect(
152+
brush = Brush.verticalGradient(
153+
colors = listOf(
154+
Colors.White16,
155+
Color.Transparent
156+
),
157+
startY = 0f,
158+
endY = borderHeight
159+
),
160+
topLeft = Offset(0f, 0f),
161+
size = Size(size.width, borderHeight)
162+
)
163+
164+
// Draw the actual button content on top
165+
drawContent()
166+
}
167+
} else {
168+
Modifier.background(Colors.White06)
169+
}
170+
)
171+
}

app/src/main/java/to/bitkit/ui/theme/Colors.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ object Colors {
1616
val White = Color(0xFFFFFFFF)
1717

1818
// Gray Base
19-
val Gray6 = Color(0xFF151515)
20-
val Gray5 = Color(0xFF1C1C1D)
21-
val Gray4 = Color(0xFF3A343C)
19+
val Gray7 = Color(0xFF101010)
20+
val Gray6 = Color(0xFF1C1C1C)
21+
val Gray5 = Color(0xFF2A2A2A)
22+
val Gray4 = Color(0xFF3A3A3A)
2223
val Gray3 = Color(0xFF48484A)
2324
val Gray2 = Color(0xFF636366)
24-
val Gray1 = Color(0xFF8E8E93)
25+
val Gray1 = Color(0xFF8E8E8E)
2526

2627
// Alpha
2728
val Black50 = Color.Black.copy(alpha = 0.5f)

0 commit comments

Comments
 (0)