[Compound] Implement components (Button) (#1021)

* Create `CompoundButton`

* Some fixes

* Lint fixes

* Start replacing existing `Button` usages

* Replace button usages

* Remove previous Button composable

* Rename `CompoundButton` to `Button`

* Fix emphasized button being displayed as Text

* Fix cancel button in `WaitListView`

* Update screenshots

* Add shorthand functions for `OutlinedButton` and `TextButton`

* Add changelog

* Fix wrong size used for emphasized button in dialog

* Create a private `ButtonInternal` implementation with the shared logic.

- Make `ButtonStyle` private.
- Rename `title` to `text`.
- Rename `buttonStyle` and `buttonSize` to just `style` and `size`.

* Fix several warnings and lint issues.

* Update screenshots

---------

Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
Jorge Martin Espinosa 2023-08-08 18:11:37 +02:00 committed by GitHub
parent fdee5d8a76
commit 23982dde47
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
228 changed files with 805 additions and 950 deletions

1
changelog.d/1021.misc Normal file
View file

@ -0,0 +1 @@
Add Button component based on Compound designs

View file

@ -54,6 +54,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
@ -188,17 +189,16 @@ private fun AnalyticsOptInFooter(
modifier = modifier,
) {
Button(
text = stringResource(id = CommonStrings.action_ok),
onClick = onTermsAccepted,
modifier = Modifier.fillMaxWidth(),
) {
Text(text = stringResource(id = CommonStrings.action_ok))
}
)
TextButton(
text = stringResource(id = CommonStrings.action_not_now),
buttonSize = ButtonSize.Medium,
onClick = onTermsDeclined,
modifier = Modifier.fillMaxWidth(),
) {
Text(text = stringResource(id = CommonStrings.action_not_now))
}
)
}
}

View file

@ -28,7 +28,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.features.createroom.impl.R
import io.element.android.features.createroom.impl.components.UserListView
import io.element.android.features.createroom.impl.userlist.UserListEvents
@ -36,7 +35,6 @@ import io.element.android.features.createroom.impl.userlist.UserListState
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.aliasButtonText
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text
@ -103,16 +101,11 @@ fun AddPeopleViewTopBar(
},
navigationIcon = { BackButton(onClick = onBackPressed) },
actions = {
val textActionResId = if (hasSelectedUsers) CommonStrings.action_next else CommonStrings.action_skip
TextButton(
modifier = Modifier.padding(horizontal = 8.dp),
text = stringResource(id = textActionResId),
onClick = onNextPressed,
) {
val textActionResId = if (hasSelectedUsers) CommonStrings.action_next else CommonStrings.action_skip
Text(
text = stringResource(id = textActionResId),
style = ElementTheme.typography.aliasButtonText,
)
}
)
}
)
}

View file

@ -57,7 +57,6 @@ import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.dialogs.RetryDialog
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.aliasButtonText
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text
@ -195,15 +194,10 @@ fun ConfigureRoomToolbar(
navigationIcon = { BackButton(onClick = onBackPressed) },
actions = {
TextButton(
modifier = Modifier.padding(horizontal = 8.dp),
text = stringResource(CommonStrings.action_create),
enabled = isNextActionEnabled,
onClick = onNextPressed,
) {
Text(
text = stringResource(CommonStrings.action_create),
style = ElementTheme.typography.aliasButtonText,
)
}
)
}
)
}

View file

@ -97,9 +97,11 @@ fun WelcomeView(
}
},
footer = {
Button(modifier = Modifier.fillMaxWidth(), onClick = onContinueClicked) {
Text(text = stringResource(CommonStrings.action_continue))
}
Button(
text = stringResource(CommonStrings.action_continue),
modifier = Modifier.fillMaxWidth(),
onClick = onContinueClicked
)
Spacer(modifier = Modifier.height(32.dp))
}
)

View file

@ -86,7 +86,6 @@ fun InviteListView(
title = stringResource(titleResource),
submitText = stringResource(CommonStrings.action_decline),
cancelText = stringResource(CommonStrings.action_cancel),
emphasizeSubmitButton = true,
onSubmitClicked = { state.eventSink(InviteListEvents.ConfirmDeclineInvite) },
onDismiss = { state.eventSink(InviteListEvents.CancelDeclineInvite) }
)

View file

@ -20,7 +20,6 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
@ -49,8 +48,8 @@ import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAto
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.aliasButtonText
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.theme.ElementTheme
@ -133,23 +132,19 @@ internal fun DefaultInviteSummaryRow(
// CTAs
Row(Modifier.padding(top = 12.dp)) {
OutlinedButton(
content = { Text(stringResource(CommonStrings.action_decline), style = ElementTheme.typography.aliasButtonText) },
text = stringResource(CommonStrings.action_decline),
onClick = onDeclineClicked,
modifier = Modifier
.weight(1f)
.heightIn(max = 36.dp),
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 0.dp),
modifier = Modifier.weight(1f),
buttonSize = ButtonSize.Medium,
)
Spacer(modifier = Modifier.width(12.dp))
Button(
content = { Text(stringResource(CommonStrings.action_accept), style = ElementTheme.typography.aliasButtonText) },
text = stringResource(CommonStrings.action_accept),
onClick = onAcceptClicked,
modifier = Modifier
.weight(1f)
.heightIn(max = 36.dp),
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 0.dp),
modifier = Modifier.weight(1f),
buttonSize = ButtonSize.Medium,
)
}
}

View file

@ -35,7 +35,6 @@ internal fun SlidingSyncNotSupportedDialog(
submitText = stringResource(CommonStrings.action_learn_more),
onSubmitClicked = onLearnMoreClicked,
onCancelClicked = onDismiss,
emphasizeSubmitButton = true,
title = stringResource(CommonStrings.dialog_title_error),
content = stringResource(R.string.screen_change_server_error_no_sliding_sync_message),
)

View file

