11package to.bitkit.ui.components
22
3+ import androidx.compose.animation.animateColorAsState
34import androidx.compose.foundation.BorderStroke
5+ import androidx.compose.foundation.clickable
6+ import androidx.compose.foundation.interaction.MutableInteractionSource
7+ import androidx.compose.foundation.interaction.collectIsPressedAsState
48import androidx.compose.foundation.layout.Arrangement
59import androidx.compose.foundation.layout.Box
610import androidx.compose.foundation.layout.Column
@@ -13,22 +17,26 @@ import androidx.compose.foundation.layout.size
1317import androidx.compose.material.icons.Icons
1418import androidx.compose.material.icons.filled.Favorite
1519import androidx.compose.material.icons.filled.Home
16- import androidx.compose.material3.Button
1720import androidx.compose.material3.CircularProgressIndicator
1821import androidx.compose.material3.Icon
19- import androidx.compose.material3.OutlinedButton
22+ import androidx.compose.material3.LocalContentColor
23+ import androidx.compose.material3.MaterialTheme
24+ import androidx.compose.material3.Surface
2025import androidx.compose.material3.Text
21- import androidx.compose.material3.TextButton
2226import androidx.compose.runtime.Composable
27+ import androidx.compose.runtime.CompositionLocalProvider
28+ import androidx.compose.runtime.getValue
29+ import androidx.compose.runtime.remember
2330import androidx.compose.ui.Alignment
2431import androidx.compose.ui.Modifier
2532import androidx.compose.ui.draw.alpha
33+ import androidx.compose.ui.draw.shadow
2634import androidx.compose.ui.graphics.Color
2735import androidx.compose.ui.text.style.TextOverflow
2836import androidx.compose.ui.tooling.preview.Preview
2937import androidx.compose.ui.unit.Dp
3038import androidx.compose.ui.unit.dp
31- import to.bitkit.ui.theme.AppButtonDefaults
39+ import to.bitkit.ui.shared.util.gradientBackground
3240import to.bitkit.ui.theme.AppThemeSurface
3341import to.bitkit.ui.theme.Colors
3442
@@ -57,41 +65,72 @@ fun PrimaryButton(
5765 size : ButtonSize = ButtonSize .Large ,
5866 enabled : Boolean = true,
5967 fullWidth : Boolean = true,
60- color : Color = Colors .White16 ,
6168) {
69+ val interactionSource = remember { MutableInteractionSource () }
70+ val isPressed by interactionSource.collectIsPressedAsState()
71+
6272 val contentPadding = PaddingValues (horizontal = size.horizontalPadding.takeIf { text != null } ? : 0 .dp)
63- Button (
64- onClick = onClick,
65- enabled = enabled && ! isLoading,
66- colors = AppButtonDefaults .primaryColors.copy(containerColor = color) ,
67- contentPadding = contentPadding ,
73+ val shape = MaterialTheme .shapes.extraLarge
74+
75+ Surface (
76+ shape = shape ,
77+ color = Color . Transparent ,
6878 modifier = Modifier
6979 .then(if (fullWidth) Modifier .fillMaxWidth() else Modifier )
7080 .requiredHeight(size.height)
7181 .then(modifier)
72- ) {
73- if (isLoading) {
74- CircularProgressIndicator (
75- color = Colors .White32 ,
76- strokeWidth = 2 .dp,
77- modifier = Modifier .size(size.height / 2 )
82+ .shadow(
83+ elevation = 4 .dp,
84+ shape = shape,
85+ ambientColor = Colors .White .copy(alpha = if (isPressed) 0.4f else 0.25f ),
86+ spotColor = Colors .White .copy(alpha = if (isPressed) 0.4f else 0.25f )
7887 )
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()
87- }
88+ .then(
89+ if (isPressed) {
90+ Modifier .gradientBackground(startColor = Colors .Gray4 , endColor = Colors .Gray5 )
91+ } else {
92+ Modifier .gradientBackground(startColor = Colors .Gray5 , endColor = Colors .Black )
8893 }
89- text?.let {
90- Text (
91- text = text,
92- maxLines = 1 ,
93- overflow = TextOverflow .Ellipsis ,
94- )
94+ )
95+ .then(if (enabled) Modifier else Modifier .alpha(0.32f ))
96+ .clickable(
97+ onClick = onClick,
98+ enabled = enabled && ! isLoading,
99+ interactionSource = interactionSource,
100+ indication = null
101+ )
102+ ) {
103+ Box (
104+ contentAlignment = Alignment .Center ,
105+ modifier = Modifier
106+ .then(if (fullWidth) Modifier .fillMaxWidth() else Modifier )
107+ .padding(contentPadding)
108+ ) {
109+ if (isLoading) {
110+ CircularProgressIndicator (
111+ color = Colors .White32 ,
112+ strokeWidth = 2 .dp,
113+ modifier = Modifier .size(size.height / 2 )
114+ )
115+ } else {
116+ CompositionLocalProvider (LocalContentColor provides Colors .White ) {
117+ Row (
118+ verticalAlignment = Alignment .CenterVertically ,
119+ horizontalArrangement = Arrangement .spacedBy(8 .dp),
120+ ) {
121+ if (icon != null ) {
122+ Box (modifier = if (enabled) Modifier else Modifier .alpha(0.5f )) {
123+ icon()
124+ }
125+ }
126+ text?.let {
127+ Text (
128+ text = text,
129+ maxLines = 1 ,
130+ overflow = TextOverflow .Ellipsis ,
131+ )
132+ }
133+ }
95134 }
96135 }
97136 }
@@ -109,42 +148,70 @@ fun SecondaryButton(
109148 enabled : Boolean = true,
110149 fullWidth : Boolean = true,
111150) {
151+ val interactionSource = remember { MutableInteractionSource () }
152+ val isPressed by interactionSource.collectIsPressedAsState()
153+
154+ val backgroundColor by animateColorAsState(
155+ targetValue = if (isPressed) Colors .White10 else Colors .White01 ,
156+ label = " secondaryButtonBackground"
157+ )
158+ val borderColor by animateColorAsState(
159+ targetValue = if (enabled) Colors .Gray4 else Color .Transparent ,
160+ label = " secondaryButtonBorder"
161+ )
162+
112163 val contentPadding = PaddingValues (horizontal = size.horizontalPadding.takeIf { text != null } ? : 0 .dp)
113- val border = BorderStroke (2 .dp, if (enabled) Colors .White16 else Color .Transparent )
114- OutlinedButton (
115- onClick = onClick,
116- enabled = enabled && ! isLoading,
117- colors = AppButtonDefaults .secondaryColors,
118- contentPadding = contentPadding,
119- border = border,
164+ val shape = MaterialTheme .shapes.extraLarge
165+
166+ Surface (
167+ shape = shape,
168+ color = backgroundColor,
169+ border = BorderStroke (2 .dp, borderColor),
120170 modifier = Modifier
121171 .then(if (fullWidth) Modifier .fillMaxWidth() else Modifier )
122172 .requiredHeight(size.height)
123173 .then(modifier)
124- ) {
125- if (isLoading) {
126- CircularProgressIndicator (
127- color = Colors .White32 ,
128- strokeWidth = 2 .dp,
129- modifier = Modifier .size(size.height / 2 )
174+ .clickable(
175+ onClick = onClick,
176+ enabled = enabled && ! isLoading,
177+ interactionSource = interactionSource,
178+ indication = null
130179 )
131- } else {
132- Row (
133- verticalAlignment = Alignment .CenterVertically ,
134- horizontalArrangement = Arrangement .spacedBy(8 .dp),
135- ) {
136- if (icon != null ) {
137- Box (modifier = if (enabled) Modifier else Modifier .alpha(0.5f )) {
138- icon()
180+ ) {
181+ Box (
182+ contentAlignment = Alignment .Center ,
183+ modifier = Modifier
184+ .then(if (fullWidth) Modifier .fillMaxWidth() else Modifier )
185+ .padding(contentPadding)
186+ ) {
187+ if (isLoading) {
188+ CircularProgressIndicator (
189+ color = Colors .White32 ,
190+ strokeWidth = 2 .dp,
191+ modifier = Modifier .size(size.height / 2 )
192+ )
193+ } else {
194+ CompositionLocalProvider (
195+ LocalContentColor provides if (enabled) Colors .White80 else Colors .White32
196+ ) {
197+ Row (
198+ verticalAlignment = Alignment .CenterVertically ,
199+ horizontalArrangement = Arrangement .spacedBy(8 .dp),
200+ ) {
201+ if (icon != null ) {
202+ Box (modifier = if (enabled) Modifier else Modifier .alpha(0.5f )) {
203+ icon()
204+ }
205+ }
206+ text?.let {
207+ Text (
208+ text = text,
209+ maxLines = 1 ,
210+ overflow = TextOverflow .Ellipsis ,
211+ )
212+ }
139213 }
140214 }
141- text?.let {
142- Text (
143- text = text,
144- maxLines = 1 ,
145- overflow = TextOverflow .Ellipsis ,
146- )
147- }
148215 }
149216 }
150217 }
@@ -161,35 +228,67 @@ fun TertiaryButton(
161228 enabled : Boolean = true,
162229 fullWidth : Boolean = true,
163230) {
231+ val interactionSource = remember { MutableInteractionSource () }
232+ val isPressed by interactionSource.collectIsPressedAsState()
233+
234+ val textColor by animateColorAsState(
235+ targetValue = when {
236+ ! enabled -> Colors .White32
237+ isPressed -> Colors .White
238+ else -> Colors .White80
239+ },
240+ label = " tertiaryButtonText"
241+ )
242+
164243 val contentPadding = PaddingValues (horizontal = size.horizontalPadding.takeIf { text != null } ? : 0 .dp)
165- TextButton (
166- onClick = onClick,
167- enabled = enabled && ! isLoading,
168- colors = AppButtonDefaults .tertiaryColors ,
169- contentPadding = contentPadding ,
244+ val shape = MaterialTheme .shapes.extraLarge
245+
246+ Surface (
247+ shape = shape ,
248+ color = Color . Transparent ,
170249 modifier = Modifier
171250 .then(if (fullWidth) Modifier .fillMaxWidth() else Modifier )
172251 .requiredHeight(size.height)
173252 .then(modifier)
174- ) {
175- if (isLoading) {
176- CircularProgressIndicator (
177- color = Colors .White32 ,
178- strokeWidth = 2 .dp,
179- modifier = Modifier .size(size.height / 2 )
253+ .clickable(
254+ onClick = onClick,
255+ enabled = enabled && ! isLoading,
256+ interactionSource = interactionSource,
257+ indication = null
180258 )
181- } else {
182- if (icon != null ) {
183- Box (modifier = if (enabled) Modifier else Modifier .alpha(0.5f )) {
184- icon()
185- }
186- }
187- text?.let {
188- Text (
189- text = text,
190- maxLines = 1 ,
191- overflow = TextOverflow .Ellipsis ,
259+ ) {
260+ Box (
261+ contentAlignment = Alignment .Center ,
262+ modifier = Modifier
263+ .then(if (fullWidth) Modifier .fillMaxWidth() else Modifier )
264+ .padding(contentPadding)
265+ ) {
266+ if (isLoading) {
267+ CircularProgressIndicator (
268+ color = Colors .White32 ,
269+ strokeWidth = 2 .dp,
270+ modifier = Modifier .size(size.height / 2 )
192271 )
272+ } else {
273+ CompositionLocalProvider (LocalContentColor provides textColor) {
274+ Row (
275+ verticalAlignment = Alignment .CenterVertically ,
276+ horizontalArrangement = Arrangement .spacedBy(8 .dp),
277+ ) {
278+ if (icon != null ) {
279+ Box (modifier = if (enabled) Modifier else Modifier .alpha(0.5f )) {
280+ icon()
281+ }
282+ }
283+ text?.let {
284+ Text (
285+ text = text,
286+ maxLines = 1 ,
287+ overflow = TextOverflow .Ellipsis ,
288+ )
289+ }
290+ }
291+ }
193292 }
194293 }
195294 }
@@ -241,11 +340,10 @@ private fun PrimaryButtonPreview() {
241340 onClick = {},
242341 )
243342 PrimaryButton (
244- text = " Primary Small Color Not Full" ,
343+ text = " Primary Small Not Full" ,
245344 size = ButtonSize .Small ,
246345 onClick = {},
247346 fullWidth = false ,
248- color = Colors .Brand ,
249347 )
250348 PrimaryButton (
251349 text = " Primary Small Loading" ,
0 commit comments