Skip to content

Commit

Permalink
Merge branch 'unify-buttons-droid-379'
Browse files Browse the repository at this point in the history
  • Loading branch information
Pururun committed Oct 18, 2023
2 parents dd18767 + 4bdd28f commit c26729e
Show file tree
Hide file tree
Showing 29 changed files with 499 additions and 547 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,33 +1,43 @@
package net.mullvad.mullvadvpn.compose.button

import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.lib.theme.color.AlphaDisconnectButton
import net.mullvad.mullvadvpn.lib.theme.color.onVariant
import net.mullvad.mullvadvpn.lib.theme.color.variant
import net.mullvad.mullvadvpn.model.TunnelState

@Composable
Expand All @@ -42,14 +52,14 @@ fun ConnectionButton(
) {
val containerColor =
if (state is TunnelState.Disconnected) {
MaterialTheme.colorScheme.surface
MaterialTheme.colorScheme.variant
} else {
MaterialTheme.colorScheme.error.copy(alpha = AlphaDisconnectButton)
}

val contentColor =
if (state is TunnelState.Disconnected) {
MaterialTheme.colorScheme.onSurface
MaterialTheme.colorScheme.onVariant
} else {
MaterialTheme.colorScheme.onError
}
Expand Down Expand Up @@ -108,11 +118,12 @@ private fun PreviewConnectionButton() {
containerColor = MaterialTheme.colorScheme.error.copy(alpha = AlphaDisconnectButton),
contentColor = MaterialTheme.colorScheme.onError,
reconnectClick = {},
isReconnectButtonEnabled = false
isReconnectButtonEnabled = true
)
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ConnectionButton(
text: String,
Expand All @@ -122,62 +133,98 @@ private fun ConnectionButton(
containerColor: Color,
contentColor: Color,
modifier: Modifier = Modifier,
height: Dp = Dimens.connectButtonHeight,
reconnectButtonTestTag: String = ""
) {
Row(modifier = modifier.height(height)) {
Button(
onClick = mainClick,
shape =
MaterialTheme.shapes.small.copy(
topEnd = CornerSize(percent = 0),
bottomEnd = CornerSize(percent = 0)
),
colors =
ButtonDefaults.buttonColors(
containerColor = containerColor,
contentColor = contentColor
),
modifier = Modifier.weight(1f).height(height)
) {
// Offset to compensate for the reconnect button.
val paddingOffset =
if (isReconnectButtonEnabled) {
height + Dimens.listItemDivider
} else {
0.dp
}
Text(
text = text,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(start = paddingOffset)
)
}
ConstraintLayout(modifier = modifier.fillMaxWidth()) {
// initial height set at 0.dp
var componentHeight by remember { mutableStateOf(0.dp) }

if (isReconnectButtonEnabled) {
Spacer(modifier = Modifier.width(Dimens.listItemDivider))
// get local density from composable
val density = LocalDensity.current

FilledIconButton(
val (connectionButton, reconnectButton) = createRefs()
CompositionLocalProvider(
LocalMinimumInteractiveComponentEnforcement provides false,
) {
val dividerSize = Dimens.listItemDivider

Button(
onClick = mainClick,
shape =
MaterialTheme.shapes.small.copy(
topStart = CornerSize(percent = 0),
bottomStart = CornerSize(percent = 0)
),
if (isReconnectButtonEnabled) {
MaterialTheme.shapes.small.copy(
topEnd = CornerSize(percent = 0),
bottomEnd = CornerSize(percent = 0)
)
} else {
MaterialTheme.shapes.small
},
colors =
IconButtonDefaults.filledIconButtonColors(
ButtonDefaults.buttonColors(
containerColor = containerColor,
contentColor = contentColor
),
onClick = reconnectClick,
modifier =
Modifier.height(height).aspectRatio(1f, true).testTag(reconnectButtonTestTag)
Modifier.constrainAs(connectionButton) {
start.linkTo(parent.start)
if (isReconnectButtonEnabled) {
end.linkTo(reconnectButton.start)
} else {
end.linkTo(parent.end)
}
width = Dimension.fillToConstraints
height = Dimension.wrapContent
}
.onGloballyPositioned {
componentHeight = with(density) { it.size.height.toDp() }
}
) {
Icon(
painter = painterResource(id = R.drawable.icon_reload),
contentDescription = null
// Offset to compensate for the reconnect button.
Text(
text = text,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier =
if (isReconnectButtonEnabled) {
Modifier.padding(start = componentHeight + Dimens.listItemDivider)
} else {
Modifier
}
)
}

if (isReconnectButtonEnabled) {
FilledIconButton(
shape =
MaterialTheme.shapes.small.copy(
topStart = CornerSize(percent = 0),
bottomStart = CornerSize(percent = 0)
),
colors =
IconButtonDefaults.filledIconButtonColors(
containerColor = containerColor,
contentColor = contentColor
),
onClick = reconnectClick,
modifier =
Modifier.testTag(reconnectButtonTestTag)
.constrainAs(reconnectButton) {
start.linkTo(connectionButton.end, margin = dividerSize)
top.linkTo(connectionButton.top)
bottom.linkTo(connectionButton.bottom)
end.linkTo(parent.end)
height = Dimension.fillToConstraints
}
.aspectRatio(1f, true)
) {
Icon(
painter = painterResource(id = R.drawable.icon_reload),
contentDescription = null
)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.mullvad.mullvadvpn.compose.button

import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.state.DeviceRevokedUiState

@Composable
fun DeviceRevokedLoginButton(onClick: () -> Unit, state: DeviceRevokedUiState) {
if (state == DeviceRevokedUiState.SECURED) {
NegativeButton(text = stringResource(id = R.string.go_to_login), onClick = onClick)
} else {
VariantButton(text = stringResource(id = R.string.go_to_login), onClick = onClick)
}
}
Original file line number Diff line number Diff line change
@@ -1,70 +1,51 @@
package net.mullvad.mullvadvpn.compose.button

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.constraintlayout.compose.ConstraintLayout
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.lib.theme.color.AlphaDisabled
import net.mullvad.mullvadvpn.lib.theme.color.AlphaVisible

@Preview
@Composable
private fun PreviewExternalActionButton() {
private fun PreviewExternalButtonEnabled() {
AppTheme { ExternalButton(onClick = {}, text = "Button", isEnabled = true) }
}

@Preview
@Composable
private fun PreviewExternalButtonDisabled() {
AppTheme { ExternalButton(onClick = {}, text = "Button", isEnabled = false) }
}

@Preview
@Composable
private fun PreviewExternalButtonLongText() {
AppTheme {
ExternalActionButton(onClick = {}, colors = ButtonDefaults.buttonColors(), text = "Button")
ExternalButton(
onClick = {},
text = "Button text is long and is trying to take up space that is large",
isEnabled = true
)
}
}

@Composable
fun ExternalActionButton(
fun ExternalButton(
onClick: () -> Unit,
colors: ButtonColors,
text: String,
modifier: Modifier = Modifier,
isEnabled: Boolean = true,
) {
ActionButton(
VariantButton(
text = text,
onClick = onClick,
colors = colors,
modifier = modifier,
isEnabled = isEnabled,
) {
ConstraintLayout(modifier = Modifier.fillMaxSize()) {
val (title, logo) = createRefs()
Text(
text = text,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyMedium,
modifier =
Modifier.constrainAs(title) {
end.linkTo(logo.start)
centerTo(parent)
}
)
Image(
painter = painterResource(id = R.drawable.icon_extlink),
contentDescription = null,
modifier =
Modifier.constrainAs(logo) {
centerVerticallyTo(parent)
end.linkTo(parent.end)
}
.padding(horizontal = Dimens.smallPadding)
.alpha(if (isEnabled) AlphaVisible else AlphaDisabled)
)
}
}
icon = {
Icon(painter = painterResource(id = R.drawable.icon_extlink), contentDescription = null)
},
)
}
Loading

0 comments on commit c26729e

Please sign in to comment.