@ -36,11 +36,10 @@ import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
import io.element.android.libraries.designsystem.components.button.ButtonWithProgress
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.matrix.api.auth.OidcDetails
import io.element.android.libraries.testtags.TestTags
@ -87,7 +86,7 @@ fun ConfirmAccountProviderView(
},
footer = {
ButtonColumnMolecule {
ButtonWithProgress(
Button(
text = stringResource(id = R.string.screen_account_provider_continue),
showProgress = isLoading,
onClick = { eventSink.invoke(ConfirmAccountProviderEvents.Continue) },
@ -97,14 +96,13 @@ fun ConfirmAccountProviderView(
.testTag(TestTags.loginContinue)
)
TextButton(
text = stringResource(id = R.string.screen_account_provider_change),
onClick = onChange,
enabled = true,
modifier = Modifier
.fillMaxWidth()
.testTag(TestTags.loginChangeServer)
) {
Text(text = stringResource(id = R.string.screen_account_provider_change))
}
)
}
}
) {

View file

@ -60,11 +60,11 @@ import io.element.android.features.login.impl.error.loginError
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.button.ButtonWithProgress
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.components.form.textFieldState
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
@ -141,7 +141,7 @@ fun LoginPasswordView(
// Flexible spacing to keep the submit button at the bottom
Spacer(modifier = Modifier.weight(1f))
// Submit
ButtonWithProgress(
Button(
text = stringResource(R.string.screen_login_submit),
showProgress = isLoading,
onClick = ::submit,

View file

@ -29,7 +29,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.material3.ButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.BiasAbsoluteAlignment
@ -52,7 +51,6 @@ import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.components.dialogs.RetryDialog
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.aliasButtonText
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Text
@ -141,18 +139,10 @@ private fun WaitListContent(
.padding(horizontal = 16.dp, vertical = 16.dp)
) {
if (state.loginAction !is Async.Success) {
TextButton(
onClick = onCancelClicked,
colors = ButtonDefaults.buttonColors(
containerColor = Color.White,
contentColor = Color.Black,
disabledContainerColor = Color.White,
disabledContentColor = Color.Black,
),
) {
Text(
ElementTheme(darkTheme = true) {
TextButton(
text = stringResource(CommonStrings.action_cancel),
style = ElementTheme.typography.aliasButtonText,
onClick = onCancelClicked,
)
}
}
@ -208,22 +198,14 @@ private fun WaitListContent(
}
}
if (state.loginAction is Async.Success) {
Button(
onClick = { state.eventSink.invoke(WaitListEvents.Continue) },
colors = ButtonDefaults.buttonColors(
containerColor = Color.White,
contentColor = Color.Black,
disabledContainerColor = Color.White,
disabledContentColor = Color.Black,
),
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(bottom = 8.dp)
) {
Text(
ElementTheme(darkTheme = true) {
Button(
text = stringResource(id = CommonStrings.action_continue),
style = ElementTheme.typography.aliasButtonText,
onClick = { state.eventSink.invoke(WaitListEvents.Continue) },
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(bottom = 8.dp),
)
}
}

View file

@ -220,7 +220,6 @@ private fun ReinviteDialog(state: MessagesState) {
content = stringResource(id = R.string.screen_room_invite_again_alert_message),
cancelText = stringResource(id = CommonStrings.action_cancel),
submitText = stringResource(id = CommonStrings.action_invite),
emphasizeSubmitButton = true,
onSubmitClicked = { state.eventSink(MessagesEvents.InviteDialogDismissed(InviteDialogAction.Invite)) },
onDismiss = { state.eventSink(MessagesEvents.InviteDialogDismissed(InviteDialogAction.Cancel)) }
)

View file

@ -39,7 +39,6 @@ import io.element.android.libraries.designsystem.components.ProgressDialogType
import io.element.android.libraries.designsystem.components.dialogs.RetryDialog
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.ui.strings.CommonStrings
@ -155,12 +154,8 @@ private fun AttachmentsPreviewBottomActions(
ButtonRowMolecule(
modifier = modifier,
) {
TextButton(onClick = onCancelClicked) {
Text(stringResource(id = CommonStrings.action_cancel))
}
TextButton(onClick = onSendClicked) {
Text(stringResource(id = CommonStrings.action_send))
}
TextButton(stringResource(id = CommonStrings.action_cancel), onClick = onCancelClicked)
TextButton(stringResource(id = CommonStrings.action_send), onClick = onSendClicked)
}
}

View file

@ -123,11 +123,10 @@ fun ForwardMessagesView(
},
actions = {
TextButton(
text = stringResource(CommonStrings.action_send),
enabled = state.selectedRooms.isNotEmpty(),
onClick = { state.eventSink(ForwardMessagesEvents.ForwardEvent) }
) {
Text(text = stringResource(CommonStrings.action_send))
}
)
}
)
}

View file

@ -44,11 +44,11 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.button.ButtonWithProgress
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text
@ -150,7 +150,7 @@ fun ReportMessageView(
Spacer(modifier = Modifier.height(24.dp))
ButtonWithProgress(
Button(
text = stringResource(CommonStrings.action_send),
enabled = state.reason.isNotBlank() && !isSending,
showProgress = isSending,

View file

@ -23,10 +23,8 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.QrCode
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.BiasAlignment
@ -42,9 +40,8 @@ import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMo
import io.element.android.libraries.designsystem.atomic.pages.OnBoardingPage
import io.element.android.libraries.designsystem.preview.DayNightPreviews
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.theme.aliasButtonText
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.testtags.TestTags
@ -144,46 +141,27 @@ private fun OnBoardingButtons(
}
if (state.canLoginWithQrCode) {
Button(
text = stringResource(id = R.string.screen_onboarding_sign_in_with_qr_code),
leadingIcon = IconSource.Vector(Icons.Default.QrCode),
onClick = onSignInWithQrCode,
enabled = true,
modifier = Modifier
.fillMaxWidth()
) {
Icon(
imageVector = Icons.Default.QrCode, contentDescription = null,
tint = MaterialTheme.colorScheme.onPrimary
)
Spacer(Modifier.width(14.dp))
Text(
text = stringResource(id = R.string.screen_onboarding_sign_in_with_qr_code),
style = ElementTheme.typography.aliasButtonText,
)
}
modifier = Modifier.fillMaxWidth()
)
}
Button(
text = stringResource(id = signInButtonStringRes),
onClick = onSignIn,
enabled = true,
modifier = Modifier
.fillMaxWidth()
.testTag(TestTags.onBoardingSignIn)
) {
Text(
text = stringResource(id = signInButtonStringRes),
style = ElementTheme.typography.aliasButtonText,
)
}
)
if (state.canCreateAccount) {
OutlinedButton(
text = stringResource(id = R.string.screen_onboarding_sign_up),
onClick = onCreateAccount,
enabled = true,
modifier = Modifier
.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.screen_onboarding_sign_up),
style = ElementTheme.typography.aliasButtonText,
)
}
)
}
Spacer(modifier = Modifier.height(16.dp))
}

View file

@ -48,8 +48,8 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.debugPlaceholderBackground
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.LogCompositions
@ -149,14 +149,13 @@ fun BugReportView(
// Submit
PreferenceRow {
Button(
text = stringResource(id = CommonStrings.action_send),
onClick = { eventSink(BugReportEvents.SendBugReport) },
enabled = state.submitEnabled,
modifier = Modifier
.fillMaxWidth()
.padding(top = 24.dp, bottom = 16.dp)
) {
Text(text = stringResource(id = CommonStrings.action_send))
}
)
}
}

View file

@ -68,7 +68,6 @@ import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.aliasButtonText
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Scaffold
@ -115,17 +114,13 @@ fun RoomDetailsEditView(
navigationIcon = { BackButton(onClick = onBackPressed) },
actions = {
TextButton(
text = stringResource(CommonStrings.action_save),
enabled = state.saveButtonEnabled,
onClick = {
focusManager.clearFocus()
state.eventSink(RoomDetailsEditEvents.Save)
},
) {
Text(
text = stringResource(CommonStrings.action_save),
style = ElementTheme.typography.aliasButtonText,
)
}
)
}
)
},

View file

