From 7a02f09439da48e07c8eea392cb5da48c6b14057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Wed, 7 Sep 2022 10:50:49 +0200 Subject: [PATCH 01/48] ColorUtil: treat empty color strings the same as null ones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise parseColor crashes Signed-off-by: Álvaro Brey --- .../java/com/nextcloud/android/common/ui/color/ColorUtil.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt b/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt index 0c6060b1..d2c02cd2 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt @@ -73,7 +73,11 @@ class ColorUtil @Inject constructor(private val context: Context) { @ColorInt private fun String?.parseColorOrFallback(fallback: () -> Int): Int { - return this?.let { Color.parseColor(this) } ?: fallback() + return if (this?.isNotBlank() == true) { + Color.parseColor(this) + } else { + fallback() + } } @ColorInt From c4d7e8f77ab9af096c3abd5b8e3fc0c613b6e126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Wed, 7 Sep 2022 12:10:36 +0200 Subject: [PATCH 02/48] ui: AndroidViewThemeUtils: add primary coloring method for progressbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous method required passing the color in Signed-off-by: Álvaro Brey --- .../android/common/ui/theme/utils/AndroidViewThemeUtils.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 28484745..52877bff 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -136,6 +136,12 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } + fun themeHorizontalProgressBar(progressBar: ProgressBar) { + withScheme(progressBar) { scheme -> + themeHorizontalProgressBar(progressBar, scheme.primary) + } + } + fun themeHorizontalProgressBar(progressBar: ProgressBar?, @ColorInt color: Int) { if (progressBar != null) { progressBar.indeterminateDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN) From a421fca7697fb9b00b0aafc76e94e1fd5383733e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Wed, 7 Sep 2022 13:14:44 +0200 Subject: [PATCH 03/48] ui: AndroidViewThemeUtils: more methods regarding buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 52877bff..006813e6 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -196,6 +196,13 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } + /** + * In most cases you'll want to use [themeImageButton] instead. + */ + fun colorImageButton(imageButton: ImageButton?, @ColorInt color: Int) { + imageButton?.setColorFilter(color, PorterDuff.Mode.SRC_ATOP) + } + /** * Tints the image with element color */ @@ -206,6 +213,15 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } fun colorTextButtons(vararg buttons: Button) { + withScheme(buttons[0]) { scheme -> + colorTextButtons(scheme.primary, *buttons) + } + } + + /** + * In most cases you'll want to use [colorTextButtons] instead. + */ + fun colorTextButtons(@ColorInt color: Int, vararg buttons: Button) { withScheme(buttons[0]) { scheme -> for (button in buttons) { button.setTextColor( @@ -215,7 +231,7 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat intArrayOf(-android.R.attr.state_enabled) ), intArrayOf( - scheme.primary, + color, colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) ) ) From 7d838732fc1e949d0cc04035fd2aef394073ed7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Wed, 7 Sep 2022 23:21:50 +0200 Subject: [PATCH 04/48] AndroidViewThemeUtils: use gray for disabled checkboxes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 006813e6..00d8a485 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -35,15 +35,7 @@ import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan import android.view.MenuItem import android.view.View -import android.widget.Button -import android.widget.CheckBox -import android.widget.EditText -import android.widget.ImageButton -import android.widget.ImageView -import android.widget.ProgressBar -import android.widget.RadioButton -import android.widget.SeekBar -import android.widget.TextView +import android.widget.* import androidx.annotation.ColorInt import androidx.core.content.res.ResourcesCompat import com.nextcloud.android.common.ui.R @@ -258,15 +250,19 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } - fun themeCheckbox(checkbox: CheckBox) { - withScheme(checkbox) { scheme -> - checkbox.buttonTintList = ColorStateList( + fun themeCheckbox(vararg checkboxes: CheckBox) { + withScheme(checkboxes[0]) { scheme -> + val colorStateList = ColorStateList( arrayOf( intArrayOf(-android.R.attr.state_checked), + intArrayOf(-android.R.attr.state_enabled), intArrayOf(android.R.attr.state_checked) ), - intArrayOf(Color.GRAY, scheme.primary) + intArrayOf(Color.GRAY, Color.GRAY, scheme.primary) ) + checkboxes.forEach { + it.buttonTintList = colorStateList + } } } From 2bb8097838dc4e5eb5cc6775bad1ca38ac71b094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Thu, 8 Sep 2022 10:01:38 +0200 Subject: [PATCH 05/48] Add MaterialSchemes implementation from color MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Useful for fallback theming Signed-off-by: Álvaro Brey --- .../android/common/ui/theme/MaterialSchemes.kt | 2 ++ .../android/common/ui/theme/MaterialSchemesImpl.kt | 11 +++++++---- .../common/ui/theme/utils/MaterialViewThemeUtils.kt | 7 +++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/MaterialSchemes.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/MaterialSchemes.kt index 9ee03e4e..7f4233f9 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/MaterialSchemes.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/MaterialSchemes.kt @@ -21,6 +21,7 @@ package com.nextcloud.android.common.ui.theme +import androidx.annotation.ColorInt import scheme.Scheme interface MaterialSchemes { @@ -36,5 +37,6 @@ interface MaterialSchemes { companion object { fun fromServerTheme(theme: ServerTheme): MaterialSchemes = MaterialSchemesImpl(theme) + fun fromColor(@ColorInt color: Int): MaterialSchemes = MaterialSchemesImpl(color) } } diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/MaterialSchemesImpl.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/MaterialSchemesImpl.kt index 85eb3280..d76ba327 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/MaterialSchemesImpl.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/MaterialSchemesImpl.kt @@ -21,15 +21,18 @@ package com.nextcloud.android.common.ui.theme +import androidx.annotation.ColorInt import scheme.Scheme -internal class MaterialSchemesImpl(serverTheme: ServerTheme) : +internal class MaterialSchemesImpl : MaterialSchemes { override val lightScheme: Scheme override val darkScheme: Scheme - init { - lightScheme = Scheme.light(serverTheme.primaryColor) - darkScheme = Scheme.dark(serverTheme.primaryColor) + constructor(@ColorInt primaryColor: Int) { + lightScheme = Scheme.light(primaryColor) + darkScheme = Scheme.dark(primaryColor) } + + constructor(serverTheme: ServerTheme) : this(serverTheme.primaryColor) } diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 258328f1..0d6bd458 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -35,6 +35,7 @@ import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipDrawable import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.progressindicator.LinearProgressIndicator +import com.google.android.material.snackbar.Snackbar import com.google.android.material.tabs.TabLayout import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textview.MaterialTextView @@ -304,6 +305,12 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva } } + fun themeSnackbarActionText(snackbar: Snackbar) { + withScheme(snackbar.context) { scheme -> + snackbar.setActionTextColor(scheme.primary) + } + } + companion object { private const val SURFACE_OPACITY_BUTTON_DISABLED: Float = 0.12f private const val ON_SURFACE_OPACITY_BUTTON_DISABLED: Float = 0.38f From 9dc69a60dbfe7f70345c62d9525b77fa4a4736f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Thu, 8 Sep 2022 11:10:18 +0200 Subject: [PATCH 06/48] Fix detekt/ktlint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .idea/codeStyles/Project.xml | 117 ++++++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 + .../ui/theme/utils/AndroidViewThemeUtils.kt | 10 +- 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..4bec4ea8 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,117 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..a55e7a17 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 00d8a485..e16e644f 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -35,7 +35,15 @@ import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan import android.view.MenuItem import android.view.View -import android.widget.* +import android.widget.Button +import android.widget.CheckBox +import android.widget.EditText +import android.widget.ImageButton +import android.widget.ImageView +import android.widget.ProgressBar +import android.widget.RadioButton +import android.widget.SeekBar +import android.widget.TextView import androidx.annotation.ColorInt import androidx.core.content.res.ResourcesCompat import com.nextcloud.android.common.ui.R From a6f7b9ed9a7999498ec63b4d4f68ccbc6504d89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Thu, 8 Sep 2022 14:21:17 +0200 Subject: [PATCH 07/48] AndroidViewThemeUtils: themeProgressBar: null-check both drawables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../android/common/ui/theme/utils/AndroidViewThemeUtils.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index e16e644f..f1ef5981 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -143,10 +143,8 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } fun themeHorizontalProgressBar(progressBar: ProgressBar?, @ColorInt color: Int) { - if (progressBar != null) { - progressBar.indeterminateDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN) - progressBar.progressDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN) - } + progressBar?.indeterminateDrawable?.setColorFilter(color, PorterDuff.Mode.SRC_IN) + progressBar?.progressDrawable?.setColorFilter(color, PorterDuff.Mode.SRC_IN) } fun colorPrimaryTextViewElement(textView: TextView) { From d0d53470766550fb572663720935e7117b8878fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Thu, 8 Sep 2022 14:22:02 +0200 Subject: [PATCH 08/48] MaterialViewThemeUtils: themeTextInputLayout: also color editText highlight MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../android/common/ui/theme/utils/MaterialViewThemeUtils.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 0d6bd458..3b68df5c 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -250,6 +250,8 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva textInputLayout.setErrorTextColor(errorColorStateList) textInputLayout.boxStrokeErrorColor = errorColorStateList textInputLayout.defaultHintTextColor = coloredColorStateList + + textInputLayout.editText?.highlightColor = scheme.primary } } From 733db63e348807d412ec3260b77e0ff7bb03f7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Thu, 8 Sep 2022 16:47:13 +0200 Subject: [PATCH 09/48] AndroidViewThemeUtils: alternate coloring for menu items MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index f1ef5981..3b306e6d 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -31,6 +31,7 @@ import android.graphics.PorterDuff import android.graphics.Typeface import android.os.Build import android.text.Spannable +import android.text.SpannableString import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan import android.view.MenuItem @@ -46,11 +47,13 @@ import android.widget.SeekBar import android.widget.TextView import androidx.annotation.ColorInt import androidx.core.content.res.ResourcesCompat +import androidx.core.graphics.drawable.DrawableCompat import com.nextcloud.android.common.ui.R import com.nextcloud.android.common.ui.color.ColorUtil import com.nextcloud.android.common.ui.theme.MaterialSchemes import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase import com.nextcloud.android.common.ui.util.PlatformThemeUtil +import scheme.Scheme import javax.inject.Inject /** @@ -68,10 +71,46 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat fun colorToolbarMenuIcon(context: Context, item: MenuItem) { withScheme(context) { scheme -> - item.icon.setColorFilter(scheme.onSurface, PorterDuff.Mode.SRC_ATOP) + colorMenuItemIcon(scheme.onSurface, item) } } + fun colorMenuItemText(context: Context, item: MenuItem) { + withScheme(context) { scheme: Scheme -> + colorMenuItemText(scheme.onSurface, item) + } + } + + fun colorMenuItemIconActive(context: Context, item: MenuItem) { + withScheme(context) { scheme -> + colorMenuItemIcon(scheme.primary, item) + } + } + + fun colorMenuItemTextActive(context: Context, item: MenuItem) { + withScheme(context) { scheme: Scheme -> + colorMenuItemText(scheme.primary, item) + } + } + + private fun colorMenuItemIcon(@ColorInt color: Int, item: MenuItem) { + val normalDrawable = item.icon + val wrapDrawable = DrawableCompat.wrap(normalDrawable) + DrawableCompat.setTint(wrapDrawable, color) + item.icon = wrapDrawable + } + + private fun colorMenuItemText(@ColorInt color: Int, item: MenuItem) { + val newItemTitle = SpannableString(item.title) + newItemTitle.setSpan( + ForegroundColorSpan(color), + 0, + newItemTitle.length, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + item.title = newItemTitle + } + fun themeStatusBar(activity: Activity, view: View) { withScheme(view) { scheme -> applyColorToStatusBar(activity, scheme.surface) From 5b1e562a13215dbc75b792069e52f8b036210564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Mon, 12 Sep 2022 18:23:50 +0200 Subject: [PATCH 10/48] AndroidViewThemeUtils: better name for imageview method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deprecate old name Signed-off-by: Álvaro Brey --- .../common/ui/theme/utils/AndroidViewThemeUtils.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 3b306e6d..a48e3beb 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -206,8 +206,20 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat /** * Colors the background as element color and the foreground as text color. + * */ + @Deprecated( + replaceWith = ReplaceWith("colorImageViewBackgroundAndIcon"), + message = "Use colorImageViewBackgroundAndIcon, which has a better name, instead" + ) fun colorImageViewButton(imageView: ImageView) { + colorImageViewBackgroundAndIcon(imageView) + } + + /** + * Colors the background as element color and the foreground as text color. + */ + fun colorImageViewBackgroundAndIcon(imageView: ImageView) { withScheme(imageView) { scheme -> imageView.imageTintList = ColorStateList.valueOf(scheme.onPrimaryContainer) imageView.backgroundTintList = ColorStateList.valueOf(scheme.primaryContainer) From ba371b85e3ac9a805b740afc0df0571b81479123 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 12 Sep 2022 22:24:26 +0200 Subject: [PATCH 11/48] Add NavigationView theming Signed-off-by: Andy Scherzinger --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index a48e3beb..f75b67a6 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -48,6 +48,7 @@ import android.widget.TextView import androidx.annotation.ColorInt import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.DrawableCompat +import com.google.android.material.navigation.NavigationView import com.nextcloud.android.common.ui.R import com.nextcloud.android.common.ui.color.ColorUtil import com.nextcloud.android.common.ui.theme.MaterialSchemes @@ -69,6 +70,40 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } + fun colorNavigationView(navigationView: NavigationView) { + withScheme(navigationView) { scheme -> + if (navigationView.itemBackground != null) { + navigationView.itemBackground!!.setTintList( + ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_checked), + intArrayOf(-android.R.attr.state_checked) + ), + intArrayOf( + scheme.secondaryContainer, + Color.TRANSPARENT + ) + ) + ) + } + navigationView.setBackgroundColor(scheme.surface) + + val colorStateList = ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_checked), + intArrayOf(-android.R.attr.state_checked) + ), + intArrayOf( + scheme.onSecondaryContainer, + scheme.onSurfaceVariant + ) + ) + + navigationView.itemTextColor = colorStateList + navigationView.itemIconTintList = colorStateList + } + } + fun colorToolbarMenuIcon(context: Context, item: MenuItem) { withScheme(context) { scheme -> colorMenuItemIcon(scheme.onSurface, item) @@ -83,13 +118,13 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat fun colorMenuItemIconActive(context: Context, item: MenuItem) { withScheme(context) { scheme -> - colorMenuItemIcon(scheme.primary, item) + colorMenuItemIcon(scheme.onSecondaryContainer, item) } } fun colorMenuItemTextActive(context: Context, item: MenuItem) { withScheme(context) { scheme: Scheme -> - colorMenuItemText(scheme.primary, item) + colorMenuItemText(scheme.onSecondaryContainer, item) } } From 114c019e9348d345f1760bed357de5dd710311fc Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 12 Sep 2022 22:38:22 +0200 Subject: [PATCH 12/48] remove unneeded theming methods Signed-off-by: Andy Scherzinger --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index f75b67a6..2f4c979f 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -104,30 +104,12 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } - fun colorToolbarMenuIcon(context: Context, item: MenuItem) { - withScheme(context) { scheme -> - colorMenuItemIcon(scheme.onSurface, item) - } - } - fun colorMenuItemText(context: Context, item: MenuItem) { withScheme(context) { scheme: Scheme -> colorMenuItemText(scheme.onSurface, item) } } - fun colorMenuItemIconActive(context: Context, item: MenuItem) { - withScheme(context) { scheme -> - colorMenuItemIcon(scheme.onSecondaryContainer, item) - } - } - - fun colorMenuItemTextActive(context: Context, item: MenuItem) { - withScheme(context) { scheme: Scheme -> - colorMenuItemText(scheme.onSecondaryContainer, item) - } - } - private fun colorMenuItemIcon(@ColorInt color: Int, item: MenuItem) { val normalDrawable = item.icon val wrapDrawable = DrawableCompat.wrap(normalDrawable) From 2d4985d395a0464b9880faa12e0feefc5fa48b90 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 12 Sep 2022 23:14:18 +0200 Subject: [PATCH 13/48] Add legacy action bar theming Signed-off-by: Andy Scherzinger --- .../ui/theme/utils/MaterialViewThemeUtils.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 3b68df5c..068eaea7 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -27,7 +27,15 @@ import android.content.Context import android.content.res.ColorStateList import android.graphics.Color import android.graphics.PorterDuff +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable +import android.text.Spannable +import android.text.SpannableString +import android.text.style.ForegroundColorSpan +import androidx.annotation.ColorInt +import androidx.appcompat.app.ActionBar import androidx.core.content.ContextCompat +import androidx.core.graphics.drawable.DrawableCompat import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.button.MaterialButton import com.google.android.material.card.MaterialCardView @@ -200,6 +208,31 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva } } + fun themeActionBar(context: Context, actionBar: ActionBar, title: String, backArrow: Drawable) { + withScheme(context) { scheme -> + setColoredTitle(actionBar, title, context, scheme.onSurface) + actionBar.setBackgroundDrawable(ColorDrawable(scheme.surface)) + + val wrap = DrawableCompat.wrap(backArrow) + wrap.setColorFilter(scheme.onSurface, PorterDuff.Mode.SRC_ATOP) + actionBar.setHomeAsUpIndicator(wrap) + } + } + + private fun setColoredTitle( + actionBar: ActionBar, + title: String, + context: Context, + @ColorInt color: Int + ) { + val text: Spannable = SpannableString(title) + text.setSpan(ForegroundColorSpan(color), + 0, + text.length, + Spannable.SPAN_INCLUSIVE_INCLUSIVE) + actionBar.title = text + } + fun themeToolbar(toolbar: MaterialToolbar) { withScheme(toolbar) { scheme -> toolbar.setBackgroundColor(scheme.surface) From 44134ecaffc2f4bf2ae6eaa07195b49831254c93 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 12 Sep 2022 23:58:34 +0200 Subject: [PATCH 14/48] add toolbar drawable tinting Signed-off-by: Andy Scherzinger --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 2f4c979f..80d5158f 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -29,6 +29,7 @@ import android.content.res.ColorStateList import android.graphics.Color import android.graphics.PorterDuff import android.graphics.Typeface +import android.graphics.drawable.Drawable import android.os.Build import android.text.Spannable import android.text.SpannableString @@ -36,16 +37,9 @@ import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan import android.view.MenuItem import android.view.View -import android.widget.Button -import android.widget.CheckBox -import android.widget.EditText -import android.widget.ImageButton -import android.widget.ImageView -import android.widget.ProgressBar -import android.widget.RadioButton -import android.widget.SeekBar -import android.widget.TextView +import android.widget.* import androidx.annotation.ColorInt +import androidx.appcompat.app.ActionBarDrawerToggle import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.DrawableCompat import com.google.android.material.navigation.NavigationView @@ -128,6 +122,24 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat item.title = newItemTitle } + private fun colorDrawable(@ColorInt color: Int, drawable: Drawable) { + val wrapDrawable = DrawableCompat.wrap(drawable) + DrawableCompat.setTint(wrapDrawable, color) + } + + fun tintToolbarArrowDrawable( + context: Context, + drawerToggle: ActionBarDrawerToggle, + drawable: Drawable + ) { + withScheme(context) { scheme: Scheme -> + val wrap = DrawableCompat.wrap(drawable) + wrap.setColorFilter(scheme.onSurface, PorterDuff.Mode.SRC_ATOP) + drawerToggle.setHomeAsUpIndicator(wrap) + drawerToggle.drawerArrowDrawable.color = scheme.onSurface + } + } + fun themeStatusBar(activity: Activity, view: View) { withScheme(view) { scheme -> applyColorToStatusBar(activity, scheme.surface) From 73e16f263c2fc9bfab5618f2b77c84f541432678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 13 Sep 2022 10:13:06 +0200 Subject: [PATCH 15/48] AndroidViewThemeUtils: restore colorToolbarMenuIcon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed by Talk Signed-off-by: Álvaro Brey --- .../android/common/ui/theme/utils/AndroidViewThemeUtils.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 80d5158f..d638096e 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -98,6 +98,12 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } + fun colorToolbarMenuIcon(context: Context, item: MenuItem) { + withScheme(context) { scheme -> + colorMenuItemIcon(scheme.onSurface, item) + } + } + fun colorMenuItemText(context: Context, item: MenuItem) { withScheme(context) { scheme: Scheme -> colorMenuItemText(scheme.onSurface, item) From b6222c694b2450afadf601c203cc170d4c1e745c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 13 Sep 2022 10:29:27 +0200 Subject: [PATCH 16/48] Fix detekt and ktlint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 55 ++++++++++--------- .../ui/theme/utils/MaterialViewThemeUtils.kt | 21 +++---- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index d638096e..1166598b 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -37,7 +37,15 @@ import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan import android.view.MenuItem import android.view.View -import android.widget.* +import android.widget.Button +import android.widget.CheckBox +import android.widget.EditText +import android.widget.ImageButton +import android.widget.ImageView +import android.widget.ProgressBar +import android.widget.RadioButton +import android.widget.SeekBar +import android.widget.TextView import androidx.annotation.ColorInt import androidx.appcompat.app.ActionBarDrawerToggle import androidx.core.content.res.ResourcesCompat @@ -68,29 +76,29 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat withScheme(navigationView) { scheme -> if (navigationView.itemBackground != null) { navigationView.itemBackground!!.setTintList( - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_checked) - ), - intArrayOf( - scheme.secondaryContainer, - Color.TRANSPARENT - ) + ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_checked), + intArrayOf(-android.R.attr.state_checked) + ), + intArrayOf( + scheme.secondaryContainer, + Color.TRANSPARENT ) + ) ) } navigationView.setBackgroundColor(scheme.surface) val colorStateList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_checked) - ), - intArrayOf( - scheme.onSecondaryContainer, - scheme.onSurfaceVariant - ) + arrayOf( + intArrayOf(android.R.attr.state_checked), + intArrayOf(-android.R.attr.state_checked) + ), + intArrayOf( + scheme.onSecondaryContainer, + scheme.onSurfaceVariant + ) ) navigationView.itemTextColor = colorStateList @@ -128,15 +136,10 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat item.title = newItemTitle } - private fun colorDrawable(@ColorInt color: Int, drawable: Drawable) { - val wrapDrawable = DrawableCompat.wrap(drawable) - DrawableCompat.setTint(wrapDrawable, color) - } - fun tintToolbarArrowDrawable( - context: Context, - drawerToggle: ActionBarDrawerToggle, - drawable: Drawable + context: Context, + drawerToggle: ActionBarDrawerToggle, + drawable: Drawable ) { withScheme(context) { scheme: Scheme -> val wrap = DrawableCompat.wrap(drawable) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 068eaea7..e308f2ce 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -210,7 +210,7 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun themeActionBar(context: Context, actionBar: ActionBar, title: String, backArrow: Drawable) { withScheme(context) { scheme -> - setColoredTitle(actionBar, title, context, scheme.onSurface) + setColoredTitle(actionBar, title, scheme.onSurface) actionBar.setBackgroundDrawable(ColorDrawable(scheme.surface)) val wrap = DrawableCompat.wrap(backArrow) @@ -218,18 +218,19 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva actionBar.setHomeAsUpIndicator(wrap) } } - + private fun setColoredTitle( - actionBar: ActionBar, - title: String, - context: Context, - @ColorInt color: Int + actionBar: ActionBar, + title: String, + @ColorInt color: Int ) { val text: Spannable = SpannableString(title) - text.setSpan(ForegroundColorSpan(color), - 0, - text.length, - Spannable.SPAN_INCLUSIVE_INCLUSIVE) + text.setSpan( + ForegroundColorSpan(color), + 0, + text.length, + Spannable.SPAN_INCLUSIVE_INCLUSIVE + ) actionBar.title = text } From b22b6a1aaa5a547464bdabc246a8c7feead89106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 13 Sep 2022 11:25:12 +0200 Subject: [PATCH 17/48] Move themeActionBar to AndroidX theme utils, since it's an appcompat class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../ui/theme/utils/AndroidXViewThemeUtils.kt | 36 +++++++++++++++++++ .../ui/theme/utils/MaterialViewThemeUtils.kt | 34 ------------------ 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt index c38c6e84..a2a721ce 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt @@ -23,10 +23,20 @@ package com.nextcloud.android.common.ui.theme.utils +import android.content.Context import android.content.res.ColorStateList import android.graphics.Color +import android.graphics.PorterDuff +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable +import android.text.Spannable +import android.text.SpannableString +import android.text.style.ForegroundColorSpan +import androidx.annotation.ColorInt +import androidx.appcompat.app.ActionBar import androidx.appcompat.widget.SwitchCompat import androidx.core.content.res.ResourcesCompat +import androidx.core.graphics.drawable.DrawableCompat import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.nextcloud.android.common.ui.R import com.nextcloud.android.common.ui.theme.MaterialSchemes @@ -81,6 +91,32 @@ class AndroidXViewThemeUtils @Inject constructor(schemes: MaterialSchemes) : } } + fun themeActionBar(context: Context, actionBar: ActionBar, title: String, backArrow: Drawable) { + withScheme(context) { scheme -> + setColoredTitle(actionBar, title, scheme.onSurface) + actionBar.setBackgroundDrawable(ColorDrawable(scheme.surface)) + + val wrap = DrawableCompat.wrap(backArrow) + wrap.setColorFilter(scheme.onSurface, PorterDuff.Mode.SRC_ATOP) + actionBar.setHomeAsUpIndicator(wrap) + } + } + + private fun setColoredTitle( + actionBar: ActionBar, + title: String, + @ColorInt color: Int + ) { + val text: Spannable = SpannableString(title) + text.setSpan( + ForegroundColorSpan(color), + 0, + text.length, + Spannable.SPAN_INCLUSIVE_INCLUSIVE + ) + actionBar.title = text + } + companion object { private const val SWITCH_COMPAT_TRACK_ALPHA: Int = 77 } diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index e308f2ce..3b68df5c 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -27,15 +27,7 @@ import android.content.Context import android.content.res.ColorStateList import android.graphics.Color import android.graphics.PorterDuff -import android.graphics.drawable.ColorDrawable -import android.graphics.drawable.Drawable -import android.text.Spannable -import android.text.SpannableString -import android.text.style.ForegroundColorSpan -import androidx.annotation.ColorInt -import androidx.appcompat.app.ActionBar import androidx.core.content.ContextCompat -import androidx.core.graphics.drawable.DrawableCompat import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.button.MaterialButton import com.google.android.material.card.MaterialCardView @@ -208,32 +200,6 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva } } - fun themeActionBar(context: Context, actionBar: ActionBar, title: String, backArrow: Drawable) { - withScheme(context) { scheme -> - setColoredTitle(actionBar, title, scheme.onSurface) - actionBar.setBackgroundDrawable(ColorDrawable(scheme.surface)) - - val wrap = DrawableCompat.wrap(backArrow) - wrap.setColorFilter(scheme.onSurface, PorterDuff.Mode.SRC_ATOP) - actionBar.setHomeAsUpIndicator(wrap) - } - } - - private fun setColoredTitle( - actionBar: ActionBar, - title: String, - @ColorInt color: Int - ) { - val text: Spannable = SpannableString(title) - text.setSpan( - ForegroundColorSpan(color), - 0, - text.length, - Spannable.SPAN_INCLUSIVE_INCLUSIVE - ) - actionBar.title = text - } - fun themeToolbar(toolbar: MaterialToolbar) { withScheme(toolbar) { scheme -> toolbar.setBackgroundColor(scheme.surface) From ef115b524c011f8141183147283ee523fcbe547b Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 13 Sep 2022 14:45:15 +0200 Subject: [PATCH 18/48] add drawable tinting theme methods Signed-off-by: Andy Scherzinger --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 1166598b..f47ab34a 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -37,16 +37,9 @@ import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan import android.view.MenuItem import android.view.View -import android.widget.Button -import android.widget.CheckBox -import android.widget.EditText -import android.widget.ImageButton -import android.widget.ImageView -import android.widget.ProgressBar -import android.widget.RadioButton -import android.widget.SeekBar -import android.widget.TextView +import android.widget.* import androidx.annotation.ColorInt +import androidx.annotation.DrawableRes import androidx.appcompat.app.ActionBarDrawerToggle import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.DrawableCompat @@ -136,6 +129,17 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat item.title = newItemTitle } + fun tintPrimaryDrawable(context: Context, @DrawableRes id: Int): Drawable? { + return tintPrimaryDrawable(context, ResourcesCompat.getDrawable(context.resources, id, null)) + } + + fun tintPrimaryDrawable(context: Context, drawable: Drawable?): Drawable? { + withScheme(context) { scheme: Scheme -> + drawable?.setColorFilter(scheme.primary, PorterDuff.Mode.SRC_ATOP) + } + return drawable + } + fun tintToolbarArrowDrawable( context: Context, drawerToggle: ActionBarDrawerToggle, From 5c533ef7112f158be4bebb66740253eb42eae948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 13 Sep 2022 16:11:37 +0200 Subject: [PATCH 19/48] ViewThemeUtilsBase: schemes should be private MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt index e620bb28..29a9b20e 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt @@ -28,7 +28,7 @@ import android.view.View import com.nextcloud.android.common.ui.util.PlatformThemeUtil import scheme.Scheme -open class ViewThemeUtilsBase(val schemes: MaterialSchemes) { +open class ViewThemeUtilsBase(private val schemes: MaterialSchemes) { /** * Scheme for painting elements */ From a7853a1f4fc6424236547cff8b1f1f60707f684f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 13 Sep 2022 16:12:13 +0200 Subject: [PATCH 20/48] AndroidViewThemeUtils: deprecate useless parameter in themeStatusBar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index f47ab34a..d2c1d469 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -37,7 +37,15 @@ import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan import android.view.MenuItem import android.view.View -import android.widget.* +import android.widget.Button +import android.widget.CheckBox +import android.widget.EditText +import android.widget.ImageButton +import android.widget.ImageView +import android.widget.ProgressBar +import android.widget.RadioButton +import android.widget.SeekBar +import android.widget.TextView import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.appcompat.app.ActionBarDrawerToggle @@ -153,8 +161,14 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } + @Deprecated(message = "Use themeStatusBar(activity) instead", replaceWith = ReplaceWith("themeStatusBar(activity)")) + @Suppress("Detekt.UnusedPrivateMember") // deprecated, to be removed fun themeStatusBar(activity: Activity, view: View) { - withScheme(view) { scheme -> + themeStatusBar(activity) + } + + fun themeStatusBar(activity: Activity) { + withScheme(activity) { scheme -> applyColorToStatusBar(activity, scheme.surface) } } From 1371ce1eea892006cbb95d45a0ced2f8ffb3aaec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 13 Sep 2022 18:21:37 +0200 Subject: [PATCH 21/48] Add a TODO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../android/common/ui/theme/utils/AndroidXViewThemeUtils.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt index a2a721ce..21ab77d1 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt @@ -91,6 +91,7 @@ class AndroidXViewThemeUtils @Inject constructor(schemes: MaterialSchemes) : } } + // TODO host the back arrow in this lib instead of passing it everywhere fun themeActionBar(context: Context, actionBar: ActionBar, title: String, backArrow: Drawable) { withScheme(context) { scheme -> setColoredTitle(actionBar, title, scheme.onSurface) From f3ab41a0f9dfa0c8e5a81d6c30187449a1af988a Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 14 Sep 2022 11:34:47 +0200 Subject: [PATCH 22/48] tabLayout: add icon tinting and non-surface theming method Signed-off-by: Andy Scherzinger --- .../common/ui/theme/utils/MaterialViewThemeUtils.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 3b68df5c..91196f64 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -255,6 +255,12 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva } } + fun themeTabLayout(tabLayout: TabLayout) { + withScheme(tabLayout) { scheme -> + colorTabLayout(tabLayout, scheme) + } + } + fun themeTabLayoutOnSurface(tabLayout: TabLayout) { withScheme(tabLayout) { scheme -> tabLayout.setBackgroundColor(scheme.surface) @@ -264,7 +270,7 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorTabLayout(tabLayout: TabLayout, scheme: Scheme) { tabLayout.setSelectedTabIndicatorColor(scheme.primary) - tabLayout.tabTextColors = ColorStateList( + val tabContentColors = ColorStateList( arrayOf( intArrayOf(android.R.attr.state_selected), intArrayOf(-android.R.attr.state_selected) @@ -274,6 +280,8 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva ContextCompat.getColor(tabLayout.context, R.color.high_emphasis_text) ) ) + tabLayout.tabTextColors = tabContentColors + tabLayout.tabIconTint = tabContentColors tabLayout.tabRippleColor = ColorStateList( arrayOf( intArrayOf(android.R.attr.state_pressed) From 83f7f024b8583849edb4a9bd6a4473b16b79b9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Wed, 14 Sep 2022 11:41:13 +0200 Subject: [PATCH 23/48] MaterialViewThemeUtils: theme snackbars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../android/common/ui/theme/utils/MaterialViewThemeUtils.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 91196f64..00878278 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -315,9 +315,11 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva } } - fun themeSnackbarActionText(snackbar: Snackbar) { + fun themeSnackbar(snackbar: Snackbar) { withScheme(snackbar.context) { scheme -> - snackbar.setActionTextColor(scheme.primary) + snackbar.setBackgroundTint(scheme.inverseSurface) + snackbar.setActionTextColor(scheme.inversePrimary) + snackbar.setTextColor(scheme.inverseOnSurface) } } From 48b598c0c10c7397ab75ee4d2499b5bef6b56c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Wed, 14 Sep 2022 17:01:49 +0200 Subject: [PATCH 24/48] ViewThemeUtilsBase: let withScheme return the block result MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../android/common/ui/theme/ViewThemeUtilsBase.kt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt index 29a9b20e..b5cfdc16 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt @@ -45,15 +45,9 @@ open class ViewThemeUtilsBase(private val schemes: MaterialSchemes) { else -> schemes.lightScheme } - protected fun withScheme(view: View, block: (Scheme) -> Unit) { - block(getSchemeInternal(view.context)) - } + protected fun withScheme(view: View, block: (Scheme) -> R): R = block(getSchemeInternal(view.context)) - protected fun withScheme(context: Context, block: (Scheme) -> Unit) { - block(getSchemeInternal(context)) - } + protected fun withScheme(context: Context, block: (Scheme) -> R): R = block(getSchemeInternal(context)) - protected fun withSchemeDark(block: (Scheme) -> Unit) { - block(schemes.darkScheme) - } + protected fun withSchemeDark(block: (Scheme) -> R): R = block(schemes.darkScheme) } From 740280bd5d738f715c2f1fdf3e2738c2b68f6674 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 14 Sep 2022 21:14:00 +0200 Subject: [PATCH 25/48] AppCompatTextView theming Signed-off-by: Andy Scherzinger --- .../common/ui/theme/utils/AndroidXViewThemeUtils.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt index 21ab77d1..fe4a9309 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt @@ -34,9 +34,11 @@ import android.text.SpannableString import android.text.style.ForegroundColorSpan import androidx.annotation.ColorInt import androidx.appcompat.app.ActionBar +import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.SwitchCompat import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.DrawableCompat +import androidx.core.widget.TextViewCompat import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.nextcloud.android.common.ui.R import com.nextcloud.android.common.ui.theme.MaterialSchemes @@ -91,6 +93,13 @@ class AndroidXViewThemeUtils @Inject constructor(schemes: MaterialSchemes) : } } + fun colorPrimaryTextViewElement(textView: AppCompatTextView) { + withScheme(textView) { scheme -> + textView.setTextColor(scheme.primary) + TextViewCompat.setCompoundDrawableTintList(textView, ColorStateList.valueOf(scheme.primary)) + } + } + // TODO host the back arrow in this lib instead of passing it everywhere fun themeActionBar(context: Context, actionBar: ActionBar, title: String, backArrow: Drawable) { withScheme(context) { scheme -> From ffc0af2bbbb6b3483aa1c86f56a2a1502e215290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Thu, 15 Sep 2022 20:50:40 +0200 Subject: [PATCH 26/48] ui: More utilities for tinting drawables and toolbars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../common/ui/theme/ViewThemeUtilsBase.kt | 1 + .../ui/theme/utils/AndroidViewThemeUtils.kt | 26 ++++++++++++++++--- .../ui/theme/utils/AndroidXViewThemeUtils.kt | 20 +++++++++----- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt index b5cfdc16..46a49b74 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/ViewThemeUtilsBase.kt @@ -40,6 +40,7 @@ open class ViewThemeUtilsBase(private val schemes: MaterialSchemes) { fun getScheme(context: Context): Scheme = getSchemeInternal(context) @Suppress("MemberVisibilityCanBePrivate") + // TODO cache by context hashcode protected fun getSchemeInternal(context: Context): Scheme = when { PlatformThemeUtil.isDarkMode(context) -> schemes.darkScheme else -> schemes.lightScheme diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index d2c1d469..64776821 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -50,6 +50,8 @@ import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.appcompat.app.ActionBarDrawerToggle import androidx.core.content.res.ResourcesCompat +import androidx.core.graphics.BlendModeColorFilterCompat +import androidx.core.graphics.BlendModeCompat import androidx.core.graphics.drawable.DrawableCompat import com.google.android.material.navigation.NavigationView import com.nextcloud.android.common.ui.R @@ -142,10 +144,28 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } fun tintPrimaryDrawable(context: Context, drawable: Drawable?): Drawable? { - withScheme(context) { scheme: Scheme -> - drawable?.setColorFilter(scheme.primary, PorterDuff.Mode.SRC_ATOP) + return drawable?.let { + withScheme(context) { scheme: Scheme -> + tintDrawable(it, scheme.primary) + } } - return drawable + } + + fun tintTextDrawable(context: Context, drawable: Drawable?): Drawable? { + return drawable?.let { + withScheme(context) { scheme: Scheme -> + tintDrawable(it, scheme.onSurface) + } + } + } + + internal fun tintDrawable(drawable: Drawable, @ColorInt color: Int): Drawable { + val wrap = DrawableCompat.wrap(drawable) + wrap.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat( + color, + BlendModeCompat.SRC_ATOP + ) + return wrap } fun tintToolbarArrowDrawable( diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt index fe4a9309..a3f4d716 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt @@ -26,7 +26,6 @@ package com.nextcloud.android.common.ui.theme.utils import android.content.Context import android.content.res.ColorStateList import android.graphics.Color -import android.graphics.PorterDuff import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.text.Spannable @@ -37,7 +36,6 @@ import androidx.appcompat.app.ActionBar import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.SwitchCompat import androidx.core.content.res.ResourcesCompat -import androidx.core.graphics.drawable.DrawableCompat import androidx.core.widget.TextViewCompat import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.nextcloud.android.common.ui.R @@ -48,7 +46,11 @@ import javax.inject.Inject /** * View theme utils for Android extension views (androidx.*) */ -class AndroidXViewThemeUtils @Inject constructor(schemes: MaterialSchemes) : +// TODO breaking change: androidViewThemeUtils parameter +class AndroidXViewThemeUtils @Inject constructor( + schemes: MaterialSchemes, + private val androidViewThemeUtils: AndroidViewThemeUtils +) : ViewThemeUtilsBase(schemes) { fun colorSwitchCompat(switchCompat: SwitchCompat) { @@ -104,11 +106,15 @@ class AndroidXViewThemeUtils @Inject constructor(schemes: MaterialSchemes) : fun themeActionBar(context: Context, actionBar: ActionBar, title: String, backArrow: Drawable) { withScheme(context) { scheme -> setColoredTitle(actionBar, title, scheme.onSurface) - actionBar.setBackgroundDrawable(ColorDrawable(scheme.surface)) + themeActionBar(context, actionBar, backArrow) + } + } - val wrap = DrawableCompat.wrap(backArrow) - wrap.setColorFilter(scheme.onSurface, PorterDuff.Mode.SRC_ATOP) - actionBar.setHomeAsUpIndicator(wrap) + fun themeActionBar(context: Context, actionBar: ActionBar, backArrow: Drawable) { + withScheme(context) { scheme -> + actionBar.setBackgroundDrawable(ColorDrawable(scheme.surface)) + val indicator = androidViewThemeUtils.tintDrawable(backArrow, scheme.onSurface) + actionBar.setHomeAsUpIndicator(indicator) } } From 1bbfb516d98802cfcdd43f76163fb59d67451b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Fri, 16 Sep 2022 17:47:06 +0200 Subject: [PATCH 27/48] MaterialViewThemeUtils: deprecate duplicated function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../common/ui/theme/utils/MaterialViewThemeUtils.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 00878278..f32ba468 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -208,11 +208,11 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva } } - fun colorCardViewBackground(card: MaterialCardView) { - withScheme(card) { scheme -> - card.setCardBackgroundColor(scheme.surfaceVariant) - } - } + @Deprecated( + "Duplicated, use themeCardView instead", + replaceWith = ReplaceWith("themeCardView(card)") + ) + fun colorCardViewBackground(card: MaterialCardView) = themeCardView(card) fun colorProgressBar(progressIndicator: LinearProgressIndicator) { withScheme(progressIndicator) { scheme -> From ad6fd92bb86b5da1fcd0a1df8aa27599031f00a8 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Fri, 16 Sep 2022 18:38:18 +0200 Subject: [PATCH 28/48] general theming for toolbar search field Signed-off-by: Andy Scherzinger --- .../ui/theme/utils/AndroidXViewThemeUtils.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt index a3f4d716..9f98c3cf 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt @@ -31,9 +31,12 @@ import android.graphics.drawable.Drawable import android.text.Spannable import android.text.SpannableString import android.text.style.ForegroundColorSpan +import android.widget.ImageView +import android.widget.LinearLayout import androidx.annotation.ColorInt import androidx.appcompat.app.ActionBar import androidx.appcompat.widget.AppCompatTextView +import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SwitchCompat import androidx.core.content.res.ResourcesCompat import androidx.core.widget.TextViewCompat @@ -118,6 +121,23 @@ class AndroidXViewThemeUtils @Inject constructor( } } + fun themeToolbarSearchView(searchView: SearchView) { + withScheme(searchView) { scheme -> + // hacky as no default way is provided + val editText = + searchView.findViewById(androidx.appcompat.R.id.search_src_text) + val searchPlate = searchView.findViewById(androidx.appcompat.R.id.search_plate) + val closeButton = searchView.findViewById(androidx.appcompat.R.id.search_close_btn) + val searchButton = searchView.findViewById(androidx.appcompat.R.id.search_button) + editText.setHintTextColor(scheme.onSurfaceVariant) + editText.highlightColor = scheme.inverseOnSurface + editText.setTextColor(scheme.onSurface) + closeButton.setColorFilter(scheme.onSurface) + searchButton.setColorFilter(scheme.onSurface) + searchPlate.setBackgroundColor(scheme.surface) + } + } + private fun setColoredTitle( actionBar: ActionBar, title: String, From d82cbe5ce14e379af1db81f430a9586ff1984f6b Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Fri, 16 Sep 2022 18:58:25 +0200 Subject: [PATCH 29/48] Primary color ColorDrawable Signed-off-by: Andy Scherzinger --- .../android/common/ui/theme/utils/AndroidViewThemeUtils.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 64776821..5fcc9dde 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -29,6 +29,7 @@ import android.content.res.ColorStateList import android.graphics.Color import android.graphics.PorterDuff import android.graphics.Typeface +import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.os.Build import android.text.Spannable @@ -109,6 +110,12 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } + fun getPrimaryColorDrawable(context: Context): Drawable { + return withScheme(context) { scheme -> + ColorDrawable(scheme.primary) + } + } + fun colorToolbarMenuIcon(context: Context, item: MenuItem) { withScheme(context) { scheme -> colorMenuItemIcon(scheme.onSurface, item) From 56e3af69f2f8f55f6ee2f648b765b74468107cb1 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 20 Sep 2022 17:32:15 +0200 Subject: [PATCH 30/48] add primaryColor access Signed-off-by: Andy Scherzinger --- .../android/common/ui/theme/utils/AndroidViewThemeUtils.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 5fcc9dde..03bc8115 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -477,6 +477,12 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } while (index != -1) } + fun primaryColor(activity: Activity): Int { + return withScheme(activity) { scheme -> + scheme.primary + } + } + companion object { private const val ON_SURFACE_OPACITY_BUTTON_DISABLED: Float = 0.38f } From 91842d0d1a88e97a48da8b78b1dd4ebe119a15bf Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sun, 25 Sep 2022 16:17:49 +0200 Subject: [PATCH 31/48] extend outlined buttons primary coloring for all defined states Signed-off-by: Andy Scherzinger --- .../ui/theme/utils/MaterialViewThemeUtils.kt | 27 ++++++++++++++++++- ui/src/main/res/values/dimens.xml | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index f32ba468..ac65f851 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -147,7 +147,6 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorMaterialButtonPrimaryOutlined(button: MaterialButton) { withScheme(button) { scheme -> - button.strokeColor = ColorStateList.valueOf(scheme.outline) button.setTextColor( ColorStateList( arrayOf( @@ -170,6 +169,31 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) ) ) + button.strokeColor = ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_hovered), + intArrayOf(-android.R.attr.state_focused), + intArrayOf(-android.R.attr.state_pressed), + ), + intArrayOf( + scheme.outline, + colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_OUTLINE_DISABLED), + scheme.outline, + scheme.primary, + scheme.outline + ) + ) + button.strokeWidth = button.resources.getDimension(R.dimen.outlinedButtonStrokeWidth).toInt() + button.rippleColor = ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_pressed) + ), + intArrayOf( + colorUtil.adjustOpacity(scheme.primary, SURFACE_OPACITY_BUTTON_DISABLED) + ) + ) } } @@ -325,6 +349,7 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva companion object { private const val SURFACE_OPACITY_BUTTON_DISABLED: Float = 0.12f + private const val ON_SURFACE_OPACITY_BUTTON_OUTLINE_DISABLED: Float = 0.12f private const val ON_SURFACE_OPACITY_BUTTON_DISABLED: Float = 0.38f } } diff --git a/ui/src/main/res/values/dimens.xml b/ui/src/main/res/values/dimens.xml index 354fce31..12e08de0 100644 --- a/ui/src/main/res/values/dimens.xml +++ b/ui/src/main/res/values/dimens.xml @@ -19,4 +19,5 @@ 28dp + 1dp From e961162e0d9dc850addf2bf7fd360108a0eb1298 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sun, 25 Sep 2022 21:10:12 +0200 Subject: [PATCH 32/48] Add theming for CheckedTextView Signed-off-by: Andy Scherzinger --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 17 +++++++++++++++++ .../ui/theme/utils/MaterialViewThemeUtils.kt | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 03bc8115..a79a9086 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -40,6 +40,7 @@ import android.view.MenuItem import android.view.View import android.widget.Button import android.widget.CheckBox +import android.widget.CheckedTextView import android.widget.EditText import android.widget.ImageButton import android.widget.ImageView @@ -390,6 +391,22 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } + fun themeCheckedTextView(vararg checkedTextViews: CheckedTextView) { + withScheme(checkedTextViews[0]) { scheme -> + val colorStateList = ColorStateList( + arrayOf( + intArrayOf(-android.R.attr.state_checked), + intArrayOf(-android.R.attr.state_enabled), + intArrayOf(android.R.attr.state_checked) + ), + intArrayOf(Color.GRAY, Color.GRAY, scheme.primary) + ) + checkedTextViews.forEach { + it.checkMarkTintList = colorStateList + } + } + } + fun themeCheckbox(vararg checkboxes: CheckBox) { withScheme(checkboxes[0]) { scheme -> val colorStateList = ColorStateList( diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index ac65f851..0897823c 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -175,7 +175,7 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva intArrayOf(-android.R.attr.state_enabled), intArrayOf(-android.R.attr.state_hovered), intArrayOf(-android.R.attr.state_focused), - intArrayOf(-android.R.attr.state_pressed), + intArrayOf(-android.R.attr.state_pressed) ), intArrayOf( scheme.outline, From f974f9b49ffd00ec58e031698370fc30dbd32283 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 27 Sep 2022 23:26:14 +0200 Subject: [PATCH 33/48] add color option for progress bar Signed-off-by: Andy Scherzinger --- .../common/ui/theme/utils/MaterialViewThemeUtils.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 0897823c..ef0f54cc 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -27,6 +27,7 @@ import android.content.Context import android.content.res.ColorStateList import android.graphics.Color import android.graphics.PorterDuff +import androidx.annotation.ColorInt import androidx.core.content.ContextCompat import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.button.MaterialButton @@ -240,10 +241,14 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorProgressBar(progressIndicator: LinearProgressIndicator) { withScheme(progressIndicator) { scheme -> - progressIndicator.setIndicatorColor(scheme.primary) + colorProgressBar(progressIndicator, scheme.primary) } } + fun colorProgressBar(progressIndicator: LinearProgressIndicator, @ColorInt color: Int) { + progressIndicator.setIndicatorColor(color) + } + fun colorTextInputLayout(textInputLayout: TextInputLayout) { withScheme(textInputLayout) { scheme -> val errorColor = scheme.onSurfaceVariant From 226ef60dd5e4878ba983cc187a29ac9c84c14382 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Thu, 29 Sep 2022 12:44:37 +0200 Subject: [PATCH 34/48] Add tonal button, cadview stroke coloring and onSecondaryContainer text theming Signed-off-by: Andy Scherzinger --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 6 ++ .../ui/theme/utils/MaterialViewThemeUtils.kt | 70 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index a79a9086..63a7f4dd 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -276,6 +276,12 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } + fun colorOnSecondaryContainerTextViewElement(textView: TextView) { + withScheme(textView) { scheme -> + textView.setTextColor(scheme.onSecondaryContainer) + } + } + fun colorPrimaryTextViewElementDarkMode(textView: TextView) { withSchemeDark { scheme -> textView.setTextColor(scheme.primary) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index ef0f54cc..7eda4b71 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -75,6 +75,18 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun themeCardView(cardView: MaterialCardView) { withScheme(cardView) { scheme -> cardView.backgroundTintList = ColorStateList.valueOf(scheme.surface) + cardView.setStrokeColor( + ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_checked), + intArrayOf(-android.R.attr.state_checked) + ), + intArrayOf( + scheme.primary, + scheme.outline + ) + ) + ) } } @@ -146,6 +158,64 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva } } + fun colorMaterialButtonPrimaryTonal(button: MaterialButton) { + withScheme(button) { scheme -> + button.backgroundTintList = + ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_hovered), + intArrayOf(-android.R.attr.state_focused), + intArrayOf(-android.R.attr.state_pressed) + ), + intArrayOf( + scheme.secondaryContainer, + colorUtil.adjustOpacity(scheme.onSurface, SURFACE_OPACITY_BUTTON_DISABLED), + scheme.onSecondaryContainer, + scheme.onSecondaryContainer, + scheme.onSecondaryContainer + ) + ) + + button.setTextColor( + ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_hovered), + intArrayOf(-android.R.attr.state_focused), + intArrayOf(-android.R.attr.state_pressed) + ), + intArrayOf( + scheme.onSecondaryContainer, + colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED), + scheme.onSecondaryContainer, + scheme.onSecondaryContainer, + scheme.onSecondaryContainer + ) + ) + ) + + button.iconTint = ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_hovered), + intArrayOf(-android.R.attr.state_focused), + intArrayOf(-android.R.attr.state_pressed) + ), + intArrayOf( + scheme.onSecondaryContainer, + colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED), + scheme.onSecondaryContainer, + scheme.onSecondaryContainer, + scheme.onSecondaryContainer + ) + ) + } + } + fun colorMaterialButtonPrimaryOutlined(button: MaterialButton) { withScheme(button) { scheme -> button.setTextColor( From e0f9bca76125d46cf7c1a7e2d32568ab9f97bee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Mon, 3 Oct 2022 12:16:55 +0200 Subject: [PATCH 35/48] Introduce ColorRole abstraction to deduplicate logic while allowing customization of colors when calling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 83 ++++++++--- .../common/ui/theme/utils/ColorRole.kt | 36 +++++ .../ui/theme/utils/MaterialViewThemeUtils.kt | 137 +++++++++++------- 3 files changed, 184 insertions(+), 72 deletions(-) create mode 100644 ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/ColorRole.kt diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 63a7f4dd..8ec92544 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -71,9 +71,10 @@ import javax.inject.Inject class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, private val colorUtil: ColorUtil) : ViewThemeUtilsBase(schemes) { - fun colorViewBackground(view: View) { + @JvmOverloads + fun colorViewBackground(view: View, colorRole: ColorRole = ColorRole.SURFACE) { withScheme(view) { scheme -> - view.setBackgroundColor(scheme.surface) + view.setBackgroundColor(colorRole.select(scheme)) } } @@ -147,24 +148,52 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat item.title = newItemTitle } + @JvmOverloads + fun tintDrawable(context: Context, @DrawableRes id: Int, colorRole: ColorRole = ColorRole.PRIMARY): Drawable? { + val drawable = ResourcesCompat.getDrawable(context.resources, id, null) + return drawable?.let { + tintDrawable(context, it, colorRole) + } + } + + @Deprecated( + replaceWith = ReplaceWith( + "tintDrawable(context, id, ColorRole.PRIMARY)", + imports = ["com.nextcloud.android.common.ui.theme.utils.ColorRole"] + ), + message = "Use tintDrawable(context, id, ColorRole.PRIMARY) instead" + ) fun tintPrimaryDrawable(context: Context, @DrawableRes id: Int): Drawable? { - return tintPrimaryDrawable(context, ResourcesCompat.getDrawable(context.resources, id, null)) + return tintDrawable(context, id, ColorRole.PRIMARY) } - fun tintPrimaryDrawable(context: Context, drawable: Drawable?): Drawable? { - return drawable?.let { - withScheme(context) { scheme: Scheme -> - tintDrawable(it, scheme.primary) - } + @JvmOverloads + fun tintDrawable(context: Context, drawable: Drawable, colorRole: ColorRole = ColorRole.PRIMARY): Drawable { + return withScheme(context) { scheme: Scheme -> + tintDrawable(drawable, colorRole.select(scheme)) } } + @Deprecated( + replaceWith = ReplaceWith( + "tintDrawable(context, drawable, ColorRole.PRIMARY)", + imports = ["com.nextcloud.android.common.ui.theme.utils.ColorRole"] + ), + message = "Use tintDrawable(context, drawable, ColorRole.PRIMARY) instead" + ) + fun tintPrimaryDrawable(context: Context, drawable: Drawable?): Drawable? { + return drawable?.let { tintDrawable(context, it, ColorRole.PRIMARY) } + } + + @Deprecated( + replaceWith = ReplaceWith( + "tintDrawable(context, drawable, ColorRole.ON_SURFACE)", + imports = ["com.nextcloud.android.common.ui.theme.utils.ColorRole"] + ), + message = "Use tintDrawable(context, drawable, ColorRole.ON_SURFACE) instead" + ) fun tintTextDrawable(context: Context, drawable: Drawable?): Drawable? { - return drawable?.let { - withScheme(context) { scheme: Scheme -> - tintDrawable(it, scheme.onSurface) - } - } + return drawable?.let { tintDrawable(context, it, ColorRole.ON_SURFACE) } } internal fun tintDrawable(drawable: Drawable, @ColorInt color: Int): Drawable { @@ -270,16 +299,30 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat progressBar?.progressDrawable?.setColorFilter(color, PorterDuff.Mode.SRC_IN) } - fun colorPrimaryTextViewElement(textView: TextView) { + @JvmOverloads + fun colorTextView(textView: TextView, colorRole: ColorRole = ColorRole.PRIMARY) { withScheme(textView) { scheme -> - textView.setTextColor(scheme.primary) + textView.setTextColor(colorRole.select(scheme)) } } + @Deprecated( + replaceWith = ReplaceWith("colorTextView(textView)"), + message = "Use colorTextView(textView) instead" + ) + fun colorPrimaryTextViewElement(textView: TextView) { + colorTextView(textView, ColorRole.PRIMARY) + } + + @Deprecated( + replaceWith = ReplaceWith( + "colorTextView(textView, ColorRole.ON_SECONDARY_CONTAINER)", + imports = ["com.nextcloud.android.common.ui.theme.utils.ColorRole"] + ), + message = "Use colorTextView(textView, ColorRole.ON_SECONDARY_CONTAINER) instead" + ) fun colorOnSecondaryContainerTextViewElement(textView: TextView) { - withScheme(textView) { scheme -> - textView.setTextColor(scheme.onSecondaryContainer) - } + colorTextView(textView, ColorRole.ON_SECONDARY_CONTAINER) } fun colorPrimaryTextViewElementDarkMode(textView: TextView) { @@ -288,6 +331,10 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } + @Deprecated( + replaceWith = ReplaceWith("colorViewBackground(view)"), + message = "Use colorViewBackground(view) instead" + ) fun colorPrimaryView(view: View) { withScheme(view) { scheme -> view.setBackgroundColor(scheme.primary) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/ColorRole.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/ColorRole.kt new file mode 100644 index 00000000..454aba86 --- /dev/null +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/ColorRole.kt @@ -0,0 +1,36 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.nextcloud.android.common.ui.theme.utils + +import scheme.Scheme + +/** + * Parameter for library methods so that clients can choose color roles without accessing the Scheme directly + */ +enum class ColorRole(internal val select: (Scheme) -> Int) { + ON_PRIMARY({ it.onPrimary }), + ON_SECONDARY_CONTAINER({ it.onSecondaryContainer }), + ON_SURFACE({ it.onSurface }), + PRIMARY({ it.primary }), + SURFACE({ it.surface }) +} diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 7eda4b71..88547afa 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -132,20 +132,7 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva ) ) - button.setTextColor( - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( - scheme.onPrimary, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) - ) - ) - ) - - button.iconTint = ColorStateList( + val contentColorList = ColorStateList( arrayOf( intArrayOf(android.R.attr.state_enabled), intArrayOf(-android.R.attr.state_enabled) @@ -155,6 +142,9 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) ) ) + + button.setTextColor(contentColorList) + button.iconTint = contentColorList } } @@ -178,26 +168,7 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva ) ) - button.setTextColor( - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_hovered), - intArrayOf(-android.R.attr.state_focused), - intArrayOf(-android.R.attr.state_pressed) - ), - intArrayOf( - scheme.onSecondaryContainer, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED), - scheme.onSecondaryContainer, - scheme.onSecondaryContainer, - scheme.onSecondaryContainer - ) - ) - ) - - button.iconTint = ColorStateList( + val contentColorList = ColorStateList( arrayOf( intArrayOf(android.R.attr.state_enabled), intArrayOf(-android.R.attr.state_enabled), @@ -213,24 +184,14 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva scheme.onSecondaryContainer ) ) + button.setTextColor(contentColorList) + button.iconTint = contentColorList } } fun colorMaterialButtonPrimaryOutlined(button: MaterialButton) { withScheme(button) { scheme -> - button.setTextColor( - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( - scheme.primary, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) - ) - ) - ) - button.iconTint = ColorStateList( + val contentColorList = ColorStateList( arrayOf( intArrayOf(android.R.attr.state_enabled), intArrayOf(-android.R.attr.state_enabled) @@ -240,6 +201,8 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) ) ) + button.setTextColor(contentColorList) + button.iconTint = contentColorList button.strokeColor = ColorStateList( arrayOf( intArrayOf(android.R.attr.state_enabled), @@ -270,26 +233,92 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorMaterialButtonPrimaryBorderless(button: MaterialButton) { withScheme(button) { scheme -> - button.setTextColor( + val contentColorList = ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_enabled) + ), + intArrayOf( + scheme.primary, + colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) + ) + ) + button.setTextColor(contentColorList) + button.iconTint = contentColorList + } + } + + /** + * text is primary, background is on_primary + */ + fun colorMaterialButtonFilledOnPrimary(button: MaterialButton) { + withScheme(button) { scheme -> + button.backgroundTintList = ColorStateList( arrayOf( intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) + intArrayOf(-android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_hovered), + intArrayOf(-android.R.attr.state_focused), + intArrayOf(-android.R.attr.state_pressed) ), intArrayOf( - scheme.primary, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) + scheme.onPrimary, + colorUtil.adjustOpacity(scheme.surface, SURFACE_OPACITY_BUTTON_DISABLED), + scheme.onPrimary, + scheme.onPrimary, + scheme.onPrimary ) ) + + val contentColorList = ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_hovered), + intArrayOf(-android.R.attr.state_focused), + intArrayOf(-android.R.attr.state_pressed) + ), + intArrayOf( + scheme.primary, + colorUtil.adjustOpacity(scheme.primary, ON_SURFACE_OPACITY_BUTTON_DISABLED), + scheme.primary, + scheme.primary, + scheme.primary + ) ) - button.iconTint = ColorStateList( + + button.setTextColor( + contentColorList + ) + + button.iconTint = contentColorList + } + } + + fun colorMaterialButtonOutlinedOnPrimary(button: MaterialButton) { + withScheme(button) { scheme -> + button.backgroundTintList = ColorStateList.valueOf(Color.TRANSPARENT) + val contentColorList = ColorStateList( arrayOf( intArrayOf(android.R.attr.state_enabled), intArrayOf(-android.R.attr.state_enabled) ), intArrayOf( - scheme.primary, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) + scheme.onPrimary, + colorUtil.adjustOpacity(scheme.onPrimary, ON_SURFACE_OPACITY_BUTTON_DISABLED) + ) + ) + button.setTextColor(contentColorList) + button.iconTint = contentColorList + button.strokeColor = contentColorList + button.strokeWidth = button.resources.getDimension(R.dimen.outlinedButtonStrokeWidth).toInt() + button.rippleColor = ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_pressed) + ), + intArrayOf( + colorUtil.adjustOpacity(scheme.primary, SURFACE_OPACITY_BUTTON_DISABLED) ) ) } From 10a5159864e3e851a9246c692abee37600b589b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Mon, 3 Oct 2022 16:47:29 +0200 Subject: [PATCH 36/48] ui: Add function to theme notification builder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../common/ui/theme/utils/AndroidXViewThemeUtils.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt index 9f98c3cf..e6373114 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt @@ -38,6 +38,7 @@ import androidx.appcompat.app.ActionBar import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SwitchCompat +import androidx.core.app.NotificationCompat import androidx.core.content.res.ResourcesCompat import androidx.core.widget.TextViewCompat import androidx.swiperefreshlayout.widget.SwipeRefreshLayout @@ -138,6 +139,12 @@ class AndroidXViewThemeUtils @Inject constructor( } } + fun themeNotificationCompatBuilder(context: Context, builder: NotificationCompat.Builder) { + withScheme(context) { scheme -> + builder.setColor(scheme.primary) + } + } + private fun setColoredTitle( actionBar: ActionBar, title: String, From 87322df2e9a428000dba431dedcd381dca8b3d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Mon, 3 Oct 2022 17:38:13 +0200 Subject: [PATCH 37/48] ui: add utilities to tint platform Switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shares most code with SwitchCompat but is not interface-compatible Signed-off-by: Álvaro Brey --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 13 ++++ .../ui/theme/utils/AndroidXViewThemeUtils.kt | 39 +--------- .../common/ui/theme/utils/SwitchColorUtils.kt | 74 +++++++++++++++++++ 3 files changed, 90 insertions(+), 36 deletions(-) create mode 100644 ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/SwitchColorUtils.kt diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 8ec92544..4944e059 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -23,6 +23,7 @@ package com.nextcloud.android.common.ui.theme.utils +import android.annotation.SuppressLint import android.app.Activity import android.content.Context import android.content.res.ColorStateList @@ -47,6 +48,7 @@ import android.widget.ImageView import android.widget.ProgressBar import android.widget.RadioButton import android.widget.SeekBar +import android.widget.Switch import android.widget.TextView import androidx.annotation.ColorInt import androidx.annotation.DrawableRes @@ -547,6 +549,17 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } while (index != -1) } + // here for backwards compatibility + @SuppressLint("UseSwitchCompatOrMaterialCode") + fun colorSwitch(switch: Switch) { + withScheme(switch) { scheme -> + val colors = SwitchColorUtils.calculateSwitchColors(switch.context, scheme) + DrawableCompat.setTintList(switch.thumbDrawable, colors.thumbColor) + DrawableCompat.setTintList(switch.trackDrawable, colors.trackColor) + } + } + + @Deprecated("Don't do this, implement custom viewthemeutils instead") fun primaryColor(activity: Activity): Int { return withScheme(activity) { scheme -> scheme.primary diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt index e6373114..9d0a6d03 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt @@ -25,7 +25,6 @@ package com.nextcloud.android.common.ui.theme.utils import android.content.Context import android.content.res.ColorStateList -import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.text.Spannable @@ -39,7 +38,6 @@ import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SwitchCompat import androidx.core.app.NotificationCompat -import androidx.core.content.res.ResourcesCompat import androidx.core.widget.TextViewCompat import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.nextcloud.android.common.ui.R @@ -59,36 +57,9 @@ class AndroidXViewThemeUtils @Inject constructor( fun colorSwitchCompat(switchCompat: SwitchCompat) { withScheme(switchCompat) { scheme -> - - val context = switchCompat.context - - val thumbUncheckedColor = ResourcesCompat.getColor( - context.resources, - R.color.switch_thumb_color_unchecked, - context.theme - ) - val trackUncheckedColor = ResourcesCompat.getColor( - context.resources, - R.color.switch_track_color_unchecked, - context.theme - ) - - val trackColor = Color.argb( - SWITCH_COMPAT_TRACK_ALPHA, - Color.red(scheme.primary), - Color.green(scheme.primary), - Color.blue(scheme.primary) - ) - - switchCompat.thumbTintList = ColorStateList( - arrayOf(intArrayOf(android.R.attr.state_checked), intArrayOf()), - intArrayOf(scheme.primary, thumbUncheckedColor) - ) - - switchCompat.trackTintList = ColorStateList( - arrayOf(intArrayOf(android.R.attr.state_checked), intArrayOf()), - intArrayOf(trackColor, trackUncheckedColor) - ) + val colors = SwitchColorUtils.calculateSwitchColors(switchCompat.context, scheme) + switchCompat.thumbTintList = colors.thumbColor + switchCompat.trackTintList = colors.trackColor } } @@ -159,8 +130,4 @@ class AndroidXViewThemeUtils @Inject constructor( ) actionBar.title = text } - - companion object { - private const val SWITCH_COMPAT_TRACK_ALPHA: Int = 77 - } } diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/SwitchColorUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/SwitchColorUtils.kt new file mode 100644 index 00000000..dbed2a0e --- /dev/null +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/SwitchColorUtils.kt @@ -0,0 +1,74 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.nextcloud.android.common.ui.theme.utils + +import android.content.Context +import android.content.res.ColorStateList +import android.graphics.Color +import androidx.core.content.res.ResourcesCompat +import com.nextcloud.android.common.ui.R +import scheme.Scheme + +/** + * To be used to calculate color lists for both Switch and SwitchCompat + */ +object SwitchColorUtils { + + private const val SWITCH_COMPAT_TRACK_ALPHA: Int = 77 + + data class SwitchColors( + val thumbColor: ColorStateList, + val trackColor: ColorStateList + ) + + fun calculateSwitchColors(context: Context, scheme: Scheme): SwitchColors { + val thumbUncheckedColor = ResourcesCompat.getColor( + context.resources, + R.color.switch_thumb_color_unchecked, + context.theme + ) + val trackUncheckedColor = ResourcesCompat.getColor( + context.resources, + R.color.switch_track_color_unchecked, + context.theme + ) + + val trackColor = Color.argb( + SWITCH_COMPAT_TRACK_ALPHA, + Color.red(scheme.primary), + Color.green(scheme.primary), + Color.blue(scheme.primary) + ) + + return SwitchColors( + thumbColor = ColorStateList( + arrayOf(intArrayOf(android.R.attr.state_checked), intArrayOf()), + intArrayOf(scheme.primary, thumbUncheckedColor) + ), + trackColor = ColorStateList( + arrayOf(intArrayOf(android.R.attr.state_checked), intArrayOf()), + intArrayOf(trackColor, trackUncheckedColor) + ) + ) + } +} From ae9ca8b9116447cf4f9c5cd907811845a4965418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 4 Oct 2022 13:13:45 +0200 Subject: [PATCH 38/48] Rework status bar coloring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for special cases Signed-off-by: Álvaro Brey --- .../android/common/ui/color/ColorUtil.kt | 12 ++++--- .../ui/theme/utils/AndroidViewThemeUtils.kt | 34 ++++++------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt b/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt index d2c02cd2..ae89a4e6 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt @@ -51,16 +51,20 @@ class ColorUtil @Inject constructor(private val context: Context) { @ColorInt fun getForegroundColorForBackgroundColor(@ColorInt color: Int): Int { - val hsl = FloatArray(HSL_SIZE) - ColorUtils.RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hsl) - - return if (hsl[INDEX_LIGHTNESS] < LIGHTNESS_DARK_THRESHOLD) { + return if (isDarkBackground(color)) { Color.WHITE } else { ContextCompat.getColor(context, R.color.grey_900) } } + fun isDarkBackground(@ColorInt color: Int): Boolean { + val hsl = FloatArray(HSL_SIZE) + ColorUtils.RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hsl) + + return hsl[INDEX_LIGHTNESS] < LIGHTNESS_DARK_THRESHOLD + } + fun setLightness(@ColorInt color: Int, lightness: Float): Int { require(lightness in 0.0..1.0) { "Lightness must be between 0 and 1" } val hsl = FloatArray(HSL_SIZE) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 4944e059..a3275b07 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -32,7 +32,6 @@ import android.graphics.PorterDuff import android.graphics.Typeface import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable -import android.os.Build import android.text.Spannable import android.text.SpannableString import android.text.style.ForegroundColorSpan @@ -57,12 +56,12 @@ import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.BlendModeColorFilterCompat import androidx.core.graphics.BlendModeCompat import androidx.core.graphics.drawable.DrawableCompat +import androidx.core.view.WindowInsetsControllerCompat import com.google.android.material.navigation.NavigationView import com.nextcloud.android.common.ui.R import com.nextcloud.android.common.ui.color.ColorUtil import com.nextcloud.android.common.ui.theme.MaterialSchemes import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase -import com.nextcloud.android.common.ui.util.PlatformThemeUtil import scheme.Scheme import javax.inject.Inject @@ -228,34 +227,23 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat fun themeStatusBar(activity: Activity) { withScheme(activity) { scheme -> - applyColorToStatusBar(activity, scheme.surface) + colorStatusBar(activity, scheme.surface) } } - private fun applyColorToStatusBar(activity: Activity, @ColorInt color: Int) { + /** + * Public for special cases, e.g. action mode. You probably want [themeStatusBar] for most cases instead. + */ + fun colorStatusBar(activity: Activity, @ColorInt color: Int) { val window = activity.window ?: return - val isLightTheme = !PlatformThemeUtil.isDarkMode(activity) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - val decor = window.decorView - if (isLightTheme) { - val systemUiFlagLightStatusBar = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or - View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR - } else { - View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR - } - decor.systemUiVisibility = systemUiFlagLightStatusBar - } else { - decor.systemUiVisibility = 0 - } - window.statusBarColor = color - } else if (isLightTheme) { - window.statusBarColor = Color.BLACK - } + val isLightBackground = !colorUtil.isDarkBackground(color) + val decor = window.decorView + window.statusBarColor = color + WindowInsetsControllerCompat(window, decor).isAppearanceLightStatusBars = isLightBackground } fun resetStatusBar(activity: Activity) { - applyColorToStatusBar( + colorStatusBar( activity, ResourcesCompat.getColor( activity.resources, From 071ec0ba2fa62e502ea094d1d93076cdcb32c163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 4 Oct 2022 13:29:35 +0200 Subject: [PATCH 39/48] PlatformThemeUtil: make isDarkMode accessible from Java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../com/nextcloud/android/common/ui/util/PlatformThemeUtil.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/util/PlatformThemeUtil.kt b/ui/src/main/java/com/nextcloud/android/common/ui/util/PlatformThemeUtil.kt index 973eea93..04603205 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/util/PlatformThemeUtil.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/util/PlatformThemeUtil.kt @@ -25,6 +25,7 @@ import android.content.Context import android.content.res.Configuration object PlatformThemeUtil { + @JvmStatic fun isDarkMode(context: Context): Boolean = when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) { Configuration.UI_MODE_NIGHT_YES -> true From 6d96f4c5573698b29842cd8de853ecb5a5b7a31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 4 Oct 2022 16:10:16 +0200 Subject: [PATCH 40/48] Some more drawable coloring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 7 +++++-- .../ui/theme/utils/AndroidXViewThemeUtils.kt | 20 ++++++++++--------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index a3275b07..6bf6dc57 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -171,7 +171,7 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat @JvmOverloads fun tintDrawable(context: Context, drawable: Drawable, colorRole: ColorRole = ColorRole.PRIMARY): Drawable { return withScheme(context) { scheme: Scheme -> - tintDrawable(drawable, colorRole.select(scheme)) + colorDrawable(drawable, colorRole.select(scheme)) } } @@ -197,7 +197,10 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat return drawable?.let { tintDrawable(context, it, ColorRole.ON_SURFACE) } } - internal fun tintDrawable(drawable: Drawable, @ColorInt color: Int): Drawable { + /** + * Public for edge cases. For most cases use [tintDrawable] instead + */ + fun colorDrawable(drawable: Drawable, @ColorInt color: Int): Drawable { val wrap = DrawableCompat.wrap(drawable) wrap.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat( color, diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt index 9d0a6d03..b35a3661 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt @@ -32,7 +32,6 @@ import android.text.SpannableString import android.text.style.ForegroundColorSpan import android.widget.ImageView import android.widget.LinearLayout -import androidx.annotation.ColorInt import androidx.appcompat.app.ActionBar import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.SearchView @@ -80,7 +79,8 @@ class AndroidXViewThemeUtils @Inject constructor( // TODO host the back arrow in this lib instead of passing it everywhere fun themeActionBar(context: Context, actionBar: ActionBar, title: String, backArrow: Drawable) { withScheme(context) { scheme -> - setColoredTitle(actionBar, title, scheme.onSurface) + val text: Spannable = getColoredSpan(title, scheme.onSurface) + actionBar.title = text themeActionBar(context, actionBar, backArrow) } } @@ -88,11 +88,17 @@ class AndroidXViewThemeUtils @Inject constructor( fun themeActionBar(context: Context, actionBar: ActionBar, backArrow: Drawable) { withScheme(context) { scheme -> actionBar.setBackgroundDrawable(ColorDrawable(scheme.surface)) - val indicator = androidViewThemeUtils.tintDrawable(backArrow, scheme.onSurface) + val indicator = androidViewThemeUtils.colorDrawable(backArrow, scheme.onSurface) actionBar.setHomeAsUpIndicator(indicator) } } + fun themeActionBarSubtitle(context: Context, actionBar: ActionBar) { + withScheme(context) { scheme -> + actionBar.subtitle = getColoredSpan(actionBar.subtitle.toString(), scheme.onSurfaceVariant) + } + } + fun themeToolbarSearchView(searchView: SearchView) { withScheme(searchView) { scheme -> // hacky as no default way is provided @@ -116,11 +122,7 @@ class AndroidXViewThemeUtils @Inject constructor( } } - private fun setColoredTitle( - actionBar: ActionBar, - title: String, - @ColorInt color: Int - ) { + private fun getColoredSpan(title: String, color: Int): Spannable { val text: Spannable = SpannableString(title) text.setSpan( ForegroundColorSpan(color), @@ -128,6 +130,6 @@ class AndroidXViewThemeUtils @Inject constructor( text.length, Spannable.SPAN_INCLUSIVE_INCLUSIVE ) - actionBar.title = text + return text } } From 40bf8e81691d4e620c06820091b65ec6242a932c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 4 Oct 2022 16:32:52 +0200 Subject: [PATCH 41/48] AndroidViewThemeUtils: fix navbar colors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../android/common/ui/theme/utils/AndroidViewThemeUtils.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 6bf6dc57..87c1b7af 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -242,7 +242,9 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat val isLightBackground = !colorUtil.isDarkBackground(color) val decor = window.decorView window.statusBarColor = color + window.navigationBarColor = color WindowInsetsControllerCompat(window, decor).isAppearanceLightStatusBars = isLightBackground + WindowInsetsControllerCompat(window, decor).isAppearanceLightNavigationBars = isLightBackground } fun resetStatusBar(activity: Activity) { From d677e4bffb341ea935b509bc3586e76286008e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Wed, 5 Oct 2022 10:46:18 +0200 Subject: [PATCH 42/48] ui: mark SwitchColorUtils as internal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../nextcloud/android/common/ui/theme/utils/SwitchColorUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/SwitchColorUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/SwitchColorUtils.kt index dbed2a0e..8de89a5c 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/SwitchColorUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/SwitchColorUtils.kt @@ -32,7 +32,7 @@ import scheme.Scheme /** * To be used to calculate color lists for both Switch and SwitchCompat */ -object SwitchColorUtils { +internal object SwitchColorUtils { private const val SWITCH_COMPAT_TRACK_ALPHA: Int = 77 From 83ffde8817dd1eedb24d5567e7794d3591cbd492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Mon, 10 Oct 2022 17:39:29 +0200 Subject: [PATCH 43/48] ColorUtil: add utility function to convert color to hex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../java/com/nextcloud/android/common/ui/color/ColorUtil.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt b/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt index ae89a4e6..2aba757b 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/color/ColorUtil.kt @@ -75,6 +75,10 @@ class ColorUtil @Inject constructor(private val context: Context) { return ColorUtils.HSLToColor(hsl) } + fun colorToHexString(@ColorInt color: Int): String { + return String.format(null, "#%06X", HEX_WHITE and color) + } + @ColorInt private fun String?.parseColorOrFallback(fallback: () -> Int): Int { return if (this?.isNotBlank() == true) { @@ -98,5 +102,6 @@ class ColorUtil @Inject constructor(private val context: Context) { private const val HSL_SIZE: Int = 3 private const val INDEX_LIGHTNESS: Int = 2 private const val LIGHTNESS_DARK_THRESHOLD: Float = 0.6f + private const val HEX_WHITE = 0xFFFFFF } } From ba0730098dfbbca600dd3c5537b03480f8850ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Mon, 10 Oct 2022 20:49:12 +0200 Subject: [PATCH 44/48] Reduce a lot of boilerplate by creating a ColorStateList build function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../ui/theme/utils/AndroidViewThemeUtils.kt | 104 +++--- .../ui/theme/utils/MaterialViewThemeUtils.kt | 297 +++++++----------- .../common/ui/util/ColorStateListUtils.kt | 31 ++ 3 files changed, 180 insertions(+), 252 deletions(-) create mode 100644 ui/src/main/java/com/nextcloud/android/common/ui/util/ColorStateListUtils.kt diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt index 87c1b7af..aee8690e 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidViewThemeUtils.kt @@ -62,6 +62,7 @@ import com.nextcloud.android.common.ui.R import com.nextcloud.android.common.ui.color.ColorUtil import com.nextcloud.android.common.ui.theme.MaterialSchemes import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase +import com.nextcloud.android.common.ui.util.buildColorStateList import scheme.Scheme import javax.inject.Inject @@ -83,29 +84,17 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat withScheme(navigationView) { scheme -> if (navigationView.itemBackground != null) { navigationView.itemBackground!!.setTintList( - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_checked) - ), - intArrayOf( - scheme.secondaryContainer, - Color.TRANSPARENT - ) + buildColorStateList( + android.R.attr.state_checked to scheme.secondaryContainer, + -android.R.attr.state_checked to Color.TRANSPARENT ) ) } navigationView.setBackgroundColor(scheme.surface) - val colorStateList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_checked) - ), - intArrayOf( - scheme.onSecondaryContainer, - scheme.onSurfaceVariant - ) + val colorStateList = buildColorStateList( + android.R.attr.state_checked to scheme.onSecondaryContainer, + -android.R.attr.state_checked to scheme.onSurfaceVariant ) navigationView.itemTextColor = colorStateList @@ -360,18 +349,13 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat fun themeImageButton(imageButton: ImageButton) { withScheme(imageButton) { scheme -> - imageButton.imageTintList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_selected), - intArrayOf(-android.R.attr.state_selected), - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( - scheme.primary, - scheme.onSurfaceVariant, - scheme.onSurfaceVariant, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) + imageButton.imageTintList = buildColorStateList( + android.R.attr.state_selected to scheme.primary, + -android.R.attr.state_selected to scheme.onSurfaceVariant, + android.R.attr.state_enabled to scheme.onSurfaceVariant, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( + scheme.onSurface, + ON_SURFACE_OPACITY_BUTTON_DISABLED ) ) } @@ -406,14 +390,11 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat withScheme(buttons[0]) { scheme -> for (button in buttons) { button.setTextColor( - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( - color, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) + buildColorStateList( + android.R.attr.state_enabled to color, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( + scheme.onSurface, + ON_SURFACE_OPACITY_BUTTON_DISABLED ) ) ) @@ -441,14 +422,12 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat fun themeCheckedTextView(vararg checkedTextViews: CheckedTextView) { withScheme(checkedTextViews[0]) { scheme -> - val colorStateList = ColorStateList( - arrayOf( - intArrayOf(-android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_enabled), - intArrayOf(android.R.attr.state_checked) - ), - intArrayOf(Color.GRAY, Color.GRAY, scheme.primary) + val colorStateList = buildColorStateList( + -android.R.attr.state_checked to Color.GRAY, + -android.R.attr.state_enabled to Color.GRAY, + android.R.attr.state_checked to scheme.primary ) + checkedTextViews.forEach { it.checkMarkTintList = colorStateList } @@ -457,13 +436,10 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat fun themeCheckbox(vararg checkboxes: CheckBox) { withScheme(checkboxes[0]) { scheme -> - val colorStateList = ColorStateList( - arrayOf( - intArrayOf(-android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_enabled), - intArrayOf(android.R.attr.state_checked) - ), - intArrayOf(Color.GRAY, Color.GRAY, scheme.primary) + val colorStateList = buildColorStateList( + -android.R.attr.state_checked to Color.GRAY, + -android.R.attr.state_enabled to Color.GRAY, + android.R.attr.state_checked to scheme.primary ) checkboxes.forEach { it.buttonTintList = colorStateList @@ -473,12 +449,9 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat fun themeRadioButton(radioButton: RadioButton) { withScheme(radioButton) { scheme -> - radioButton.buttonTintList = ColorStateList( - arrayOf( - intArrayOf(-android.R.attr.state_checked), - intArrayOf(android.R.attr.state_checked) - ), - intArrayOf(Color.GRAY, scheme.primary) + radioButton.buttonTintList = buildColorStateList( + -android.R.attr.state_checked to Color.GRAY, + android.R.attr.state_checked to scheme.primary ) } } @@ -487,16 +460,11 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat withScheme(editText) { scheme -> // TODO check API-level compatibility // editText.background.setColorFilter(color, PorterDuff.Mode.SRC_ATOP) - editText.backgroundTintList = ColorStateList( - arrayOf( - intArrayOf(-android.R.attr.state_focused), - intArrayOf(android.R.attr.state_focused) - ), - intArrayOf( - scheme.outline, - scheme.primary - ) + editText.backgroundTintList = buildColorStateList( + -android.R.attr.state_focused to scheme.outline, + android.R.attr.state_focused to scheme.primary ) + editText.setHintTextColor(scheme.onSurfaceVariant) editText.setTextColor(scheme.onSurface) } @@ -552,7 +520,7 @@ class AndroidViewThemeUtils @Inject constructor(schemes: MaterialSchemes, privat } } - @Deprecated("Don't do this, implement custom viewthemeutils instead") + @Deprecated("Don't do this, implement custom viewThemeUtils instead") fun primaryColor(activity: Activity): Int { return withScheme(activity) { scheme -> scheme.primary diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 88547afa..cf3f96db 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -44,6 +44,7 @@ import com.nextcloud.android.common.ui.R import com.nextcloud.android.common.ui.color.ColorUtil import com.nextcloud.android.common.ui.theme.MaterialSchemes import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase +import com.nextcloud.android.common.ui.util.buildColorStateList import scheme.Scheme import javax.inject.Inject @@ -76,15 +77,9 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva withScheme(cardView) { scheme -> cardView.backgroundTintList = ColorStateList.valueOf(scheme.surface) cardView.setStrokeColor( - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_checked) - ), - intArrayOf( - scheme.primary, - scheme.outline - ) + buildColorStateList( + android.R.attr.state_checked to scheme.primary, + -android.R.attr.state_checked to scheme.outline ) ) } @@ -92,12 +87,10 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorMaterialTextButton(button: MaterialButton) { withScheme(button) { scheme -> - button.rippleColor = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_pressed) - ), - intArrayOf( - colorUtil.adjustOpacity(scheme.primary, SURFACE_OPACITY_BUTTON_DISABLED) + button.rippleColor = buildColorStateList( + android.R.attr.state_pressed to colorUtil.adjustOpacity( + scheme.primary, + SURFACE_OPACITY_BUTTON_DISABLED ) ) } @@ -106,12 +99,9 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorMaterialButtonText(button: MaterialButton) { withScheme(button) { scheme -> val disabledColor = ContextCompat.getColor(button.context, R.color.disabled_text) - val colorStateList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf(scheme.primary, disabledColor) + val colorStateList = buildColorStateList( + android.R.attr.state_enabled to scheme.primary, + -android.R.attr.state_enabled to disabledColor ) button.setTextColor(colorStateList) button.iconTint = colorStateList @@ -120,26 +110,19 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorMaterialButtonPrimaryFilled(button: MaterialButton) { withScheme(button) { scheme -> - button.backgroundTintList = - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( - scheme.primary, - colorUtil.adjustOpacity(scheme.onSurface, SURFACE_OPACITY_BUTTON_DISABLED) - ) + button.backgroundTintList = buildColorStateList( + android.R.attr.state_enabled to scheme.primary, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( + scheme.onSurface, + SURFACE_OPACITY_BUTTON_DISABLED ) + ) - val contentColorList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( - scheme.onPrimary, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) + val contentColorList = buildColorStateList( + android.R.attr.state_enabled to scheme.onPrimary, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( + scheme.onSurface, + SURFACE_OPACITY_BUTTON_DISABLED ) ) @@ -150,39 +133,26 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorMaterialButtonPrimaryTonal(button: MaterialButton) { withScheme(button) { scheme -> - button.backgroundTintList = - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_hovered), - intArrayOf(-android.R.attr.state_focused), - intArrayOf(-android.R.attr.state_pressed) - ), - intArrayOf( - scheme.secondaryContainer, - colorUtil.adjustOpacity(scheme.onSurface, SURFACE_OPACITY_BUTTON_DISABLED), - scheme.onSecondaryContainer, - scheme.onSecondaryContainer, - scheme.onSecondaryContainer - ) - ) + button.backgroundTintList = buildColorStateList( + android.R.attr.state_enabled to scheme.secondaryContainer, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( + scheme.onSurface, + SURFACE_OPACITY_BUTTON_DISABLED + ), + -android.R.attr.state_hovered to scheme.onSecondaryContainer, + -android.R.attr.state_focused to scheme.onSecondaryContainer, + -android.R.attr.state_pressed to scheme.onSecondaryContainer + ) - val contentColorList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_hovered), - intArrayOf(-android.R.attr.state_focused), - intArrayOf(-android.R.attr.state_pressed) + val contentColorList = buildColorStateList( + android.R.attr.state_enabled to scheme.onSecondaryContainer, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( + scheme.onSurface, + ON_SURFACE_OPACITY_BUTTON_DISABLED ), - intArrayOf( - scheme.onSecondaryContainer, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED), - scheme.onSecondaryContainer, - scheme.onSecondaryContainer, - scheme.onSecondaryContainer - ) + -android.R.attr.state_hovered to scheme.onSecondaryContainer, + -android.R.attr.state_focused to scheme.onSecondaryContainer, + -android.R.attr.state_pressed to scheme.onSecondaryContainer ) button.setTextColor(contentColorList) button.iconTint = contentColorList @@ -191,41 +161,33 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorMaterialButtonPrimaryOutlined(button: MaterialButton) { withScheme(button) { scheme -> - val contentColorList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( - scheme.primary, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) + val contentColorList = buildColorStateList( + android.R.attr.state_enabled to scheme.primary, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( + scheme.onSurface, + ON_SURFACE_OPACITY_BUTTON_DISABLED ) ) + button.setTextColor(contentColorList) button.iconTint = contentColorList - button.strokeColor = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_hovered), - intArrayOf(-android.R.attr.state_focused), - intArrayOf(-android.R.attr.state_pressed) + button.strokeColor = buildColorStateList( + android.R.attr.state_enabled to scheme.outline, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( + scheme.onSurface, + ON_SURFACE_OPACITY_BUTTON_OUTLINE_DISABLED ), - intArrayOf( - scheme.outline, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_OUTLINE_DISABLED), - scheme.outline, - scheme.primary, - scheme.outline - ) + -android.R.attr.state_hovered to scheme.outline, + -android.R.attr.state_focused to scheme.primary, + -android.R.attr.state_pressed to scheme.outline ) - button.strokeWidth = button.resources.getDimension(R.dimen.outlinedButtonStrokeWidth).toInt() - button.rippleColor = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_pressed) - ), - intArrayOf( - colorUtil.adjustOpacity(scheme.primary, SURFACE_OPACITY_BUTTON_DISABLED) + + button.strokeWidth = + button.resources.getDimension(R.dimen.outlinedButtonStrokeWidth).toInt() + button.rippleColor = buildColorStateList( + android.R.attr.state_pressed to colorUtil.adjustOpacity( + scheme.primary, + SURFACE_OPACITY_BUTTON_DISABLED ) ) } @@ -233,16 +195,14 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorMaterialButtonPrimaryBorderless(button: MaterialButton) { withScheme(button) { scheme -> - val contentColorList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( - scheme.primary, - colorUtil.adjustOpacity(scheme.onSurface, ON_SURFACE_OPACITY_BUTTON_DISABLED) + val contentColorList = buildColorStateList( + android.R.attr.state_enabled to scheme.primary, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( + scheme.onSurface, + ON_SURFACE_OPACITY_BUTTON_DISABLED ) ) + button.setTextColor(contentColorList) button.iconTint = contentColorList } @@ -253,39 +213,26 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva */ fun colorMaterialButtonFilledOnPrimary(button: MaterialButton) { withScheme(button) { scheme -> - button.backgroundTintList = - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_hovered), - intArrayOf(-android.R.attr.state_focused), - intArrayOf(-android.R.attr.state_pressed) - ), - intArrayOf( - scheme.onPrimary, - colorUtil.adjustOpacity(scheme.surface, SURFACE_OPACITY_BUTTON_DISABLED), - scheme.onPrimary, - scheme.onPrimary, - scheme.onPrimary - ) - ) - - val contentColorList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_hovered), - intArrayOf(-android.R.attr.state_focused), - intArrayOf(-android.R.attr.state_pressed) + button.backgroundTintList = buildColorStateList( + android.R.attr.state_enabled to scheme.onPrimary, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( + scheme.surface, + SURFACE_OPACITY_BUTTON_DISABLED ), - intArrayOf( - scheme.primary, - colorUtil.adjustOpacity(scheme.primary, ON_SURFACE_OPACITY_BUTTON_DISABLED), - scheme.primary, + -android.R.attr.state_hovered to scheme.onPrimary, + -android.R.attr.state_focused to scheme.onPrimary, + -android.R.attr.state_pressed to scheme.onPrimary + ) + + val contentColorList = buildColorStateList( + android.R.attr.state_enabled to scheme.primary, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( scheme.primary, - scheme.primary - ) + ON_SURFACE_OPACITY_BUTTON_DISABLED + ), + -android.R.attr.state_hovered to scheme.primary, + -android.R.attr.state_focused to scheme.primary, + -android.R.attr.state_pressed to scheme.primary ) button.setTextColor( @@ -299,26 +246,23 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorMaterialButtonOutlinedOnPrimary(button: MaterialButton) { withScheme(button) { scheme -> button.backgroundTintList = ColorStateList.valueOf(Color.TRANSPARENT) - val contentColorList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( + val contentColorList = buildColorStateList( + android.R.attr.state_enabled to scheme.onPrimary, + -android.R.attr.state_enabled to colorUtil.adjustOpacity( scheme.onPrimary, - colorUtil.adjustOpacity(scheme.onPrimary, ON_SURFACE_OPACITY_BUTTON_DISABLED) + ON_SURFACE_OPACITY_BUTTON_DISABLED ) ) + button.setTextColor(contentColorList) button.iconTint = contentColorList button.strokeColor = contentColorList - button.strokeWidth = button.resources.getDimension(R.dimen.outlinedButtonStrokeWidth).toInt() - button.rippleColor = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_pressed) - ), - intArrayOf( - colorUtil.adjustOpacity(scheme.primary, SURFACE_OPACITY_BUTTON_DISABLED) + button.strokeWidth = + button.resources.getDimension(R.dimen.outlinedButtonStrokeWidth).toInt() + button.rippleColor = buildColorStateList( + android.R.attr.state_pressed to colorUtil.adjustOpacity( + scheme.primary, + SURFACE_OPACITY_BUTTON_DISABLED ) ) } @@ -352,25 +296,14 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva withScheme(textInputLayout) { scheme -> val errorColor = scheme.onSurfaceVariant - val errorColorStateList = ColorStateList( - arrayOf( - intArrayOf(-android.R.attr.state_focused), - intArrayOf(android.R.attr.state_focused) - ), - intArrayOf( - errorColor, - errorColor - ) + val errorColorStateList = buildColorStateList( + -android.R.attr.state_focused to errorColor, + android.R.attr.state_focused to errorColor ) - val coloredColorStateList = ColorStateList( - arrayOf( - intArrayOf(-android.R.attr.state_focused), - intArrayOf(android.R.attr.state_focused) - ), - intArrayOf( - scheme.outline, - scheme.primary - ) + + val coloredColorStateList = buildColorStateList( + -android.R.attr.state_focused to scheme.outline, + android.R.attr.state_focused to scheme.primary ) textInputLayout.setBoxStrokeColorStateList(coloredColorStateList) @@ -398,24 +331,20 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorTabLayout(tabLayout: TabLayout, scheme: Scheme) { tabLayout.setSelectedTabIndicatorColor(scheme.primary) - val tabContentColors = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_selected), - intArrayOf(-android.R.attr.state_selected) - ), - intArrayOf( - scheme.primary, - ContextCompat.getColor(tabLayout.context, R.color.high_emphasis_text) + val tabContentColors = buildColorStateList( + android.R.attr.state_selected to scheme.primary, + -android.R.attr.state_selected to ContextCompat.getColor( + tabLayout.context, + R.color.high_emphasis_text ) ) + tabLayout.tabTextColors = tabContentColors tabLayout.tabIconTint = tabContentColors - tabLayout.tabRippleColor = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_pressed) - ), - intArrayOf( - colorUtil.adjustOpacity(scheme.primary, SURFACE_OPACITY_BUTTON_DISABLED) + tabLayout.tabRippleColor = buildColorStateList( + android.R.attr.state_pressed to colorUtil.adjustOpacity( + scheme.primary, + SURFACE_OPACITY_BUTTON_DISABLED ) ) } diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/util/ColorStateListUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/util/ColorStateListUtils.kt new file mode 100644 index 00000000..05ea3ae8 --- /dev/null +++ b/ui/src/main/java/com/nextcloud/android/common/ui/util/ColorStateListUtils.kt @@ -0,0 +1,31 @@ +/* + * Nextcloud Android Common Library + * + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.android.common.ui.util + +import android.content.res.ColorStateList + +/** + * First element of each pair is @AttRes (can be negated) and second one is @ColorInt + */ +fun buildColorStateList(vararg pairs: Pair): ColorStateList { + val stateArray = pairs.map { intArrayOf(it.first) }.toTypedArray() + val colorArray = pairs.map { it.second }.toIntArray() + return ColorStateList(stateArray, colorArray) +} From 1f49e6a45f33be907ad0cb733b5f0d6a09085820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 11 Oct 2022 14:21:52 +0200 Subject: [PATCH 45/48] MaterialViewThemeUtils: deduplicate ripple color MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../ui/theme/utils/MaterialViewThemeUtils.kt | 35 ++++++------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index cf3f96db..da50e71e 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -87,12 +87,7 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun colorMaterialTextButton(button: MaterialButton) { withScheme(button) { scheme -> - button.rippleColor = buildColorStateList( - android.R.attr.state_pressed to colorUtil.adjustOpacity( - scheme.primary, - SURFACE_OPACITY_BUTTON_DISABLED - ) - ) + button.rippleColor = rippleColor(scheme) } } @@ -184,12 +179,7 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva button.strokeWidth = button.resources.getDimension(R.dimen.outlinedButtonStrokeWidth).toInt() - button.rippleColor = buildColorStateList( - android.R.attr.state_pressed to colorUtil.adjustOpacity( - scheme.primary, - SURFACE_OPACITY_BUTTON_DISABLED - ) - ) + button.rippleColor = rippleColor(scheme) } } @@ -259,12 +249,7 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva button.strokeColor = contentColorList button.strokeWidth = button.resources.getDimension(R.dimen.outlinedButtonStrokeWidth).toInt() - button.rippleColor = buildColorStateList( - android.R.attr.state_pressed to colorUtil.adjustOpacity( - scheme.primary, - SURFACE_OPACITY_BUTTON_DISABLED - ) - ) + button.rippleColor = rippleColor(scheme) } } @@ -341,12 +326,7 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva tabLayout.tabTextColors = tabContentColors tabLayout.tabIconTint = tabContentColors - tabLayout.tabRippleColor = buildColorStateList( - android.R.attr.state_pressed to colorUtil.adjustOpacity( - scheme.primary, - SURFACE_OPACITY_BUTTON_DISABLED - ) - ) + tabLayout.tabRippleColor = rippleColor(scheme) } fun colorChipBackground(chip: Chip) { @@ -380,6 +360,13 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva } } + private fun rippleColor(scheme: Scheme) = buildColorStateList( + android.R.attr.state_pressed to colorUtil.adjustOpacity( + scheme.primary, + SURFACE_OPACITY_BUTTON_DISABLED + ) + ) + companion object { private const val SURFACE_OPACITY_BUTTON_DISABLED: Float = 0.12f private const val ON_SURFACE_OPACITY_BUTTON_OUTLINE_DISABLED: Float = 0.12f From 17f5d6c48a8067308a386aba1ca5111fe6059560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Thu, 13 Oct 2022 10:58:01 +0200 Subject: [PATCH 46/48] Remove unneeded TODO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../android/common/ui/theme/utils/AndroidXViewThemeUtils.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt index b35a3661..5ac2de01 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/AndroidXViewThemeUtils.kt @@ -47,7 +47,6 @@ import javax.inject.Inject /** * View theme utils for Android extension views (androidx.*) */ -// TODO breaking change: androidViewThemeUtils parameter class AndroidXViewThemeUtils @Inject constructor( schemes: MaterialSchemes, private val androidViewThemeUtils: AndroidViewThemeUtils From 783c4b7f6afec1cfa2736923e8a8cfa16c1656c3 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Thu, 13 Oct 2022 12:12:45 +0200 Subject: [PATCH 47/48] Add disabled state to FAB Signed-off-by: Andy Scherzinger --- .../ui/theme/utils/MaterialViewThemeUtils.kt | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index da50e71e..8445b62c 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -68,8 +68,27 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun themeFAB(fab: FloatingActionButton) { withScheme(fab) { scheme -> - fab.backgroundTintList = ColorStateList.valueOf(scheme.primaryContainer) - fab.imageTintList = ColorStateList.valueOf(scheme.onPrimaryContainer) + fab.backgroundTintList = ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_enabled) + ), + intArrayOf( + scheme.primaryContainer, + Color.GRAY + ) + ) + + fab.imageTintList = ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_enabled), + intArrayOf(-android.R.attr.state_enabled) + ), + intArrayOf( + scheme.onPrimaryContainer, + Color.WHITE + ) + ) } } From ed7019a04da78d1896f2c0db3ecf6d1416199974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Fri, 14 Oct 2022 11:09:52 +0200 Subject: [PATCH 48/48] MaterialViewThemeUtils: simplify colorstatelist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey Signed-off-by: Álvaro Brey --- .../ui/theme/utils/MaterialViewThemeUtils.kt | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt index 8445b62c..882e1224 100644 --- a/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt +++ b/ui/src/main/java/com/nextcloud/android/common/ui/theme/utils/MaterialViewThemeUtils.kt @@ -68,26 +68,14 @@ class MaterialViewThemeUtils @Inject constructor(schemes: MaterialSchemes, priva fun themeFAB(fab: FloatingActionButton) { withScheme(fab) { scheme -> - fab.backgroundTintList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( - scheme.primaryContainer, - Color.GRAY - ) + fab.backgroundTintList = buildColorStateList( + android.R.attr.state_enabled to scheme.primaryContainer, + -android.R.attr.state_enabled to Color.GRAY ) - fab.imageTintList = ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_enabled), - intArrayOf(-android.R.attr.state_enabled) - ), - intArrayOf( - scheme.onPrimaryContainer, - Color.WHITE - ) + fab.imageTintList = buildColorStateList( + android.R.attr.state_enabled to scheme.onPrimaryContainer, + -android.R.attr.state_enabled to Color.WHITE ) } }