From 9f5952036cee25404cb2bf940bd84d06f30eaefb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9lian=20CLERC?= Date: Fri, 1 Apr 2022 16:18:16 +0200 Subject: [PATCH 01/13] Release 1.0.18 (#80) * Release/1.0.18 (#79) * Add native keyboard propositions lookalike (#78) * Bump grapes version to 1.0.18 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f2ab9107..d1bab5e9 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext { - grapes_version = '1.0.17' + grapes_version = '1.0.18' kotlin_version = '1.5.31' firebase_app_distribution_version = '2.1.2' From c309db4d07b7e3bbd7932fde3abe66318b85e0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vivien=20Mah=C3=A9?= Date: Wed, 6 Apr 2022 09:03:32 +0200 Subject: [PATCH 02/13] Fixes the secondary image of the SimpleEntryItem to be visible. (#82) --- .../src/main/res/layout/component_simple_entry_item.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/src/main/res/layout/component_simple_entry_item.xml b/library/src/main/res/layout/component_simple_entry_item.xml index de1909d3..4cc0b513 100644 --- a/library/src/main/res/layout/component_simple_entry_item.xml +++ b/library/src/main/res/layout/component_simple_entry_item.xml @@ -149,9 +149,10 @@ style="@style/SimpleEntryItemSecondaryImage" android:layout_width="@dimen/listEntryItemSecondaryImageSize" android:layout_height="@dimen/listEntryItemSecondaryImageSize" - app:layout_constraintBottom_toTopOf="@id/simpleEntryItemContentSecondaryImageStartHeightGuideline" + app:layout_constraintBottom_toTopOf="@id/simpleEntryItemContentSecondaryImageEndHeightGuideline" app:layout_constraintStart_toEndOf="@+id/simpleEntryItemContentSecondaryImageStartWidthGuideline" - app:layout_constraintTop_toBottomOf="@id/simpleEntryItemContentSecondaryImageEndHeightGuideline" + app:layout_constraintTop_toBottomOf="@id/simpleEntryItemContentSecondaryImageStartHeightGuideline" + tools:src="@drawable/ic_avatar_placeholder" tools:visibility="visible" /> From abc60bb1c53d6f92e82f461310562478153ea07a Mon Sep 17 00:00:00 2001 From: Dany Bouca Nova Date: Wed, 6 Apr 2022 10:59:46 +0200 Subject: [PATCH 03/13] [WIP] - task/update-buckets (#81) - Change DeepBlueBucket - Change InformativeActionBucket --- .../com/spendesk/grapes/DeepBlueBucketView.kt | 2 +- .../grapes/InformativeActionBucketView.kt | 38 ++++++++++---- .../res/layout/bucket_action_informative.xml | 52 +++++++++++++++---- library/src/main/res/values/colors.xml | 1 + library/src/main/res/values/dimens.xml | 3 ++ library/src/main/res/values/styles.xml | 10 +++- .../samples/home/fragments/CardsFragment.kt | 19 +++---- 7 files changed, 93 insertions(+), 32 deletions(-) diff --git a/library/src/main/java/com/spendesk/grapes/DeepBlueBucketView.kt b/library/src/main/java/com/spendesk/grapes/DeepBlueBucketView.kt index 163292d6..96376851 100644 --- a/library/src/main/java/com/spendesk/grapes/DeepBlueBucketView.kt +++ b/library/src/main/java/com/spendesk/grapes/DeepBlueBucketView.kt @@ -33,7 +33,7 @@ open class DeepBlueBucketView : BucketView { bindView() } - fun updateData(configuration: Configuration) { + fun updateConfiguration(configuration: Configuration) { with(binding) { deepBlueBucketTitle.text = configuration.title deepBlueBucketDescription.text = configuration.description diff --git a/library/src/main/java/com/spendesk/grapes/InformativeActionBucketView.kt b/library/src/main/java/com/spendesk/grapes/InformativeActionBucketView.kt index d1a268d1..4d8aa127 100644 --- a/library/src/main/java/com/spendesk/grapes/InformativeActionBucketView.kt +++ b/library/src/main/java/com/spendesk/grapes/InformativeActionBucketView.kt @@ -3,8 +3,14 @@ package com.spendesk.grapes import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater +import android.widget.TextView +import androidx.annotation.ColorRes +import androidx.core.content.ContextCompat +import androidx.core.content.res.ResourcesCompat import com.spendesk.grapes.databinding.BucketActionInformativeBinding import com.spendesk.grapes.extensions.gone +import com.spendesk.grapes.extensions.removeDrawables +import com.spendesk.grapes.extensions.setDrawableLeft import com.spendesk.grapes.extensions.visible import com.spendesk.grapes.messages.MessageInlineView @@ -12,7 +18,7 @@ import com.spendesk.grapes.messages.MessageInlineView * @author danyboucanova * @since 27/10/2020 */ -class InformativeActionBucketView : BucketView { +open class InformativeActionBucketView : BucketView { //region constructors @@ -32,30 +38,44 @@ class InformativeActionBucketView : BucketView { data class Configuration( val title: CharSequence, - val smallButtonText: CharSequence, + @ColorRes val titleColor: Int = ResourcesCompat.ID_NULL, val subtitleText: CharSequence, - val shouldShowChip: Boolean, - val messageContent: MessageInlineView.Style? = null + @ColorRes val subtitleColor: Int = ResourcesCompat.ID_NULL, + val smallButtonText: CharSequence, + val messageInlineStyle: MessageInlineView.Style? = null ) - fun updateData(configuration: Configuration) { + fun updateConfiguration(configuration: Configuration) { with(binding) { actionInformativeTitleText.text = configuration.title + configuration.titleColor + .takeIf { it != ResourcesCompat.ID_NULL } + ?.let { actionInformativeTitleText.setTextColor(ContextCompat.getColor(context, it)) } actionInformativeButton.text = configuration.smallButtonText - if (configuration.shouldShowChip) { - actionInformativeMessage.visible() + if (configuration.messageInlineStyle != null) { + actionInformativeMessageInline.visible() actionInformativeSubtitleText.gone() - configuration.messageContent?.let { actionInformativeMessage.updateConfiguration(configuration = MessageInlineView.Configuration(it, configuration.subtitleText)) } + actionInformativeMessageInline.updateConfiguration(configuration = MessageInlineView.Configuration(configuration.messageInlineStyle, configuration.subtitleText)) } else { - actionInformativeMessage.gone() + actionInformativeMessageInline.gone() actionInformativeSubtitleText.visible() actionInformativeSubtitleText.text = configuration.subtitleText } } } + fun setTitle(title: CharSequence) { + binding.actionInformativeTitleText.text = title + } + private fun bindView() { binding.actionInformativeButton.setOnClickListener { onButtonClick?.invoke() } } + + private fun updateSubtitleDrawable(textView: TextView, drawableResId: Int) = + when (drawableResId) { + 0 -> textView.removeDrawables() + else -> textView.setDrawableLeft(drawableResId) + } } \ No newline at end of file diff --git a/library/src/main/res/layout/bucket_action_informative.xml b/library/src/main/res/layout/bucket_action_informative.xml index d6b66dde..de20aae5 100644 --- a/library/src/main/res/layout/bucket_action_informative.xml +++ b/library/src/main/res/layout/bucket_action_informative.xml @@ -2,8 +2,6 @@ + + + app:layout_constraintTop_toTopOf="parent" + tools:text="Subtitle" + tools:visibility="gone" /> + tools:style="warning" + tools:text="Message Inline" + tools:visibility="visible" /> + + + tools:text="Button Text" /> \ No newline at end of file diff --git a/library/src/main/res/values/colors.xml b/library/src/main/res/values/colors.xml index c3849015..cfdc9a83 100644 --- a/library/src/main/res/values/colors.xml +++ b/library/src/main/res/values/colors.xml @@ -103,6 +103,7 @@ + @color/white @color/white @color/mainNeutralLight @color/mainComplementary diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml index 28a1d2ae..1037e631 100644 --- a/library/src/main/res/values/dimens.xml +++ b/library/src/main/res/values/dimens.xml @@ -70,8 +70,11 @@ 32sp 14sp + 2dp @dimen/smallMargin + 4dp @dimen/normalMargin + @dimen/bucketPadding diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml index b41cb5ff..8b9683da 100644 --- a/library/src/main/res/values/styles.xml +++ b/library/src/main/res/values/styles.xml @@ -38,12 +38,16 @@ @@ -52,10 +56,14 @@ @color/actionInformativeSubtitleTextColor @font/gt_america marquee - 2 + true @dimen/actionInformationSubtitleTextMarginEnd + + - + + + + + + + + + + + \ No newline at end of file diff --git a/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/InputsFragment.kt b/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/InputsFragment.kt index 273a6218..6d372e63 100644 --- a/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/InputsFragment.kt +++ b/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/InputsFragment.kt @@ -26,9 +26,19 @@ class InputsFragment : Fragment(R.layout.fragment_home_inputs) { with(binding) { homeHeader.homeGenericHeaderTitle.text = context?.getString(R.string.inputs) - homeInputsSectionSearchMainPrimary.getEditText().doAfterTextChanged { requireActivity().shortToaster("Text changed: $it") } - homeInputsSectionSearchMainPrimaryLoading.showProgressBar(true) - homeInputsSectionSearchMainSecondaryLoading.showProgressBar(true) + + // TextInput + homeInputsSectionTextInputPrimary.getEditText().doAfterTextChanged { requireActivity().shortToaster("Text changed: $it") } + homeInputsSectionTextInputPrimaryFulfilled.getEditText().setText("This is a text") + homeInputsSectionTextInputPrimaryWithIcon.getEditText().setText("This is a text") + homeInputsSectionTextInputSecondaryFulfilled.getEditText().setText("This is a text") + + // SearchInput + homeInputsSectionSearchInputPrimaryLoading.showProgressBar(true) + homeInputsSectionSearchInputSecondaryLoading.showProgressBar(true) + + // Password + homeInputsSectionPasswordInputPrimary.onEndTextClicked = { requireActivity().shortToaster("Forgot password clicked!") } } } } \ No newline at end of file diff --git a/sample/src/main/res/layout/fragment_home_cards.xml b/sample/src/main/res/layout/fragment_home_cards.xml index b630d8e5..68392f15 100644 --- a/sample/src/main/res/layout/fragment_home_cards.xml +++ b/sample/src/main/res/layout/fragment_home_cards.xml @@ -250,7 +250,6 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/homeCardSectionRegistrationCodeNormalSubtitle" /> - diff --git a/sample/src/main/res/layout/fragment_home_inputs.xml b/sample/src/main/res/layout/fragment_home_inputs.xml index f40e107d..081da8ba 100644 --- a/sample/src/main/res/layout/fragment_home_inputs.xml +++ b/sample/src/main/res/layout/fragment_home_inputs.xml @@ -18,21 +18,23 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + app:layout_constraintTop_toBottomOf="@id/homeInputsSectionTextInputTitleText"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/homeInputsSectionSearchInputPrimarySubtitle" + app:textInputStyle="primary" /> + app:layout_constraintTop_toBottomOf="@+id/homeInputsSectionSearchInputPrimary" /> - + app:layout_constraintTop_toBottomOf="@id/homeInputsSectionSearchInputPrimaryLoadingSubtitle" + app:textInputStyle="primary" /> + app:layout_constraintTop_toBottomOf="@+id/homeInputsSectionSearchInputPrimaryLoading" /> - + app:layout_constraintTop_toBottomOf="@id/homeInputsSectionSearchInputSecondarySubtitle" + app:textInputStyle="secondary" /> + app:layout_constraintTop_toBottomOf="@+id/homeInputsSectionSearchInputSecondary" /> - + app:layout_constraintTop_toBottomOf="@id/homeInputsSectionSearchInputSecondaryLoadingSubtitle" + app:textInputStyle="secondary" /> + + + + + + + + + + + + + + + + + + + diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index f46699fa..2f4e5cbe 100644 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -52,8 +52,16 @@ Not Active - Search Input Main - With loader + Text Input + Primary fulfilled + Primary with icon + Secondary fulfilled + Search Input + Primary with loader + Secondary with loader + Password Input + Enter your password + Forgot? List From ce1037906fb68a189cd5721bcb73d997356c171a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vivien=20Mah=C3=A9?= Date: Wed, 13 Apr 2022 15:24:29 +0200 Subject: [PATCH 05/13] Add horizontal and circular loading property to Button (#84) --- .../ActionMessageBottomSheetDialogFragment.kt | 8 +- .../main/java/com/spendesk/grapes/Button.kt | 244 ++++++++---- .../com/spendesk/grapes/DeepBlueBucketView.kt | 10 +- .../grapes/InformativeActionBucketView.kt | 2 +- .../block/SummaryBlockContentMapView.kt | 10 +- .../res/layout/bucket_action_informative.xml | 3 +- library/src/main/res/layout/button.xml | 51 +++ library/src/main/res/values/attrs.xml | 7 + library/src/main/res/values/colors.xml | 2 +- library/src/main/res/values/dimens.xml | 3 +- library/src/main/res/values/styles_button.xml | 26 ++ .../samples/home/fragments/ButtonsFragment.kt | 40 +- .../main/res/layout/fragment_home_buttons.xml | 351 +++++++++++++++++- sample/src/main/res/values/strings.xml | 2 + 14 files changed, 663 insertions(+), 96 deletions(-) create mode 100644 library/src/main/res/layout/button.xml create mode 100644 library/src/main/res/values/styles_button.xml diff --git a/library/src/main/java/com/spendesk/grapes/ActionMessageBottomSheetDialogFragment.kt b/library/src/main/java/com/spendesk/grapes/ActionMessageBottomSheetDialogFragment.kt index b74d0075..50f8d132 100644 --- a/library/src/main/java/com/spendesk/grapes/ActionMessageBottomSheetDialogFragment.kt +++ b/library/src/main/java/com/spendesk/grapes/ActionMessageBottomSheetDialogFragment.kt @@ -12,9 +12,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.spendesk.grapes.databinding.FragmentBottomSheetInfoBinding -import com.spendesk.grapes.extensions.getHeight -import com.spendesk.grapes.extensions.visibleOrGone -import com.spendesk.grapes.extensions.visibleWithTextOrGone +import com.spendesk.grapes.extensions.* /** * @author danyboucanova @@ -95,8 +93,8 @@ open class ActionMessageBottomSheetDialogFragment : BottomSheetDialogFragment() actionMessageBottomSheetTitleText.text = configuration.title actionMessageBottomSheetDescriptionText.visibleWithTextOrGone(configuration.description) - actionMessageBottomSheetPrimaryButton.visibleWithTextOrGone(configuration.primaryButtonText) - actionMessageBottomSheetSecondaryButton.visibleWithTextOrGone(configuration.secondaryButtonText) + with(actionMessageBottomSheetPrimaryButton) { configuration.primaryButtonText?.let { visible(); setText(it) } ?: gone() } + with(actionMessageBottomSheetSecondaryButton) { configuration.secondaryButtonText?.let { visible(); setText(it) } ?: gone() } actionMessageBottomSheetPullView.visibleOrGone(configuration.shouldShowHandle) actionMessageBottomSheetDescriptionText.apply { diff --git a/library/src/main/java/com/spendesk/grapes/Button.kt b/library/src/main/java/com/spendesk/grapes/Button.kt index 6488d5ea..2463abb2 100644 --- a/library/src/main/java/com/spendesk/grapes/Button.kt +++ b/library/src/main/java/com/spendesk/grapes/Button.kt @@ -1,19 +1,18 @@ package com.spendesk.grapes import android.content.Context +import android.graphics.Color import android.graphics.Rect -import android.graphics.Typeface -import android.text.TextUtils import android.util.AttributeSet import android.util.TypedValue -import android.view.Gravity -import androidx.annotation.ColorRes -import androidx.annotation.DimenRes -import androidx.appcompat.widget.AppCompatTextView +import android.view.LayoutInflater +import androidx.annotation.* +import androidx.annotation.IntRange import androidx.core.content.res.ResourcesCompat -import com.spendesk.grapes.extensions.colorStateListCompat -import com.spendesk.grapes.extensions.setDrawableLeft -import com.spendesk.grapes.extensions.setRippleDrawable +import androidx.core.widget.TextViewCompat +import com.google.android.material.card.MaterialCardView +import com.spendesk.grapes.databinding.ButtonBinding +import com.spendesk.grapes.extensions.* /** * Implementation of the Grapes Button which handles three different styles: Primary Button, Secondary Button and Alert Button. @@ -21,25 +20,28 @@ import com.spendesk.grapes.extensions.setRippleDrawable * @author danyboucanova * @since 10/09/2020 */ -class Button : AppCompatTextView { +class Button : MaterialCardView { + + // region constructors - //region constructors constructor(context: Context) : super(context) { - initButton(null) + setupView(null) } constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - initButton(attrs) + setupView(attrs) } constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - initButton(attrs) + setupView(attrs) } - //endregion constructors + + // endregion constructors data class Configuration( val text: CharSequence, val style: Style, + val loaderType: LoaderType = LoaderType.getDefault(), val isEnabled: Boolean = true ) @@ -79,38 +81,78 @@ class Button : AppCompatTextView { } } + enum class LoaderType(val position: Int) { + NONE(-1), + HORIZONTAL(0), + CIRCULAR(1); + + companion object { + fun fromPosition(position: Int): LoaderType { + return try { + values().first { it.position == position } + } catch (exception: NoSuchElementException) { + getDefault() + } + } + + fun getDefault() = NONE + } + } + private lateinit var size: Size private val bounds = Rect() + private var binding = ButtonBinding.inflate(LayoutInflater.from(context), this) + + init { + isClickable(isClickable = true) + } + /** - * Set the button's height according to its [Size] + * Set the button's height according to its [Size]. */ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - val desiredHeight = when (size) { - Size.NORMAL -> resources.getDimensionPixelSize(R.dimen.buttonHeight) - Size.SMALL -> resources.getDimensionPixelSize(R.dimen.buttonSmallHeight) - } - val desiredWidth = when (size) { Size.NORMAL -> MeasureSpec.getSize(widthMeasureSpec) Size.SMALL -> { - paint.getTextBounds(text.toString(), 0, text.length, bounds) + binding.text.paint.getTextBounds(binding.text.toString(), 0, binding.text.text.length, bounds) resources.getDimensionPixelSize(R.dimen.buttonSmallPaddingStart) + bounds.width() + resources.getDimensionPixelSize(R.dimen.buttonSmallPaddingEnd) } } + val desiredHeight = when (size) { + Size.NORMAL -> resources.getDimensionPixelSize(R.dimen.buttonHeight) + Size.SMALL -> resources.getDimensionPixelSize(R.dimen.buttonSmallHeight) + } + super.onMeasure( MeasureSpec.makeMeasureSpec(desiredWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(desiredHeight, MeasureSpec.EXACTLY) ) } + override fun setEnabled(enabled: Boolean) { + super.setEnabled(enabled) + + binding.text.isEnabled = enabled + binding.container.isEnabled = enabled + } + fun updateConfiguration(configuration: Configuration) { - text = configuration.text + setText(configuration.text) setStyle(configuration.style) + setLoaderType(configuration.loaderType) isEnabled = configuration.isEnabled } + fun setText(text: CharSequence) { + binding.text.text = text + } + + fun setText(@StringRes textResId: Int) { + if (textResId != TypedValue.TYPE_NULL) binding.text.setText(textResId) + } + /** * Set dynamically the style of the button * @@ -123,7 +165,7 @@ class Button : AppCompatTextView { colorBackground = R.color.buttonPrimaryBackground, colorBackgroundPressed = R.color.buttonPrimaryBackgroundPressed, colorBackgroundDisabled = R.color.buttonPrimaryBackgroundDisabled, - contentColorStateListId = R.color.btn_primary_text, + contentTextColorStateList = R.color.btn_primary_text, radius = R.dimen.buttonRadius ) @@ -132,7 +174,7 @@ class Button : AppCompatTextView { colorBackground = R.color.buttonSecondaryBackground, colorBackgroundPressed = R.color.buttonSecondaryBackgroundPressed, colorBackgroundDisabled = R.color.buttonSecondaryBackgroundDisabled, - contentColorStateListId = R.color.btn_secondary_text, + contentTextColorStateList = R.color.btn_secondary_text, radius = R.dimen.buttonRadius, stroke = R.dimen.buttonSecondaryBackgroundStroke, strokeColor = R.color.buttonSecondaryBackgroundStroke @@ -143,7 +185,7 @@ class Button : AppCompatTextView { colorBackground = R.color.buttonAlertBackground, colorBackgroundPressed = R.color.buttonAlertBackgroundPressed, colorBackgroundDisabled = R.color.buttonAlertBackgroundDisabled, - contentColorStateListId = R.color.btn_alert_text, + contentTextColorStateList = R.color.btn_alert_text, radius = R.dimen.buttonRadius, stroke = R.dimen.buttonAlertBackgroundStroke, strokeColor = R.color.buttonAlertBackgroundStroke @@ -154,78 +196,140 @@ class Button : AppCompatTextView { colorBackground = R.color.buttonWarningBackground, colorBackgroundPressed = R.color.buttonWarningBackgroundPressed, colorBackgroundDisabled = R.color.buttonWarningBackgroundDisabled, - contentColorStateListId = R.color.btn_warning_text, + contentTextColorStateList = R.color.btn_warning_text, radius = R.dimen.buttonRadius ) }.let { buttonConfig -> + // Set cardView properties + strokeWidth = if (buttonConfig.stroke != 0) resources.getDimensionPixelOffset(buttonConfig.stroke) else 0 + strokeColor = if (buttonConfig.strokeColor != 0) context.colorCompat(buttonConfig.strokeColor) else 0 + radius = resources.getDimension(buttonConfig.radius) + cardElevation = 0f + // Set background - setRippleDrawable( - buttonConfig.colorBackground, - buttonConfig.colorBackgroundPressed, - buttonConfig.colorBackgroundDisabled, - buttonConfig.radius, - buttonConfig.stroke, - buttonConfig.strokeColor + binding.container.setRippleDrawable( + colorId = buttonConfig.colorBackground, + colorPressedId = buttonConfig.colorBackgroundPressed, + colorDisableId = buttonConfig.colorBackgroundDisabled, + radiusId = buttonConfig.radius, + strokeId = buttonConfig.stroke, + strokeColorId = buttonConfig.strokeColor ) // Set color to the text of the button - setTextColor(context.colorStateListCompat(buttonConfig.contentColorStateListId)) + binding.text.setTextColor(context.colorStateListCompat(buttonConfig.contentTextColorStateList)) + + // Set color to the icon if there is one + if (binding.text.compoundDrawables.isNotEmpty()) { + TextViewCompat.setCompoundDrawableTintList(binding.text, context.colorStateListCompat(buttonConfig.contentTextColorStateList)) + } + + // Set color to the horizontal progress bar + with(binding.horizontalProgressBar) { + setIndicatorColor(context.colorCompat(buttonConfig.colorBackgroundPressed)) + trackColor = Color.TRANSPARENT + trackCornerRadius = resources.getDimensionPixelSize(R.dimen.bigMargin) + trackThickness = when (size) { + Size.NORMAL -> resources.getDimensionPixelSize(R.dimen.buttonHeight) + Size.SMALL -> resources.getDimensionPixelSize(R.dimen.buttonSmallHeight) + } + } + + // Set color to the circular progress bar + binding.circularProgressBar.setIndicatorColor(context.colorCompat(buttonConfig.contentTextColorStateList)) } } - private fun initButton(attributeSet: AttributeSet?) { - with(context.obtainStyledAttributes(attributeSet, R.styleable.Button)) { - size = Size.fromPosition(getInt(R.styleable.Button_grapesButtonSize, Size.getDefault().position)) + /** + * Sets the type of loader to be displayed for this button: + * - [LoaderType.HORIZONTAL] will display a horizontal progress bar as background of this button, the value can be updated via [updateLoaderProgress]. + * - [LoaderType.CIRCULAR] will display an infinite circular progress bar on the right side of the button. + * - [LoaderType.NONE] will remove any loader. + */ + fun setLoaderType(loaderType: LoaderType) { + with(binding) { + when (loaderType) { + LoaderType.HORIZONTAL -> { + isClickable(isClickable = false) // The button is not clickable when in loading state + text.visible() + horizontalProgressBar.visible() + circularProgressBar.gone() + } - setupView( - textId = getResourceId(R.styleable.Button_android_text, TypedValue.TYPE_NULL), - drawableStartId = getResourceId(R.styleable.Button_android_drawableStart, TypedValue.TYPE_NULL), - buttonStyle = Style.fromPosition(getInt(R.styleable.Button_grapesButtonStyle, Style.getDefault().position)) - ) + LoaderType.CIRCULAR -> { + isClickable(isClickable = false) // The button is not clickable when in loading state + text.gone() // The text is not visible when showing the circular progress bar + horizontalProgressBar.gone() + circularProgressBar.visible() + } - recycle() + LoaderType.NONE -> { + isClickable(isClickable = true) + text.visible() + horizontalProgressBar.gone() + circularProgressBar.gone() + } + } } } - private fun setupView(textId: Int, drawableStartId: Int, buttonStyle: Style) { - // Set basic properties - includeFontPadding = false - ellipsize = TextUtils.TruncateAt.MARQUEE - gravity = Gravity.CENTER - isClickable = true - isFocusable = true - isAllCaps = false - setSingleLine() + /** + * Updates the progress of the horizontal progress bar, if set using [LoaderType.HORIZONTAL]. The range of the progress is 0 to 100. + * + * @param progress Value of the progress bar within the range 0 to 100. + */ + fun updateLoaderProgress(@IntRange(from = 0, to = 100) progress: Int) { + binding.horizontalProgressBar.setProgressCompat(progress, true) + } - // Set text font - if (!isInEditMode) setTypeface(ResourcesCompat.getFont(context, R.font.gt_america_bold), Typeface.NORMAL) + private fun setupView(attributeSet: AttributeSet?) { + with(context.obtainStyledAttributes(attributeSet, R.styleable.Button)) { + val buttonSize = Size.fromPosition(getInt(R.styleable.Button_grapesButtonSize, Size.getDefault().position)) + val textId = getResourceId(R.styleable.Button_android_text, TypedValue.TYPE_NULL) + val drawableStartId = getResourceId(R.styleable.Button_android_drawableStart, TypedValue.TYPE_NULL) + val enabled = getBoolean(R.styleable.Button_android_enabled, true) + val buttonStyle = Style.fromPosition(getInt(R.styleable.Button_grapesButtonStyle, Style.getDefault().position)) + val loaderType = LoaderType.fromPosition(getInt(R.styleable.Button_grapesButtonLoaderType, LoaderType.getDefault().position)) + recycle() - // Set text size - when (size) { - Size.SMALL -> R.dimen.buttonSmallTextSize - Size.NORMAL -> R.dimen.buttonNormalTextSize - }.let { buttonTextSizeResId -> setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimensionPixelOffset(buttonTextSizeResId).toFloat()) } + isEnabled = enabled + size = buttonSize + setText(textResId = textId) + configureTextView(drawableStartId = drawableStartId) + setStyle(buttonStyle = buttonStyle) + setLoaderType(loaderType = loaderType) + } + } - // Set text - if (textId != ResourcesCompat.ID_NULL) setText(textId) + private fun configureTextView(drawableStartId: Int) { + with(binding.text) { + // Set text size depending on the requested Button size + val buttonTextSize = when (size) { + Size.SMALL -> resources.getDimensionPixelOffset(R.dimen.buttonSmallTextSize).toFloat() + Size.NORMAL -> resources.getDimensionPixelOffset(R.dimen.buttonNormalTextSize).toFloat() + } + setTextSize(TypedValue.COMPLEX_UNIT_PX, buttonTextSize) - // Set left drawable - if (drawableStartId != ResourcesCompat.ID_NULL) { - val paddingHorz = resources.getDimensionPixelSize(R.dimen.buttonDrawablePadding) + // Set left drawable if set + if (drawableStartId != ResourcesCompat.ID_NULL) { + val paddingHorz = resources.getDimensionPixelSize(R.dimen.buttonDrawablePadding) - setDrawableLeft(drawableStartId) - setPadding(paddingHorz, 0, paddingHorz + compoundDrawables.first().bounds.width(), 0) + setDrawableLeft(drawableStartId) + setPadding(paddingHorz, 0, paddingHorz + compoundDrawables.first().bounds.width(), 0) + } } + } - // Set style - setStyle(buttonStyle) + private fun isClickable(isClickable: Boolean) { + this.isClickable = isClickable + this.isFocusable = isClickable } private inner class ButtonConfig( @ColorRes val colorBackground: Int, @ColorRes val colorBackgroundPressed: Int, @ColorRes val colorBackgroundDisabled: Int, - @ColorRes val contentColorStateListId: Int, + @ColorRes val contentTextColorStateList: Int, @DimenRes val radius: Int = 0, @DimenRes val stroke: Int = 0, @ColorRes val strokeColor: Int = 0 diff --git a/library/src/main/java/com/spendesk/grapes/DeepBlueBucketView.kt b/library/src/main/java/com/spendesk/grapes/DeepBlueBucketView.kt index 96376851..bdb5cb76 100644 --- a/library/src/main/java/com/spendesk/grapes/DeepBlueBucketView.kt +++ b/library/src/main/java/com/spendesk/grapes/DeepBlueBucketView.kt @@ -34,11 +34,9 @@ open class DeepBlueBucketView : BucketView { } fun updateConfiguration(configuration: Configuration) { - with(binding) { - deepBlueBucketTitle.text = configuration.title - deepBlueBucketDescription.text = configuration.description - deepBlueBucketButton.text = configuration.buttonText - } + updateTitle(title = configuration.title) + updateDescription(description = configuration.description) + updateButtonText(buttonText = configuration.buttonText) } fun updateTitle(title: CharSequence) { @@ -50,7 +48,7 @@ open class DeepBlueBucketView : BucketView { } fun updateButtonText(buttonText: CharSequence) { - binding.deepBlueBucketButton.text = buttonText + binding.deepBlueBucketButton.setText(buttonText) } private fun bindView() { diff --git a/library/src/main/java/com/spendesk/grapes/InformativeActionBucketView.kt b/library/src/main/java/com/spendesk/grapes/InformativeActionBucketView.kt index 4d8aa127..d419b96b 100644 --- a/library/src/main/java/com/spendesk/grapes/InformativeActionBucketView.kt +++ b/library/src/main/java/com/spendesk/grapes/InformativeActionBucketView.kt @@ -51,7 +51,7 @@ open class InformativeActionBucketView : BucketView { configuration.titleColor .takeIf { it != ResourcesCompat.ID_NULL } ?.let { actionInformativeTitleText.setTextColor(ContextCompat.getColor(context, it)) } - actionInformativeButton.text = configuration.smallButtonText + actionInformativeButton.setText(configuration.smallButtonText) if (configuration.messageInlineStyle != null) { actionInformativeMessageInline.visible() diff --git a/library/src/main/java/com/spendesk/grapes/component/content/summary/block/SummaryBlockContentMapView.kt b/library/src/main/java/com/spendesk/grapes/component/content/summary/block/SummaryBlockContentMapView.kt index 5d02a7a4..4e0b8a03 100644 --- a/library/src/main/java/com/spendesk/grapes/component/content/summary/block/SummaryBlockContentMapView.kt +++ b/library/src/main/java/com/spendesk/grapes/component/content/summary/block/SummaryBlockContentMapView.kt @@ -65,7 +65,7 @@ class SummaryBlockContentMapView : SummaryBlockView { if (shouldDisplayViewMoreButton()) { summaryBlockContentViewMoreButton.visible() - summaryBlockContentViewMoreButton.text = buttonCollapsedText + updateViewMoreButton(text = buttonCollapsedText) } else { summaryBlockContentMapList.visible() } @@ -98,17 +98,21 @@ class SummaryBlockContentMapView : SummaryBlockView { when { summaryBlockContentMapList.isVisible -> { summaryBlockContentMapList.gone() - summaryBlockContentViewMoreButton.text = buttonCollapsedText + updateViewMoreButton(text = buttonCollapsedText) } summaryBlockContentMapList.isVisible.not() -> { summaryBlockContentMapList.visible() - summaryBlockContentViewMoreButton.text = buttonExpandedText + updateViewMoreButton(text = buttonExpandedText) } } } } } + private fun updateViewMoreButton(text: CharSequence?) { + text?.let { binding.summaryBlockContentViewMoreButton.setText(it) } + } + private fun shouldDisplayViewMoreButton() = buttonCollapsedText != null && buttonExpandedText != null } \ No newline at end of file diff --git a/library/src/main/res/layout/bucket_action_informative.xml b/library/src/main/res/layout/bucket_action_informative.xml index de20aae5..eae63488 100644 --- a/library/src/main/res/layout/bucket_action_informative.xml +++ b/library/src/main/res/layout/bucket_action_informative.xml @@ -40,13 +40,12 @@ android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintEnd_toStartOf="@+id/actionInformativeButton" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/actionInformativeTitleText" app:layout_constraintTop_toTopOf="parent" tools:text="Subtitle" - tools:visibility="gone" /> + tools:visibility="visible" /> + + + + + + + + + + + \ No newline at end of file diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index 65de217b..269b3cf8 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -5,9 +5,11 @@ + + @@ -18,7 +20,12 @@ + + + + + \ No newline at end of file diff --git a/library/src/main/res/values/colors.xml b/library/src/main/res/values/colors.xml index cfdc9a83..b2da0ec7 100644 --- a/library/src/main/res/values/colors.xml +++ b/library/src/main/res/values/colors.xml @@ -72,7 +72,7 @@ @color/mainPrimaryNormal @color/mainPrimaryDark - @color/mainNeutralLight + @color/mainNeutralNormal @color/white @color/white @color/white diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml index 1037e631..f450b62b 100644 --- a/library/src/main/res/values/dimens.xml +++ b/library/src/main/res/values/dimens.xml @@ -37,7 +37,6 @@ 32dp @dimen/bigMargin @dimen/bigMargin - 16sp 14sp 12dp @@ -47,6 +46,8 @@ 8dp 1dp 1dp + @dimen/smallMargin + 2dp diff --git a/library/src/main/res/values/styles_button.xml b/library/src/main/res/values/styles_button.xml new file mode 100644 index 00000000..0448f94c --- /dev/null +++ b/library/src/main/res/values/styles_button.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ButtonsFragment.kt b/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ButtonsFragment.kt index 9ddf1a4c..358a67bd 100644 --- a/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ButtonsFragment.kt +++ b/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ButtonsFragment.kt @@ -1,11 +1,16 @@ package com.spendesk.grapes.samples.home.fragments +import android.animation.ValueAnimator import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment +import androidx.interpolator.view.animation.FastOutSlowInInterpolator +import com.spendesk.grapes.Button import com.spendesk.grapes.samples.R import com.spendesk.grapes.samples.core.internal.viewBinding import com.spendesk.grapes.samples.databinding.FragmentHomeButtonsBinding +import java.util.* +import kotlin.concurrent.schedule /** * @author danyboucanova @@ -15,6 +20,9 @@ class ButtonsFragment : Fragment(R.layout.fragment_home_buttons) { companion object { fun newInstance() = ButtonsFragment() + + private const val HORIZONTAL_PROGRESS_ANIMATION_DURATION_MS = 1000L + private const val CIRCULAR_PROGRESS_ANIMATION_DELAY_MS = 2000L } private val binding by viewBinding(FragmentHomeButtonsBinding::bind) @@ -22,6 +30,36 @@ class ButtonsFragment : Fragment(R.layout.fragment_home_buttons) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.homeHeader.homeGenericHeaderTitle.text = context?.getString(R.string.buttons) + with(binding) { + homeHeader.homeGenericHeaderTitle.text = context?.getString(R.string.buttons) + + // Primary horizontal progress button + ValueAnimator.ofFloat(0f, 100f)?.apply { + duration = HORIZONTAL_PROGRESS_ANIMATION_DURATION_MS + addUpdateListener { anim -> + val animatedProgress = (anim.animatedValue as Float).toInt() + homeButtonSectionPrimaryHorizontalProgressButton.updateLoaderProgress(progress = animatedProgress) + } + interpolator = FastOutSlowInInterpolator() + repeatMode = ValueAnimator.RESTART + repeatCount = ValueAnimator.INFINITE + start() + } + + // Primary circular progress button + Timer().schedule(CIRCULAR_PROGRESS_ANIMATION_DELAY_MS) { + with(requireActivity()) { + runOnUiThread { + homeButtonSectionPrimaryCircularProgressButton.setLoaderType(loaderType = Button.LoaderType.CIRCULAR) + } + } + } + + homeButtonSectionPrimaryWithIconHorizontalProgressButton.updateLoaderProgress(progress = 30) + homeButtonSectionSecondaryHorizontalProgressButton.updateLoaderProgress(progress = 30) + homeButtonSectionSecondaryWithIconHorizontalProgressButton.updateLoaderProgress(progress = 30) + homeButtonSectionAlertHorizontalProgressButton.updateLoaderProgress(progress = 30) + homeButtonSectionWarningHorizontalProgressButton.updateLoaderProgress(progress = 30) + } } } \ No newline at end of file diff --git a/sample/src/main/res/layout/fragment_home_buttons.xml b/sample/src/main/res/layout/fragment_home_buttons.xml index 4a502bc2..8d234727 100644 --- a/sample/src/main/res/layout/fragment_home_buttons.xml +++ b/sample/src/main/res/layout/fragment_home_buttons.xml @@ -74,6 +74,61 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/homeButtonSectionPrimaryNormalSubtitle" /> + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/homeButtonSectionPrimaryCircularProgressButton" /> + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/homeButtonSectionPrimaryWithIconCircularProgressButton" /> + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/homeButtonSectionSecondaryCircularProgressButton" /> + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/homeButtonSectionSecondaryWithIconCircularProgressButton" /> + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/homeButtonSectionAlertCircularProgressButton" /> + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/homeButtonSectionWarningCircularProgressButton" /> Normal + Horizontal loading + Circular loading Disabled Primary Primary with icon From 10a7261f36fa824f62d0438f4d25daa752d1510c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vivien=20Mah=C3=A9?= Date: Wed, 13 Apr 2022 16:52:19 +0200 Subject: [PATCH 06/13] Starts migration from AppCompat to MaterialComponents. (#86) --- library/src/main/java/com/spendesk/grapes/BadgeView.kt | 4 ++-- .../spendesk/grapes/extensions/EditTextExtensions.kt | 3 +-- .../java/com/spendesk/grapes/inputs/PasswordInput.kt | 4 ++-- .../java/com/spendesk/grapes/inputs/SearchInput.kt | 4 ++-- .../main/java/com/spendesk/grapes/inputs/TextInput.kt | 6 +++--- .../com/spendesk/grapes/inputs/definition/Input.kt | 10 +++++----- .../java/com/spendesk/grapes/messages/InfoTipView.kt | 4 ++-- .../com/spendesk/grapes/messages/MessageInlineView.kt | 4 ++-- .../spendesk/grapes/selectors/SelectLabelTextView.kt | 4 ++-- library/src/main/res/layout/button.xml | 2 +- library/src/main/res/layout/password_input.xml | 2 +- library/src/main/res/layout/search_input.xml | 4 ++-- library/src/main/res/layout/selector_switch_card.xml | 2 +- library/src/main/res/layout/selector_view.xml | 8 ++++---- library/src/main/res/layout/text_input.xml | 2 +- library/src/main/res/layout/view_registration_code.xml | 10 +++++----- library/src/main/res/values/styles_input.xml | 2 +- .../com/spendesk/grapes/samples/home/HomeActivity.kt | 4 ++-- sample/src/main/res/layout/activity_home.xml | 2 +- sample/src/main/res/layout/fragment_home_selectors.xml | 8 ++++---- sample/src/main/res/menu/menu_home.xml | 2 +- sample/src/main/res/values/themes.xml | 2 +- 22 files changed, 46 insertions(+), 47 deletions(-) diff --git a/library/src/main/java/com/spendesk/grapes/BadgeView.kt b/library/src/main/java/com/spendesk/grapes/BadgeView.kt index 9aad9e0d..c6849026 100644 --- a/library/src/main/java/com/spendesk/grapes/BadgeView.kt +++ b/library/src/main/java/com/spendesk/grapes/BadgeView.kt @@ -5,15 +5,15 @@ import android.graphics.Typeface import android.util.AttributeSet import android.util.TypedValue import android.view.Gravity -import androidx.appcompat.widget.AppCompatTextView import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat +import com.google.android.material.textview.MaterialTextView /** * @author danyboucanova * @since 18/11/2020 */ -class BadgeView : AppCompatTextView { +class BadgeView : MaterialTextView { //region constructors constructor(context: Context) : super(context) diff --git a/library/src/main/java/com/spendesk/grapes/extensions/EditTextExtensions.kt b/library/src/main/java/com/spendesk/grapes/extensions/EditTextExtensions.kt index 0b780fb2..390ffa4c 100644 --- a/library/src/main/java/com/spendesk/grapes/extensions/EditTextExtensions.kt +++ b/library/src/main/java/com/spendesk/grapes/extensions/EditTextExtensions.kt @@ -4,7 +4,6 @@ import android.text.Editable import android.text.TextWatcher import android.view.MotionEvent import android.widget.EditText -import androidx.appcompat.widget.AppCompatEditText import androidx.core.content.ContextCompat import androidx.core.widget.doAfterTextChanged import com.spendesk.grapes.R @@ -16,7 +15,7 @@ import kotlin.concurrent.schedule * @since 17/06/2021 */ -internal fun AppCompatEditText.setupClearButtonWithAction() { +internal fun EditText.setupClearButtonWithAction() { val drawable = ContextCompat.getDrawable(context, R.drawable.ic_clear_round) doAfterTextChanged { editable -> diff --git a/library/src/main/java/com/spendesk/grapes/inputs/PasswordInput.kt b/library/src/main/java/com/spendesk/grapes/inputs/PasswordInput.kt index 3c08ae2e..115515bc 100644 --- a/library/src/main/java/com/spendesk/grapes/inputs/PasswordInput.kt +++ b/library/src/main/java/com/spendesk/grapes/inputs/PasswordInput.kt @@ -3,7 +3,7 @@ package com.spendesk.grapes.inputs import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater -import androidx.appcompat.widget.AppCompatEditText +import android.widget.EditText import androidx.core.content.res.ResourcesCompat import com.spendesk.grapes.R import com.spendesk.grapes.databinding.PasswordInputBinding @@ -42,7 +42,7 @@ class PasswordInput : Input { private val binding = PasswordInputBinding.inflate(LayoutInflater.from(context), this, true) - override fun getEditText(): AppCompatEditText = binding.editText + override fun getEditText(): EditText = binding.editText private fun setupView(attributeSet: AttributeSet?) { attributeSet?.let { diff --git a/library/src/main/java/com/spendesk/grapes/inputs/SearchInput.kt b/library/src/main/java/com/spendesk/grapes/inputs/SearchInput.kt index 64fdba18..28184fb9 100644 --- a/library/src/main/java/com/spendesk/grapes/inputs/SearchInput.kt +++ b/library/src/main/java/com/spendesk/grapes/inputs/SearchInput.kt @@ -3,8 +3,8 @@ package com.spendesk.grapes.inputs import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater +import android.widget.EditText import android.widget.ProgressBar -import androidx.appcompat.widget.AppCompatEditText import androidx.core.content.res.ResourcesCompat import com.spendesk.grapes.R import com.spendesk.grapes.databinding.SearchInputBinding @@ -38,7 +38,7 @@ class SearchInput : Input { private val binding = SearchInputBinding.inflate(LayoutInflater.from(context), this, true) - override fun getEditText(): AppCompatEditText = binding.editText + override fun getEditText(): EditText = binding.editText /** * Whether or not the horizontal [ProgressBar] displayed below the editText is shown. diff --git a/library/src/main/java/com/spendesk/grapes/inputs/TextInput.kt b/library/src/main/java/com/spendesk/grapes/inputs/TextInput.kt index 11b36077..1c147c4e 100644 --- a/library/src/main/java/com/spendesk/grapes/inputs/TextInput.kt +++ b/library/src/main/java/com/spendesk/grapes/inputs/TextInput.kt @@ -3,14 +3,14 @@ package com.spendesk.grapes.inputs import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater -import androidx.appcompat.widget.AppCompatEditText +import android.widget.EditText import androidx.core.content.res.ResourcesCompat import com.spendesk.grapes.R import com.spendesk.grapes.databinding.TextInputBinding import com.spendesk.grapes.inputs.definition.Input /** - * A basic implementation [Input] which only displays an [AppCompatEditText]. + * A basic implementation [Input] which only displays an [EditText]. * * @author Vivien Mahe * @since 04/04/2022 @@ -35,7 +35,7 @@ class TextInput : Input { private val binding = TextInputBinding.inflate(LayoutInflater.from(context), this, true) - override fun getEditText(): AppCompatEditText = binding.editText + override fun getEditText(): EditText = binding.editText private fun setupView(attributeSet: AttributeSet?) { attributeSet?.let { diff --git a/library/src/main/java/com/spendesk/grapes/inputs/definition/Input.kt b/library/src/main/java/com/spendesk/grapes/inputs/definition/Input.kt index 141b6511..261e750b 100644 --- a/library/src/main/java/com/spendesk/grapes/inputs/definition/Input.kt +++ b/library/src/main/java/com/spendesk/grapes/inputs/definition/Input.kt @@ -4,14 +4,14 @@ import android.content.Context import android.graphics.PorterDuff import android.graphics.PorterDuffColorFilter import android.util.AttributeSet -import androidx.appcompat.widget.AppCompatEditText +import android.widget.EditText import androidx.cardview.widget.CardView import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import com.spendesk.grapes.R /** - * Definition of an Input field within Grapes Design System, which ensure the presence of an [AppCompatEditText] and its basic configuration. + * Definition of an Input field within Grapes Design System, which ensure the presence of an [EditText] and its basic configuration. * * @author Vivien Mahe * @since 06/04/2022 @@ -50,9 +50,9 @@ abstract class Input : CardView { } /** - * Subclasses must override this method and provide the [AppCompatEditText] present in the layout to build this [Input]. + * Subclasses must override this method and provide the [EditText] present in the layout to build this [Input]. */ - abstract fun getEditText(): AppCompatEditText + abstract fun getEditText(): EditText /** * Returns the text value within the editText of this input. @@ -87,7 +87,7 @@ abstract class Input : CardView { * @param style The style to be applied to this editText. * @param extraConfiguration An instruction block that can be applied (if any) to this editText to allow some extra configuration. */ - open fun configureEditText(focusable: Boolean, hint: String? = null, drawableStart: Int, style: Style, extraConfiguration: ((editText: AppCompatEditText) -> Unit)? = null) { + open fun configureEditText(focusable: Boolean, hint: String? = null, drawableStart: Int, style: Style, extraConfiguration: ((editText: EditText) -> Unit)? = null) { with(getEditText()) { // Set basic properties this.isFocusable = focusable diff --git a/library/src/main/java/com/spendesk/grapes/messages/InfoTipView.kt b/library/src/main/java/com/spendesk/grapes/messages/InfoTipView.kt index 08438c78..2c870a95 100644 --- a/library/src/main/java/com/spendesk/grapes/messages/InfoTipView.kt +++ b/library/src/main/java/com/spendesk/grapes/messages/InfoTipView.kt @@ -7,9 +7,9 @@ import android.util.TypedValue import android.view.Gravity import androidx.annotation.DimenRes import androidx.annotation.DrawableRes -import androidx.appcompat.widget.AppCompatTextView import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat +import com.google.android.material.textview.MaterialTextView import com.spendesk.grapes.R /** @@ -17,7 +17,7 @@ import com.spendesk.grapes.R * @since 2020-01-22 */ @Deprecated("This component is deprecated. Please use the newer one MessageInlineView") -class InfoTipView : AppCompatTextView { +class InfoTipView : MaterialTextView { // region constructor diff --git a/library/src/main/java/com/spendesk/grapes/messages/MessageInlineView.kt b/library/src/main/java/com/spendesk/grapes/messages/MessageInlineView.kt index 01eb4eda..c40924d3 100644 --- a/library/src/main/java/com/spendesk/grapes/messages/MessageInlineView.kt +++ b/library/src/main/java/com/spendesk/grapes/messages/MessageInlineView.kt @@ -7,11 +7,11 @@ import android.util.TypedValue import android.view.Gravity import androidx.annotation.ColorRes import androidx.annotation.DrawableRes -import androidx.appcompat.widget.AppCompatTextView import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toDrawable +import com.google.android.material.textview.MaterialTextView import com.spendesk.grapes.R import com.spendesk.grapes.extensions.setDrawable import com.spendesk.grapes.extensions.setDrawableLeft @@ -21,7 +21,7 @@ import com.spendesk.grapes.extensions.setDrawableLeft * @author danyboucanova * @since 26/10/2020 */ -class MessageInlineView : AppCompatTextView { +class MessageInlineView : MaterialTextView { //region constructors diff --git a/library/src/main/java/com/spendesk/grapes/selectors/SelectLabelTextView.kt b/library/src/main/java/com/spendesk/grapes/selectors/SelectLabelTextView.kt index 0f1374a4..3d2cf692 100644 --- a/library/src/main/java/com/spendesk/grapes/selectors/SelectLabelTextView.kt +++ b/library/src/main/java/com/spendesk/grapes/selectors/SelectLabelTextView.kt @@ -3,8 +3,8 @@ package com.spendesk.grapes.selectors import android.content.Context import android.util.AttributeSet import android.widget.Checkable -import androidx.appcompat.widget.AppCompatTextView import androidx.core.content.ContextCompat +import com.google.android.material.textview.MaterialTextView import com.spendesk.grapes.R import com.spendesk.grapes.extensions.addRippleEffect @@ -12,7 +12,7 @@ import com.spendesk.grapes.extensions.addRippleEffect * @author danyboucanova * @since 03/06/2021 */ -open class SelectLabelTextView : AppCompatTextView, Checkable { +open class SelectLabelTextView : MaterialTextView, Checkable { //region constructors diff --git a/library/src/main/res/layout/button.xml b/library/src/main/res/layout/button.xml index b921f4ff..7f536abc 100644 --- a/library/src/main/res/layout/button.xml +++ b/library/src/main/res/layout/button.xml @@ -22,7 +22,7 @@ tools:progress="30" tools:visibility="visible" /> - - - - - + android:layout_height="wrap_content" + android:paddingHorizontal="@dimen/selectorViewTextPaddingHorz" + android:paddingVertical="@dimen/selectorViewTextPaddingVert"> - - - - - - diff --git a/sample/src/main/java/com/spendesk/grapes/samples/home/HomeActivity.kt b/sample/src/main/java/com/spendesk/grapes/samples/home/HomeActivity.kt index bd66429a..ba13eff1 100644 --- a/sample/src/main/java/com/spendesk/grapes/samples/home/HomeActivity.kt +++ b/sample/src/main/java/com/spendesk/grapes/samples/home/HomeActivity.kt @@ -5,7 +5,7 @@ import android.view.Menu import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate -import androidx.appcompat.widget.SwitchCompat +import com.google.android.material.switchmaterial.SwitchMaterial import com.google.android.material.tabs.TabLayoutMediator import com.spendesk.grapes.samples.R import com.spendesk.grapes.samples.core.extensions.disposedBy @@ -45,7 +45,7 @@ class HomeActivity : AppCompatActivity() { override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.menu_home, menu) - with(menu?.findItem(R.id.menuHomeSwitchTheme)?.actionView as SwitchCompat) { + with(menu?.findItem(R.id.menuHomeSwitchTheme)?.actionView as SwitchMaterial) { isChecked = isDarkThemeOn() setOnCheckedChangeListener { buttonView, isChecked -> diff --git a/sample/src/main/res/layout/activity_home.xml b/sample/src/main/res/layout/activity_home.xml index a1af9562..db5d1000 100644 --- a/sample/src/main/res/layout/activity_home.xml +++ b/sample/src/main/res/layout/activity_home.xml @@ -19,7 +19,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> - - - + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/homeSelectorsSectionTabCardViewTabLayoutOne" /> \ No newline at end of file diff --git a/sample/src/main/res/values/themes.xml b/sample/src/main/res/values/themes.xml index 687e21cd..aff73498 100644 --- a/sample/src/main/res/values/themes.xml +++ b/sample/src/main/res/values/themes.xml @@ -25,7 +25,7 @@ @drawable/layer_list_splashscreen - From 8af5e0266b20a3f0d834ba81ad3f60c3ff971350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9lian=20CLERC?= Date: Fri, 15 Apr 2022 15:28:57 +0200 Subject: [PATCH 07/13] Release/1.0.19 (#89) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d1bab5e9..5be6369c 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext { - grapes_version = '1.0.18' + grapes_version = '1.0.19' kotlin_version = '1.5.31' firebase_app_distribution_version = '2.1.2' From dfe76bec01b843f25a97c8b6f6bd296d44af27a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vivien=20Mah=C3=A9?= Date: Thu, 21 Apr 2022 14:28:07 +0200 Subject: [PATCH 08/13] Fixes setting the width of a Button. (#90) --- library/src/main/java/com/spendesk/grapes/Button.kt | 12 ++++++------ .../grapes/samples/home/fragments/ButtonsFragment.kt | 10 +++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/library/src/main/java/com/spendesk/grapes/Button.kt b/library/src/main/java/com/spendesk/grapes/Button.kt index 2463abb2..edc5ecad 100644 --- a/library/src/main/java/com/spendesk/grapes/Button.kt +++ b/library/src/main/java/com/spendesk/grapes/Button.kt @@ -1,6 +1,7 @@ package com.spendesk.grapes import android.content.Context +import android.content.res.ColorStateList import android.graphics.Color import android.graphics.Rect import android.util.AttributeSet @@ -112,9 +113,9 @@ class Button : MaterialCardView { * Set the button's height according to its [Size]. */ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - val desiredWidth = when (size) { - Size.NORMAL -> MeasureSpec.getSize(widthMeasureSpec) - Size.SMALL -> { + val desiredWidth = when (MeasureSpec.getMode(widthMeasureSpec)) { + MeasureSpec.EXACTLY -> MeasureSpec.getSize(widthMeasureSpec) + else -> { binding.text.paint.getTextBounds(binding.text.toString(), 0, binding.text.text.length, bounds) resources.getDimensionPixelSize(R.dimen.buttonSmallPaddingStart) + bounds.width() + resources.getDimensionPixelSize(R.dimen.buttonSmallPaddingEnd) } @@ -205,15 +206,14 @@ class Button : MaterialCardView { strokeColor = if (buttonConfig.strokeColor != 0) context.colorCompat(buttonConfig.strokeColor) else 0 radius = resources.getDimension(buttonConfig.radius) cardElevation = 0f + rippleColor = ColorStateList.valueOf(Color.TRANSPARENT) // Set background binding.container.setRippleDrawable( colorId = buttonConfig.colorBackground, colorPressedId = buttonConfig.colorBackgroundPressed, colorDisableId = buttonConfig.colorBackgroundDisabled, - radiusId = buttonConfig.radius, - strokeId = buttonConfig.stroke, - strokeColorId = buttonConfig.strokeColor + radiusId = buttonConfig.radius ) // Set color to the text of the button diff --git a/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ButtonsFragment.kt b/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ButtonsFragment.kt index 358a67bd..3618225b 100644 --- a/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ButtonsFragment.kt +++ b/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ButtonsFragment.kt @@ -48,10 +48,14 @@ class ButtonsFragment : Fragment(R.layout.fragment_home_buttons) { // Primary circular progress button Timer().schedule(CIRCULAR_PROGRESS_ANIMATION_DELAY_MS) { - with(requireActivity()) { - runOnUiThread { - homeButtonSectionPrimaryCircularProgressButton.setLoaderType(loaderType = Button.LoaderType.CIRCULAR) + try { + with(requireActivity()) { + runOnUiThread { + homeButtonSectionPrimaryCircularProgressButton.setLoaderType(loaderType = Button.LoaderType.CIRCULAR) + } } + } catch (throwable: Throwable) { + // Might crash when the activity is killed and the timer requires it } } From d7ce5a5df025617fd54d0f12742f9a463c55f381 Mon Sep 17 00:00:00 2001 From: Dany Bouca Nova Date: Thu, 21 Apr 2022 14:41:08 +0200 Subject: [PATCH 09/13] [Fix] - task/fix-simple-entry-item-view (#91) - Fix simple entry item + samples --- .../res/layout/component_simple_entry_item.xml | 18 +----------------- library/src/main/res/layout/summary_header.xml | 1 - .../samples/home/fragments/ListsFragment.kt | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/library/src/main/res/layout/component_simple_entry_item.xml b/library/src/main/res/layout/component_simple_entry_item.xml index 4cc0b513..75e2a7d5 100644 --- a/library/src/main/res/layout/component_simple_entry_item.xml +++ b/library/src/main/res/layout/component_simple_entry_item.xml @@ -126,7 +126,7 @@ android:id="@+id/simpleEntryItemSelectionMarker" style="@style/SimpleEntryItemSelectorMarker" android:layout_width="@dimen/listEntryItemSelectorMarkerWidth" - android:layout_height="0dp" + android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -210,14 +210,6 @@ tools:text="7 €" tools:visibility="visible" /> - - - - Date: Thu, 21 Apr 2022 14:54:43 +0200 Subject: [PATCH 10/13] [ActionMessageBottomSheet] - task/AA-1727-action-message-bottom-sheet-change-font (#92) - Change font --- library/src/main/res/values/dimens.xml | 2 +- library/src/main/res/values/styles_bottom_sheets.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml index f450b62b..f4e70fe1 100644 --- a/library/src/main/res/values/dimens.xml +++ b/library/src/main/res/values/dimens.xml @@ -207,7 +207,7 @@ @dimen/hugeMargin @dimen/normalMargin 18sp - 16sp + @dimen/bodyRegularSize @dimen/normalMargin @dimen/normalMargin diff --git a/library/src/main/res/values/styles_bottom_sheets.xml b/library/src/main/res/values/styles_bottom_sheets.xml index b82bf235..6a0a4336 100644 --- a/library/src/main/res/values/styles_bottom_sheets.xml +++ b/library/src/main/res/values/styles_bottom_sheets.xml @@ -42,7 +42,7 @@ + + + \ No newline at end of file diff --git a/sample/src/main/res/values/styles_components.xml b/sample/src/main/res/values/styles_components.xml new file mode 100644 index 00000000..f4cfe57f --- /dev/null +++ b/sample/src/main/res/values/styles_components.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file From 2bbff00700728fe7ec62ce3372be848548c63052 Mon Sep 17 00:00:00 2001 From: Tweener Date: Thu, 21 Apr 2022 19:10:56 +0200 Subject: [PATCH 12/13] Fixes SummaryHeader so the simpleEntryItem is not clickable. Also, adds the SummaryHeader to the Grapes demo app. --- .../content/summary/SummaryHeaderView.kt | 1 + .../home/fragments/ContentsFragment.kt | 49 ++++++++++++++++ .../res/layout/fragment_home_contents.xml | 57 ++++++++++++++++++- sample/src/main/res/values/strings.xml | 2 + 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/spendesk/grapes/component/content/summary/SummaryHeaderView.kt b/library/src/main/java/com/spendesk/grapes/component/content/summary/SummaryHeaderView.kt index a3f6757a..fa49df54 100644 --- a/library/src/main/java/com/spendesk/grapes/component/content/summary/SummaryHeaderView.kt +++ b/library/src/main/java/com/spendesk/grapes/component/content/summary/SummaryHeaderView.kt @@ -47,6 +47,7 @@ class SummaryHeaderView : ConstraintLayout { with(binding) { // User & supplier with(summaryHeaderExpenseAmountSimpleEntryView) { + isClickable = false visibleOrGone(configuration.simpleEntryItemViewConfiguration != null) configuration.simpleEntryItemViewConfiguration?.let { updateConfiguration(configuration = it) } } diff --git a/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ContentsFragment.kt b/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ContentsFragment.kt index 33101b63..0ce02214 100644 --- a/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ContentsFragment.kt +++ b/sample/src/main/java/com/spendesk/grapes/samples/home/fragments/ContentsFragment.kt @@ -3,13 +3,17 @@ package com.spendesk.grapes.samples.home.fragments import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment +import com.spendesk.grapes.component.SimpleEntryItemView import com.spendesk.grapes.component.content.summary.SummaryCardLinkView +import com.spendesk.grapes.component.content.summary.SummaryHeaderView import com.spendesk.grapes.component.content.summary.block.SummaryBlockContentMapView import com.spendesk.grapes.component.content.summary.block.SummaryBlockContentTextView import com.spendesk.grapes.component.content.summary.block.definition.SummaryBlockTitleView import com.spendesk.grapes.extensions.shortToaster import com.spendesk.grapes.list.content.summary.SummaryBlockContentModel import com.spendesk.grapes.list.content.summary.item.InlineKeyValueItemView +import com.spendesk.grapes.messages.MessageBlockView +import com.spendesk.grapes.messages.MessageInlineView import com.spendesk.grapes.samples.R import com.spendesk.grapes.samples.core.internal.viewBinding import com.spendesk.grapes.samples.databinding.FragmentHomeContentsBinding @@ -41,6 +45,51 @@ class ContentsFragment : Fragment(R.layout.fragment_home_contents) { } private fun setupBlockMap() { + // Header + with(binding.homeButtonSectionHeaderBlock) { + val simpleEntryConfiguration = SimpleEntryItemView.Configuration( + primaryImageUrl = "https://avatars.githubusercontent.com/u/9486557?s=60&v=4", + placeholderPrimaryImage = R.drawable.ic_launcher_foreground, + secondaryImageUrl = "https://avatars.githubusercontent.com/u/596985?v=4", + placeholderSecondaryImage = R.drawable.ic_launcher_foreground, + shouldCircleCropSecondaryImage = true, + titleStart = "Supplier", + descriptionStart = "Employee name • Description", + titleEnd = "71,03 €", + descriptionEnd = "14 June", + titleEndOptional = "$68,34", + messageConfiguration = MessageInlineView.Configuration( + style = MessageInlineView.Style.WARNING, + title = "Missing receipt", + drawableStartId = R.drawable.ic_warning + ) + ) + + updateConfiguration( + configuration = SummaryHeaderView.Configuration( + simpleEntryItemViewConfiguration = simpleEntryConfiguration, + amount = "130 €", + amountSubtitle = "This is the subtitle of the amount", + description = "Some description to explain why this header exists, and its existence is that questionable that it might require many many many lines to describe everything.", + descriptionSubtitle = "And if the description is not enough, there is also this field to explain more", + typeConfiguration = MessageInlineView.Configuration( + style = MessageInlineView.Style.WARNING, + title = "Missing receipt", + drawableStartId = R.drawable.ic_warning + ), + messageBlockConfiguration = MessageBlockView.Configuration( + style = MessageBlockView.Style.ALERT, + title = "Deny reason", + drawableStartId = R.drawable.ic_status_error, + description = "Oui oui oui t'es deny", + signatureText = "Par tout le monde", + signatureDrawableUrl = "https://avatars.githubusercontent.com/u/9486557?s=60&v=4", + signatureDrawablePlaceholderResId = R.drawable.ic_launcher_foreground + ) + ) + ) + } + // Map extended with(binding.homeButtonSectionMapExtendedBlock) { updateConfiguration( diff --git a/sample/src/main/res/layout/fragment_home_contents.xml b/sample/src/main/res/layout/fragment_home_contents.xml index 67f635e5..df1ad813 100644 --- a/sample/src/main/res/layout/fragment_home_contents.xml +++ b/sample/src/main/res/layout/fragment_home_contents.xml @@ -18,6 +18,61 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/homeButtonSectionHeaderBucketView" /> List + Header + Full header Map Extended Compact From 7a8311d0740b61cdab1e24a5367e3496b7448a66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vivien=20Mah=C3=A9?= Date: Mon, 25 Apr 2022 10:37:06 +0200 Subject: [PATCH 13/13] SearchableBottomSheetDialogFragment - Crash due to Activity not attached (#93) --- .../SearchableBottomSheetDialogFragment.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/spendesk/grapes/bottomsheet/searchable/SearchableBottomSheetDialogFragment.kt b/library/src/main/java/com/spendesk/grapes/bottomsheet/searchable/SearchableBottomSheetDialogFragment.kt index 0b24198f..55c7e8ad 100644 --- a/library/src/main/java/com/spendesk/grapes/bottomsheet/searchable/SearchableBottomSheetDialogFragment.kt +++ b/library/src/main/java/com/spendesk/grapes/bottomsheet/searchable/SearchableBottomSheetDialogFragment.kt @@ -8,6 +8,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.FrameLayout +import androidx.fragment.app.FragmentActivity import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment @@ -150,11 +151,20 @@ class SearchableBottomSheetDialogFragment : BottomSheetDialogFragment() { private fun bindView() { binding?.apply { searchableSheetHeaderCloseButton.setOnClickListener { dismiss() } - searchableSheetSearchInput.getEditText().afterTextChangedWith(EDITTEXT_TEXT_CHANGED_DELAY) { with(requireActivity()) { runOnUiThread { onSearchInputChanged?.invoke(it.trim()) } } } + searchableSheetSearchInput.getEditText().afterTextChangedWith(EDITTEXT_TEXT_CHANGED_DELAY) { withActivityAttached { runOnUiThread { onSearchInputChanged?.invoke(it.trim()) } } } } with(adapter) { - onItemSelected = { _, item -> with(requireActivity()) { runOnUiThread { onItemClicked?.invoke(item) } } } + onItemSelected = { _, item -> withActivityAttached { runOnUiThread { onItemClicked?.invoke(item) } } } + } + } + + /** + * Ensures the parent activity is attached to perform the given action [consumer]. + */ + private fun withActivityAttached(consumer: FragmentActivity.() -> Unit) { + if (isAdded && activity != null) { + consumer(requireActivity()) } } }