@ -128,10 +128,8 @@ fun RoomInviteMembersTopBar(
navigationIcon = { BackButton(onClick = onBackPressed) },
actions = {
TextButton(
text = stringResource(CommonStrings.action_send),
onClick = onSendPressed,
content = {
Text(stringResource(CommonStrings.action_send))
},
enabled = canSend,
)
}

View file

@ -45,7 +45,6 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.aliasButtonText
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Scaffold
@ -212,14 +211,9 @@ private fun RoomMemberListTopBar(
actions = {
if (canInvite) {
TextButton(
modifier = Modifier.padding(horizontal = 8.dp),
text = stringResource(CommonStrings.action_invite),
onClick = onInvitePressed,
) {
Text(
text = stringResource(CommonStrings.action_invite),
style = ElementTheme.typography.aliasButtonText,
)
}
)
}
}
)

View file

@ -19,7 +19,6 @@ package io.element.android.features.roomlist.impl.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
@ -37,7 +36,7 @@ import androidx.compose.ui.unit.dp
import io.element.android.features.roomlist.impl.R
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.aliasButtonText
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Surface
@ -83,15 +82,11 @@ internal fun RequestVerificationHeader(
)
Spacer(modifier = Modifier.height(12.dp))
Button(
text = stringResource(CommonStrings.action_continue),
buttonSize = ButtonSize.Medium,
modifier = Modifier.fillMaxWidth(),
contentPadding = PaddingValues(horizontal = 20.dp, vertical = 7.dp),
onClick = onVerifyClicked,
) {
Text(
stringResource(CommonStrings.action_continue),
style = ElementTheme.typography.aliasButtonText
)
}
)
}
}
}

View file

@ -27,7 +27,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
@ -44,15 +43,16 @@ import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
import io.element.android.libraries.designsystem.components.button.ButtonWithProgress
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.aliasButtonText
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.matrix.api.verification.VerificationEmoji
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.coroutines.sync.Mutex
import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep as FlowStep
@Composable
@ -75,6 +75,7 @@ fun VerifySelfSessionView(
val buttonsVisible by remember(verificationFlowStep) {
derivedStateOf { verificationFlowStep != FlowStep.AwaitingOtherDeviceResponse && verificationFlowStep != FlowStep.Completed }
}
Mutex()
HeaderFooterPage(
modifier = modifier,
header = {
@ -219,23 +220,21 @@ internal fun BottomMenu(screenState: VerifySelfSessionState, goBack: () -> Unit)
ButtonColumnMolecule(
modifier = Modifier.padding(bottom = 20.dp)
) {
ButtonWithProgress(
text = positiveButtonTitle?.let { stringResource(it) },
showProgress = isVerifying,
modifier = Modifier.fillMaxWidth(),
onClick = { positiveButtonEvent?.let { eventSink(it) } }
)
if (positiveButtonTitle != null) {
Button(
text = stringResource(positiveButtonTitle),
showProgress = isVerifying,
modifier = Modifier.fillMaxWidth(),
onClick = { positiveButtonEvent?.let { eventSink(it) } }
)
}
if (negativeButtonTitle != null) {
TextButton(
text = stringResource(negativeButtonTitle),
modifier = Modifier.fillMaxWidth(),
onClick = negativeButtonCallback,
enabled = negativeButtonEnabled,
) {
Text(
text = stringResource(negativeButtonTitle),
style = ElementTheme.typography.aliasButtonText,
)
}
)
}
}
}

View file

@ -28,7 +28,7 @@ import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
import io.element.android.libraries.designsystem.theme.components.TextButton
@Composable
@ -59,11 +59,8 @@ internal fun ButtonColumnMoleculeDarkPreview() =
@Composable
private fun ContentToPreview() {
ButtonColumnMolecule {
Button(onClick = {}, modifier = Modifier.fillMaxWidth()) {
Text(text = "Button")
}
TextButton(onClick = {}, modifier = Modifier.fillMaxWidth()) {
Text(text = "TextButton")
}
Button(text = "Button", onClick = {}, modifier = Modifier.fillMaxWidth())
OutlinedButton(text = "OutlinedButton", onClick = {}, modifier = Modifier.fillMaxWidth())
TextButton(text = "TextButton", onClick = {}, modifier = Modifier.fillMaxWidth())
}
}

View file

@ -25,7 +25,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
@Composable
@ -54,11 +53,7 @@ internal fun ButtonRowMoleculeDarkPreview() =
@Composable
private fun ContentToPreview() {
ButtonRowMolecule {
TextButton(onClick = { }) {
Text("Button 1")
}
TextButton(onClick = { }) {
Text("Button 2")
}
TextButton(text = "Button 1", onClick = {})
TextButton(text = "Button 2", onClick = {})
}
}

View file

@ -129,9 +129,10 @@ private fun ProgressDialogContent(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.BottomEnd
) {
TextButton(onClick = onCancelClicked) {
Text(stringResource(id = CommonStrings.action_cancel))
}
TextButton(
text = stringResource(id = CommonStrings.action_cancel),
onClick = onCancelClicked,
)
}
}
}

View file

@ -48,9 +48,10 @@ fun AsyncFailure(
Text(text = throwable.message ?: stringResource(id = CommonStrings.error_unknown))
if (onRetry != null) {
Spacer(modifier = Modifier.height(24.dp))
Button(onClick = onRetry) {
Text(text = stringResource(id = CommonStrings.action_retry))
}
Button(
text = stringResource(id = CommonStrings.action_retry),
onClick = onRetry
)
}
}
}

View file

@ -1,107 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.components.button
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.progressSemantics
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonElevation
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.theme.aliasButtonText
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.ElementButtonDefaults
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.theme.ElementTheme
/**
* A component that will display a button with an indeterminate circular progressbar.
* When [showProgress] is true:
* - A circular progressbar is displayed.
* - [text] is replaced by [progressText], if defined.
* - [onClick] gets disabled.
*/
@Composable
fun ButtonWithProgress(
text: String?,
onClick: () -> Unit,
modifier: Modifier = Modifier,
showProgress: Boolean = false,
progressText: String? = text,
enabled: Boolean = true,
shape: Shape = ElementButtonDefaults.shape,
colors: ButtonColors = ElementButtonDefaults.buttonColors(),
elevation: ButtonElevation? = ElementButtonDefaults.buttonElevation(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ElementButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) {
Button(
onClick = {
if (!showProgress) {
onClick()
}
},
modifier = modifier,
enabled = enabled,
shape = shape,
colors = colors,
elevation = elevation,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
) {
if (showProgress) {
CircularProgressIndicator(
modifier = Modifier
.progressSemantics()
.size(18.dp),
color = MaterialTheme.colorScheme.onPrimary,
strokeWidth = 2.dp,
)
if (progressText != null) {
Spacer(Modifier.width(10.dp))
Text(progressText, style = ElementTheme.typography.aliasButtonText)
}
} else if (text != null) {
Text(text, style = ElementTheme.typography.aliasButtonText)
}
}
}
@Preview(group = PreviewGroup.Buttons)
@Composable
internal fun ButtonWithProgressPreview() = ElementThemedPreview {
ButtonWithProgress(
text = "Button with progress",
onClick = {},
showProgress = true,
)
}

View file

@ -27,7 +27,6 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Surface
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
@ -38,7 +37,10 @@ import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.theme.ElementTheme
import kotlin.math.max
@ -53,7 +55,6 @@ internal fun SimpleAlertDialogContent(
onSubmitClicked: () -> Unit = {},
thirdButtonText: String? = null,
onThirdButtonClicked: () -> Unit = {},
emphasizeSubmitButton: Boolean = false,
shape: Shape = AlertDialogDefaults.shape,
containerColor: Color = AlertDialogDefaults.containerColor,
iconContentColor: Color = AlertDialogDefaults.iconContentColor,
@ -71,30 +72,23 @@ internal fun SimpleAlertDialogContent(
if (thirdButtonText != null) {
// If there is a 3rd item it should be at the end of the dialog
// Having this 3rd action is discouraged, see https://m3.material.io/components/dialogs/guidelines#e13b68f5-e367-4275-ad6f-c552ee8e358f
TextButton(onClick = onThirdButtonClicked) {
Text(
text = thirdButtonText,
style = ElementTheme.typography.fontBodyMdRegular,
)
}
}
TextButton(onClick = onCancelClicked) {
Text(
text = cancelText,
style = ElementTheme.typography.fontBodyMdRegular,
TextButton(
text = thirdButtonText,
buttonSize = ButtonSize.Medium,
onClick = onThirdButtonClicked,
)
}
TextButton(
text = cancelText,
buttonSize = ButtonSize.Medium,
onClick = onCancelClicked,
)
if (submitText != null) {
TextButton(onClick = onSubmitClicked) {
Text(
text = submitText,
style = if (emphasizeSubmitButton) {
ElementTheme.typography.fontBodyMdMedium
} else {
ElementTheme.typography.fontBodyMdRegular
}
)
}
Button(
text = submitText,
buttonSize = ButtonSize.Medium,
onClick = onSubmitClicked,
)
}
}
},

View file

@ -26,11 +26,9 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.Dp
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.utils.BooleanProvider
import io.element.android.libraries.ui.strings.CommonStrings
@OptIn(ExperimentalMaterial3Api::class)
@ -44,7 +42,6 @@ fun ConfirmationDialog(
submitText: String = stringResource(id = CommonStrings.action_ok),
cancelText: String = stringResource(id = CommonStrings.action_cancel),
thirdButtonText: String? = null,
emphasizeSubmitButton: Boolean = false,
onCancelClicked: () -> Unit = onDismiss,
onThirdButtonClicked: () -> Unit = {},
shape: Shape = AlertDialogDefaults.shape,
@ -71,7 +68,6 @@ fun ConfirmationDialog(
titleContentColor = titleContentColor,
textContentColor = textContentColor,
tonalElevation = tonalElevation,
emphasizeSubmitButton = emphasizeSubmitButton,
)
}
}
@ -87,7 +83,6 @@ private fun ConfirmationDialogContent(
title: String? = null,
thirdButtonText: String? = null,
onThirdButtonClicked: () -> Unit = {},
emphasizeSubmitButton: Boolean = false,
shape: Shape = AlertDialogDefaults.shape,
containerColor: Color = AlertDialogDefaults.containerColor,
iconContentColor: Color = AlertDialogDefaults.iconContentColor,
@ -106,7 +101,6 @@ private fun ConfirmationDialogContent(
onCancelClicked = onCancelClicked,
thirdButtonText = thirdButtonText,
onThirdButtonClicked = onThirdButtonClicked,
emphasizeSubmitButton = emphasizeSubmitButton,
shape = shape,
containerColor = containerColor,
iconContentColor = iconContentColor,
@ -119,7 +113,7 @@ private fun ConfirmationDialogContent(
@Preview(group = PreviewGroup.Dialogs)
@Composable
internal fun ConfirmationDialogPreview(@PreviewParameter(BooleanProvider::class) emphasizeSubmitButton: Boolean) =
internal fun ConfirmationDialogPreview() =
ElementThemedPreview {
DialogPreview {
ConfirmationDialogContent(
@ -130,7 +124,6 @@ internal fun ConfirmationDialogPreview(@PreviewParameter(BooleanProvider::class)
thirdButtonText = "Disable",
onSubmitClicked = {},
onCancelClicked = {},
emphasizeSubmitButton = emphasizeSubmitButton,
)
}
}

View file

@ -18,7 +18,7 @@ package io.element.android.libraries.designsystem.components.dialogs
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.AlertDialogDefaults
import androidx.compose.material3.TextButton
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -28,10 +28,9 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.ui.strings.CommonStrings
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RetryDialog(
content: String,
@ -48,44 +47,22 @@ fun RetryDialog(
textContentColor: Color = AlertDialogDefaults.textContentColor,
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
) {
AlertDialog(
modifier = modifier,
onDismissRequest = onDismiss,
title = {
Text(
text = title,
style = ElementTheme.typography.fontHeadingSmRegular,
)
},
text = {
Text(
text = content,
style = ElementTheme.typography.fontBodyMdRegular,
)
},
confirmButton = {
TextButton(onClick = onRetry) {
Text(
text = retryText,
style = ElementTheme.typography.fontBodyMdRegular,
)
}
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text(
text = dismissText,
style = ElementTheme.typography.fontBodyMdRegular,
)
}
},
shape = shape,
containerColor = containerColor,
iconContentColor = iconContentColor,
titleContentColor = titleContentColor,
textContentColor = textContentColor,
tonalElevation = tonalElevation,
)
AlertDialog(modifier = modifier, onDismissRequest = onDismiss) {
RetryDialogContent(
title = title,
content = content,
retryText = retryText,
dismissText = dismissText,
onRetry = onRetry,
onDismiss = onDismiss,
shape = shape,
containerColor = containerColor,
iconContentColor = iconContentColor,
titleContentColor = titleContentColor,
textContentColor = textContentColor,
tonalElevation = tonalElevation,
)
}
}
@Composable

View file

@ -24,8 +24,8 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
import io.element.android.libraries.designsystem.theme.components.Text
/**
* Debug tool to add a vertical and a horizontal ruler on top of the content.
@ -76,8 +76,10 @@ internal fun WithRulerDarkPreview() =
@Composable
private fun ContentToPreview() {
WithRulers(xRulersOffset = 20.dp, yRulersOffset = 15.dp) {
OutlinedButton(onClick = {}) {
Text(text = "A Button with rulers on it!")
}
OutlinedButton(
text = "A Button with rulers on it!",
buttonSize = ButtonSize.Medium,
onClick = {},
)
}
}

View file

@ -18,68 +18,323 @@ package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ButtonColors
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.progressSemantics
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Share
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ButtonElevation
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.theme.ElementTheme
// Designs: https://www.figma.com/file/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?type=design&mode=design&t=U03tOFZz5FSLVUMa-1
@Composable
fun Button(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = ElementButtonDefaults.shape,
colors: ButtonColors = ElementButtonDefaults.buttonColors(),
elevation: ButtonElevation? = ElementButtonDefaults.buttonElevation(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ElementButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
buttonSize: ButtonSize = ButtonSize.Large,
showProgress: Boolean = false,
leadingIcon: IconSource? = null,
) = ButtonInternal(text, onClick, ButtonStyle.Filled, modifier, enabled, buttonSize, showProgress, leadingIcon)
@Composable
fun OutlinedButton(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
buttonSize: ButtonSize = ButtonSize.Large,
showProgress: Boolean = false,
leadingIcon: IconSource? = null,
) = ButtonInternal(text, onClick, ButtonStyle.Outlined, modifier, enabled, buttonSize, showProgress, leadingIcon)
@Composable
fun TextButton(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
buttonSize: ButtonSize = ButtonSize.Large,
showProgress: Boolean = false,
leadingIcon: IconSource? = null,
) = ButtonInternal(text, onClick, ButtonStyle.Text, modifier, enabled, buttonSize, showProgress, leadingIcon)
@Composable
private fun ButtonInternal(
text: String,
onClick: () -> Unit,
style: ButtonStyle,
modifier: Modifier = Modifier,
enabled: Boolean = true,
size: ButtonSize = ButtonSize.Large,
showProgress: Boolean = false,
leadingIcon: IconSource? = null,
) {
val minHeight = when (size) {
ButtonSize.Medium -> 40.dp
ButtonSize.Large -> 48.dp
}
val paddingValues = when (size) {
ButtonSize.Medium -> {
when (style) {
ButtonStyle.Text -> PaddingValues(horizontal = 12.dp, vertical = 10.dp)
else -> PaddingValues(horizontal = 16.dp, vertical = 10.dp)
}
}
ButtonSize.Large -> {
when (style) {
ButtonStyle.Text -> PaddingValues(horizontal = 16.dp, vertical = 13.dp)
else -> PaddingValues(horizontal = 24.dp, vertical = 13.dp)
}
}
}
val shape = when (style) {
ButtonStyle.Filled, ButtonStyle.Outlined -> RoundedCornerShape(percent = 50)
ButtonStyle.Text -> RectangleShape
}
val colors = when (style) {
ButtonStyle.Filled -> ButtonDefaults.buttonColors(
containerColor = ElementTheme.materialColors.primary,
contentColor = ElementTheme.materialColors.onPrimary,
disabledContainerColor = ElementTheme.colors.bgActionPrimaryDisabled,
disabledContentColor = ElementTheme.colors.textOnSolidPrimary
)
ButtonStyle.Outlined, ButtonStyle.Text -> ButtonDefaults.buttonColors(
containerColor = Color.Transparent,
contentColor = ElementTheme.materialColors.primary,
disabledContainerColor = Color.Transparent,
disabledContentColor = ElementTheme.colors.textDisabled,
)
}
val border = when (style) {
ButtonStyle.Filled, ButtonStyle.Text -> null
ButtonStyle.Outlined -> BorderStroke(
width = 1.dp,
color = ElementTheme.colors.borderInteractiveSecondary
)
}
val textStyle = when (size) {
ButtonSize.Medium -> MaterialTheme.typography.labelLarge
ButtonSize.Large -> ElementTheme.typography.fontBodyLgMedium
}
androidx.compose.material3.Button(
onClick = onClick,
modifier = modifier,
onClick = {
if (!showProgress) {
onClick()
}
},
modifier = modifier.heightIn(min = minHeight),
enabled = enabled,
shape = shape,
colors = colors,
elevation = elevation,
elevation = null,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content,
)
contentPadding = paddingValues,
interactionSource = remember { MutableInteractionSource() },
) {
when {
showProgress -> {
CircularProgressIndicator(
modifier = Modifier
.progressSemantics()
.size(20.dp),
color = LocalContentColor.current,
strokeWidth = 2.dp,
)
}
leadingIcon != null -> {
androidx.compose.material.Icon(
painter = leadingIcon.getPainter(),
contentDescription = null,
tint = LocalContentColor.current,
modifier = Modifier.size(20.dp),
)
}
else -> Unit
}
Text(
text = text,
style = textStyle,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(horizontal = 8.dp),
)
}
}
object ElementButtonDefaults {
val ContentPadding = PaddingValues(horizontal = 24.dp, vertical = 14.dp)
val shape: Shape @Composable get() = ButtonDefaults.shape
@Composable
fun buttonElevation(): ButtonElevation = ButtonDefaults.buttonElevation()
sealed interface IconSource {
data class Resource(val id: Int) : IconSource
data class Vector(val vector: ImageVector) : IconSource
@Composable
fun buttonColors(): ButtonColors = ButtonDefaults.buttonColors()
fun getPainter(): Painter = when (this) {
is Resource -> painterResource(id)
is Vector -> rememberVectorPainter(image = vector)
}
}
enum class ButtonSize {
Medium, Large
}
private enum class ButtonStyle {
Filled, Outlined, Text
}
@Preview(group = PreviewGroup.Buttons)
@Composable
internal fun ButtonPreview() = ElementThemedPreview {
Column {
Button(onClick = {}, enabled = true) {
Text(text = "Click me! - Enabled")
}
Button(onClick = {}, enabled = false) {
Text(text = "Click me! - Disabled")
internal fun FilledButtonMediumPreview() {
ButtonCombinationPreview(
buttonStyle = ButtonStyle.Filled,
buttonSize = ButtonSize.Medium,
)
}
@Preview(group = PreviewGroup.Buttons)
@Composable
internal fun FilledButtonLargePreview() {
ButtonCombinationPreview(
buttonStyle = ButtonStyle.Filled,
buttonSize = ButtonSize.Large,
)
}
@Preview(group = PreviewGroup.Buttons)
@Composable
internal fun OutlinedButtonMediumPreview() {
ButtonCombinationPreview(
buttonStyle = ButtonStyle.Outlined,
buttonSize = ButtonSize.Medium,
)
}
@Preview(group = PreviewGroup.Buttons)
@Composable
internal fun OutlinedButtonLargePreview() {
ButtonCombinationPreview(
buttonStyle = ButtonStyle.Outlined,
buttonSize = ButtonSize.Large,
)
}
@Preview(group = PreviewGroup.Buttons)
@Composable
internal fun TextButtonMediumPreview() {
ButtonCombinationPreview(
buttonStyle = ButtonStyle.Text,
buttonSize = ButtonSize.Medium,
)
}
@Preview(group = PreviewGroup.Buttons)
@Composable
internal fun TextButtonLargePreview() {
ButtonCombinationPreview(
buttonStyle = ButtonStyle.Text,
buttonSize = ButtonSize.Large,
)
}
@Composable
private fun ButtonCombinationPreview(
buttonStyle: ButtonStyle,
buttonSize: ButtonSize,
modifier: Modifier = Modifier,
) {
ElementThemedPreview {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier
.padding(16.dp)
.width(IntrinsicSize.Max),
) {
// Normal
ButtonRowPreview(
modifier = Modifier.then(modifier),
buttonStyle = buttonStyle,
buttonSize = buttonSize,
)
// With icon
ButtonRowPreview(
modifier = Modifier.then(modifier),
leadingIcon = IconSource.Vector(Icons.Outlined.Share),
buttonStyle = buttonStyle,
buttonSize = buttonSize,
)
// With progress
ButtonRowPreview(
modifier = Modifier.then(modifier),
showProgress = true,
buttonStyle = buttonStyle,
buttonSize = buttonSize,
)
}
}
}
@Composable
private fun ButtonRowPreview(
buttonStyle: ButtonStyle,
buttonSize: ButtonSize,
modifier: Modifier = Modifier,
leadingIcon: IconSource? = null,
showProgress: Boolean = false,
) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)) {
ButtonInternal(
text = "A button",
showProgress = showProgress,
onClick = {},
style = buttonStyle,
size = buttonSize,
leadingIcon = leadingIcon,
modifier = Modifier.then(modifier),
)
ButtonInternal(
text = "A button",
showProgress = showProgress,
enabled = false,
onClick = {},
style = buttonStyle,
size = buttonSize,
leadingIcon = leadingIcon,
modifier = Modifier.then(modifier),
)
}
}

View file

@ -1,91 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ButtonElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
@Composable
fun OutlinedButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = ElementOutlinedButtonDefaults.shape,
colors: ButtonColors = ElementOutlinedButtonDefaults.buttonColors(),
elevation: ButtonElevation? = ElementOutlinedButtonDefaults.buttonElevation(),
border: BorderStroke? = ElementOutlinedButtonDefaults.border,
contentPadding: PaddingValues = ElementOutlinedButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
) {
androidx.compose.material3.Button(
onClick = onClick,
modifier = modifier,
enabled = enabled,
shape = shape,
colors = colors,
elevation = elevation,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content,
)
}
object ElementOutlinedButtonDefaults {
val ContentPadding = PaddingValues(horizontal = 24.dp, vertical = 14.dp)
val shape: Shape @Composable get() = ButtonDefaults.outlinedShape
val border: BorderStroke @Composable get() = ButtonDefaults.outlinedButtonBorder
@Composable
fun buttonElevation(): ButtonElevation = ButtonDefaults.buttonElevation()
@Composable
fun buttonColors(): ButtonColors = ButtonDefaults.outlinedButtonColors()
}
@Preview(group = PreviewGroup.Buttons)
@Composable
internal fun OutlinedButtonsPreview() = ElementThemedPreview { ContentToPreview() }
@Composable
private fun ContentToPreview() {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedButton(onClick = {}, enabled = true) {
Text(text = "Click me! - Enabled")
}
OutlinedButton(onClick = {}, enabled = false) {
Text(text = "Click me! - Disabled")
}
}
}

View file

@ -1,76 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ButtonElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
@Composable
fun TextButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.textShape,
colors: ButtonColors = ButtonDefaults.textButtonColors(),
elevation: ButtonElevation? = null,
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.TextButtonContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
) {
androidx.compose.material3.TextButton(
onClick = onClick,
modifier = modifier,
enabled = enabled,
shape = shape,
colors = colors,
elevation = elevation,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content,
)
}
@Preview(group = PreviewGroup.Buttons)
@Composable
internal fun TextButtonPreview() = ElementThemedPreview { ContentToPreview() }
@Composable
private fun ContentToPreview() {
Column {
TextButton(onClick = {}, enabled = true) {
Text(text = "Click me! - Enabled")
}
TextButton(onClick = {}, enabled = false) {
Text(text = "Click me! - Disabled")
}
}
}

View file

@ -32,16 +32,13 @@ import io.element.android.libraries.designsystem.theme.components.DropdownMenu
import io.element.android.libraries.designsystem.theme.components.DropdownMenuItem
import io.element.android.libraries.designsystem.theme.components.DropdownMenuItemText
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
@Preview(group = PreviewGroup.Menus)
@Composable
internal fun MenuPreview() {
ElementThemedPreview {
var isExpanded by remember { mutableStateOf(false) }
Button(onClick = { isExpanded = !isExpanded }) {
Text("Toggle")
}
Button(text = "Toggle", onClick = { isExpanded = !isExpanded })
DropdownMenu(expanded = isExpanded, onDismissRequest = { isExpanded = false }) {
for (i in 0..5) {
val leadingIcon: @Composable (() -> Unit)? = if (i in 2..3) {

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c51726746993ad3ed0f6da9fe49a02b87ec518495e04f6cdb28ab4454dc72938
size 25457
oid sha256:46791d70473aca73286b0e4474bd0b649c918005516e5bc9b6a3bbdb9a8f5fd2
size 26694

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:14ffd433679cbadf1bb325257786a834fce3e362d2ed763c1823b0c958c0f38a
size 27496
oid sha256:bcbe69c4bdba925ca2e5926dfb916d9f83e5c17717b8fc6d3665f87ceb32d23d
size 28738

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:85d3ea85f270fae4db7e14ab9c2c19a6c4f3a68e1c2112010471cb69cdb71b2b
size 22071
oid sha256:67a4bb7f73aeb7e8f014cf33147c08b6b95fc2f15c8b843c9d83c9bf24fa150a
size 22026

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fd79483dea8ce19284069511ec96dfc68704a9ff2f1a33be312bbcdb387123c6
size 26655
oid sha256:4417dad9a43b1759acb558213bb87538535a7e9a2b87c7292b4531d77551d7c8
size 27993

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:931423fea194fb1bede5cb3d73083fb65335716ca088fbda707f4f4727eae4dd
size 28757
oid sha256:92376ec0846541af886963486f25a1b6de3db6d318ca5088098b322d24255570
size 30079

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bfa6e3d8698a2327d6e3cc14318856f221355581e6c661b92d2e215daf8f30cd
size 22879
oid sha256:c46a163c5b47489334a8a9475fc2a39e4682081023e21a326f2cbc2e88f035e0
size 22852

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:434f7619fb6bd337ede775fc343acc05950907987523acbd0f578624e5d26857
size 49246
oid sha256:5fd66b90f0566317a48565be56e75496a7b156fc96354ea61a0cc0a7f036625a
size 49329

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:93036a30e1af96805c20ea5d65b6d3eb40d2ee11f8f3420436e936dd5b4ca38b
size 50201
oid sha256:5b6dc784e88a7c9ef9d5812ee474e8cbc5cafc55dfd21adeb15d3ace99a41db0
size 50340

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:92fda75e246b46ab786da2f54f920bf96959618ac20cece5f6ca754f7fcf6914
size 14161
oid sha256:ae8be2032172fbda58c917e00401f59a4c6363dee0bb8304f6a0bba18abbb67d
size 14135

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a2a005b84bbf1be15028d36e153e79eb5acbe41e65e3f274a6d78b22be95efb5
size 28509
oid sha256:427314c0d0749e03b8639b6b0e15f294a8090b392f297e6a5a1714b77d3b174c
size 28520

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6bb2d3d6e83f5b0ca17809c415e636bf5dbfa846259e8fabd6c3afae37d7d1f9
size 15231
oid sha256:af55dec154a30df77baa8f2e8ebfe2787cc99ac0d717274e319ea89c3b46d6eb
size 15206

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d3f7631f15054ac55688f76805a6f1924e79058881957b67284865b6508886cc
size 29249
oid sha256:c69b2b87544bccb46590aafcdd638e8fa4c81c6c3ca53052cede42e1926301f3
size 29275

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3cb08dc14db764d1bc432dc58374cad50da83c5e30e7e48077b6f400aa7a3c9b
size 57811
oid sha256:e5bdcb1947e4f2c40d48ce69d2d7218f3aed7a96706a36f62eb6ee8cf18123f1
size 58121

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d0a9c923401980b00b756159f9c77f153892b79cc2b806150734b6bd8f67fe4d
size 83675
oid sha256:8ee9b90232d573c09c824cbf63673cfca3e0a6823cd86914b4ea798e13b3d860
size 83688

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4e543f94df5f2de717e7e870fe043ecf72b29aeaca23d33b9b16af76e2cc1636
size 61222
oid sha256:5411b9f81d37d7834eb7c50c59cb2bc1686f5f706fe96952147515ef1c041a62
size 61494

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1b94a9fdcf1f2c62fa2a0f574210b85de96ba068ba17ba562af79f21d7a38f8f
size 86854
oid sha256:1395d6bfe4258c13cbc76711505bc58666064777f0219d8d89203ebb313c3bb0
size 86882

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5312bd01a41dc0d1b022b6ce7258435d1cd9de75bd4231ce7f86ed6f84de2e4b
size 26306
oid sha256:cb391a409ce4174127ad8ad4961975092f92a24224381a0c8c5e9940eb555235
size 27629

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1b9b88deb5557da8b4670231ee41aa737543244d61abfd399d7de0f6d4496dde
size 27439
oid sha256:97ffdf54dd223794d0ccc013b773b381d8e047f6854a927bf5b20b67b4c75015
size 28863

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1387a1337da70f8e87474aef106110f0dfb55e59f340e0906390e509da1dd0b4
size 299376
oid sha256:6d2eab27a1132893542b240399a4003b4049b72903a822077f69dd9dafd26f71
size 299106

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cdf0215f1ba1f6a89a6204e19b3df7dec1e64d7fd71bdf8c706e1969e11e702d
size 404366
oid sha256:fbad2f74e329a424e75ef96cb0c427a7baba044f3267346756324c39ebd6add6
size 404196

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:07e722c2936e1332168319059d5b4a553b1fc7f03da8aff40b005a05b203632d
size 28679
oid sha256:7ee847a64a963e1536e8fa118516cb58dd3ef450decbaafda3cae067bd44e8c4
size 28447

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:eab30f7ec6ad8e289f4987d23f373ca8f96220a5d0762d46723058bca53d0a41
size 33580
oid sha256:0aa12e1e306c98dc03ce08acf178624c17622546ab32d93571d0e6f73530e95a
size 33101

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6a344ef3f77b759e1d43733f85fc7ee9bee98d6eb3980ce13c435bb33c0703f0
size 33720
oid sha256:ad431cfafb873a27010ef2f5191efbbb7a7d43518f3fd72cc1d93bde3fbc5db4
size 33246

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6e5874a0e224636c5ad13f4022e8f2ef3dff97206a5551734de560fbc40c562a
size 14447
oid sha256:f8edf269361969e35486f0bfdfcfe99c69c82adbeea87c5ccc7af244a68dfdbe
size 14022

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1e526f418f5c8d1d0c51509808e22548ce3c295752e7a1cf28cfe394fccc01f4
size 28834
oid sha256:36dbf0c8406baed1c3125173b0113e071e28e8370b7fe6ec7887687e59e98035
size 28612

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:97639d0985e0303e3a58120fbb7a2bba67b4279d198140a9f4cf6b19aa74bed0
size 29199
oid sha256:d7c5c16830d017da9d76cdf9469fe7e2d7e718b5d1cb2408e15fdcf773d707d6
size 29132

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f0372c5389850f853652ad40ad54069e456aa33e13335e733d779a8d4d384049
size 35297
oid sha256:791944236c8027c25bad58e2a6db65a72d310fdc54095ed7475701a9fad689c7
size 35006

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:62f57ee9fc205539ede541baf8e4b887ef7776675c4760acd5b27545cd021df8
size 35420
oid sha256:adfadfbbcd6920bca70c435cbb68c83e18cfd9e15eac4545fa5f1e404b258255
size 35121

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ea79f0de34ba0613fea7ba98c65f5ff925a336ddf2d6734ea77b1a2d559527f0
size 14416
oid sha256:1694a5589d39a7b4d7fcc823a0d6b2c86e9bb9c759ace8e5790df85ebc7ea3af
size 14167

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4b13ebc73e257d5f588f9e74d0a35bc9af951faece57556636378914786429e3
size 29503
oid sha256:5575ca96bb0b925109b5aad2207c304a0d1d54e8eeace250369e23982f23ec09
size 29424

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5fcd5bd88a1aea468c8f5e08a3e07a323bd0e76f8db913611929c80184c2f68c
size 53541
oid sha256:014ace4752ba1f47272fd5320aa567a3b825c159548b36a1cdea34eb933cf0f0
size 52332

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d3a5f5dcad110d0fe9cc1e81537319feac59c7d25084d9b77ed22c44969a7237
size 48499
oid sha256:7fa8aed2bf9fd7b52feeecee0b6a754f5d4d6ac7874812582af6f62d57e8386d
size 50351

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ee4f54670538988698e947dd42d6d3bc585f743684e83202d48f8d02d1bdf1f8
size 49214
oid sha256:55f3f0dad422de2490c3685530684ef4b94e03600a9a6f477a7841f64caacd50
size 51093

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:442ff73662328311d0f8d9ef0000bf2be3b6141810b26f864847217081900411
size 41007
oid sha256:a01b90afcca784a2ebd08e7645cc6caf296c03c37ca6e2fa295ce8ca8b907d8b
size 41481

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:442ff73662328311d0f8d9ef0000bf2be3b6141810b26f864847217081900411
size 41007
oid sha256:a01b90afcca784a2ebd08e7645cc6caf296c03c37ca6e2fa295ce8ca8b907d8b
size 41481

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f20e6a88d40320286d73dfa346a02783a00b1fb4a10c804c2f147e2f909c5a2a
size 56083
oid sha256:0219335bf2f3be0a4a785d7ca2e05700278401aa090d5972a76ce077cfbe5be6
size 55406

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c25bf522377a036e8faae35e8afe458d82cf3c761e2df237a1a4d5785f44e188
size 50202
oid sha256:b877305884353e5cf2b95cdbaad90a60bec8508b98ca702ea63272dde221667c
size 51997

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:904a991dd0b753af68f0ab626d1f236dc9ea273a35f100475cadad8f4332d25d
size 50896
oid sha256:9b8a1fbf13bdc64c63ddffab55137c7c313630e11bd6c20da07593d8cc5460cc
size 52593

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:98ff0c7db1cd224a6d9897b1daf49f57fc659b25e60a9d670e8b1c66811d4fed
size 42505
oid sha256:c0d554cf60b5c6c6a58e1793c1155605c4c17606a0dfc92c8f4e9d39bab5bc56
size 43014

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:98ff0c7db1cd224a6d9897b1daf49f57fc659b25e60a9d670e8b1c66811d4fed
size 42505
oid sha256:c0d554cf60b5c6c6a58e1793c1155605c4c17606a0dfc92c8f4e9d39bab5bc56
size 43014

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:42d22676a81b8c1f313f2f21814b787c54fa52f8b344207b509fbb798f2f58a1
size 20075
oid sha256:129144d77e162fb3263884191e240a3cb3b259501f69d0b346a73bd5273b9f66
size 21290

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:34645175d5acb2915d04b9306d648a287cae769bffcae7ecaffd293d43580683
size 29023
oid sha256:20191d257eb9db133382d8ca3ed15980bf4950a3583947a4145e1393509a70ac
size 30395

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:56f203dce2ed8ff23a75eb66bcb116fb4af61b63b1ad095ecebf6d97ba557a2c
size 31392
oid sha256:d9790e38cc340cbaf2db8fc72578f7f3ad4760b132acb3bee1e82c9cb41ccefd
size 32710

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1d23fb856aa3402cebf5c976fe32f0475f2f58b37a9ac9d028b0164dae4de397
size 13357
oid sha256:c57da4d726af9971ec746d01fb2791ce0ffbb7e8a643ea49fcdccf2c60c60579
size 13350

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e748443031dd55fdf60f13debd2484f8169b7eb23980786ad73898004c7bcbfe
size 19615
oid sha256:1287b345aec7c250f9f47722d3dc3ab6979f0311ee35916d013545f1675aad1d
size 20912

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5c2419ccf59c98899071e705b63feb83e8976acca53ccb8f375551aa056f9950
size 29204
oid sha256:f3401af59f4fcdc85914f00080029114d56dd2d5808ee5ef0cd2f36e9e3977b6
size 30649

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:598f0a995896c32b1755951779f3784dbbe5062b7039bb8952d383acf2399efd
size 31871
oid sha256:fd82812f25b2a11e280cab9606b88f48dc88ec45a2067742582ba82d9426d738
size 33345

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9bf0bc49ba28e3e31414b1d1eb177c119529bc7c95209a8bbefafa6fc07a6fba
size 12603
oid sha256:6445a52dfcf1c34488fc60a30eec00e467a300dc5d4766498456a7a3b8ff93ea
size 12576

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bb559f5cd8b391ab4406c903a59376061255142317b035bd084f153779036eb9
size 36589
oid sha256:64a4a845c409c02afb7944a0e60566ed3f8ab5a2a6c9ad2dbf4f068df9ed1a7d
size 37965

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ae73b980357c9def721335ecd69ffb8d921963d422e38c84735f53b6f4a596f2
size 35101
oid sha256:d436ecedf88500e967d39adf4ee1878c956efc068c0ac5dd8b4a327cd208821e
size 36509

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fac71b82a06f65e799ca345cc9b2e22af6c0000b9900bdcdc584ca6b0f6c2c4d
size 34178
oid sha256:ba54e1084b5eeec31a86c8ed77e0e60dee7696e910eee3d03a794b6771b5c6be
size 35443

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e66b4ae355ae37f7810db1923c4018a44b1056c6471a3ed675032f036d30ff34
size 32685
oid sha256:22c9cb863c50b76ee4d95fe7def73c9cbf15d3754fc708fb8e85078e31fdd722
size 33936

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:52a5e65b23072ccfdc7220daca437e93342c04cee91cd971ba8d13872968ae7d
size 36962
oid sha256:c9fb80a007891ceba86d3cdf7711ba3a8d585358fea9558a0c451f67de58b94b
size 37346

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ea4a9e4b5488e925652ff747997dcbb58c55dd126c7b81f5222c30291270d7e6
size 39147
oid sha256:c9b3fcd78615bb01e7d6c044519a835222a5791547aa0c99a6bb7dc0a0ec72d4
size 39687

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7c60ca1b2273df93b927550e51d69f2b3a2b59f5060e0794b1cc7dbaa432dc51
size 36879
oid sha256:12ce43111318a2d77ea2dd878afb2dc8f668bb976b2a7367b732a0a5c86e71a3
size 37168

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a47d3a323db2c60d2825eccbc28b2df21ff7c5f2f2da86e27c61059493b18f70
size 38074
oid sha256:d7702e2ac4263ad23d209bce8ad6fce2a7ba3f4ca20f47c7585ff7e6e0965eed
size 38169

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7c60ca1b2273df93b927550e51d69f2b3a2b59f5060e0794b1cc7dbaa432dc51
size 36879
oid sha256:12ce43111318a2d77ea2dd878afb2dc8f668bb976b2a7367b732a0a5c86e71a3
size 37168

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4c26b06e09a81b2990a7505b70a3bf2647e508d631e9fc65ee0a37364c685808
size 38928
oid sha256:7f133c65e9857599199920927e526d1c3a89b6eea0bbae6d3951f858de11530b
size 39119

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:baa415403a4ecac05895381608a24844b5c6f90c561f561668c55fe821740cb8
size 40193
oid sha256:ad6ab5e91e5ef1ff565dda6e36c51bcd9458dba1aa99624afb63fea4f0f7f1d7
size 40259

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4c26b06e09a81b2990a7505b70a3bf2647e508d631e9fc65ee0a37364c685808
size 38928
oid sha256:7f133c65e9857599199920927e526d1c3a89b6eea0bbae6d3951f858de11530b
size 39119

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e97d88bef72c332cd145dc1080a989d163478c0252a9993f2f474bd51f2e4da8
size 148762
oid sha256:890331a5e2d87f5a326815a2729edb3fc709a509d17dfd3e33ca5d5f9dd98a3e
size 148093

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e8edd6d72db9efaaed76ac64f9882a5b66ac30747355815955157a3f3fc98c2c
size 149344
oid sha256:ae596d57381c529975d11e32c3ff3e64ec8de4eba7c52aa69fcf04e2c6854b6f
size 148784

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2cb81f2228ad63ff38bb6abe44c305adc66378bf85d36264219427be58ac58e3
size 63343
oid sha256:5e75dc8c50d9173a803c4dc8cee3b35f9bf3905bc6a19dd9479fe2d51c7f266c
size 64148

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e97d88bef72c332cd145dc1080a989d163478c0252a9993f2f474bd51f2e4da8
size 148762
oid sha256:890331a5e2d87f5a326815a2729edb3fc709a509d17dfd3e33ca5d5f9dd98a3e
size 148093

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:85222447b700315e6eea458fc72d61fb741018cb80c3a4530d4efc08ac9335ac
size 129373
oid sha256:74b7fa3ce27045b0349950e976c424a155ca5aef680a58789877cdf7a7e9a32d
size 128877

Some files were not shown because too many files have changed in this diff Show more