diff --git a/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.kt b/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.kt index fc893589c707..1e48c86fffb0 100644 --- a/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.kt +++ b/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.kt @@ -2,12 +2,12 @@ * Nextcloud Android client application * * SPDX-FileCopyrightText: 2021-2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2026 Alper Ozturk * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only */ package com.owncloud.android.ui import android.content.Context -import android.content.res.Resources import android.graphics.drawable.Drawable import android.util.AttributeSet import android.widget.ImageView @@ -15,7 +15,7 @@ import android.widget.RelativeLayout import androidx.annotation.Px import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat -import androidx.core.graphics.drawable.DrawableCompat +import androidx.core.view.updateLayoutParams import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.account.User import com.nextcloud.utils.GlideHelper.loadCircularBitmapIntoImageView @@ -24,28 +24,29 @@ import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.lib.resources.shares.ShareeUser import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.DisplayUtils.AvatarGenerationListener import com.owncloud.android.utils.theme.ViewThemeUtils -import kotlin.math.min -@Suppress("MagicNumber") class AvatarGroupLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 ) : RelativeLayout(context, attrs, defStyleAttr, defStyleRes), - AvatarGenerationListener { - private val borderDrawable = ContextCompat.getDrawable(context, R.drawable.round_bgnd) + DisplayUtils.AvatarGenerationListener { + private val borderDrawable = checkNotNull(ContextCompat.getDrawable(context, R.drawable.round_bgnd)).apply { + setTint(ContextCompat.getColor(context, R.color.bg_default)) + } @Px - private val avatarSize: Int = DisplayUtils.convertDpToPixel(40f, context) + private val avatarSize = DisplayUtils.convertDpToPixel(AVATAR_SIZE_DP, context) @Px - private val avatarBorderSize: Int = DisplayUtils.convertDpToPixel(2f, context) + private val avatarBorderSize = DisplayUtils.convertDpToPixel(AVATAR_BORDER_DP, context) @Px - private val overlapPx: Int = DisplayUtils.convertDpToPixel(24f, context) + private val overlapPx = DisplayUtils.convertDpToPixel(AVATAR_OVERLAP_DP, context) + + private val avatarRadius = resources.getDimension(R.dimen.list_item_avatar_icon_radius) var boundFileId: Long? = null set(value) { @@ -57,19 +58,12 @@ class AvatarGroupLayout @JvmOverloads constructor( private var displayedSharees: List? = null - init { - checkNotNull(borderDrawable) - DrawableCompat.setTint(borderDrawable, ContextCompat.getColor(context, R.color.bg_default)) - } - - @Suppress("LongMethod", "TooGenericExceptionCaught") fun setAvatars(user: User, sharees: List, viewThemeUtils: ViewThemeUtils) { if (sharees == displayedSharees) { return } displayedSharees = sharees - val context = getContext() removeAllViews() if (sharees.isEmpty()) { @@ -78,108 +72,79 @@ class AvatarGroupLayout @JvmOverloads constructor( } visibility = VISIBLE - var avatarLayoutParams: LayoutParams? - val shareeSize = min(sharees.size, MAX_AVATAR_COUNT) - val resources = context.resources - val avatarRadius = resources.getDimension(R.dimen.list_item_avatar_icon_radius) + val avatarCount = sharees.size.coerceAtMost(MAX_AVATAR_COUNT) + val hasOverflow = sharees.size > MAX_AVATAR_COUNT val serverName = user.accountName.substringAfterLast('@') - var sharee: ShareeUser - var avatarCount = 0 - while (avatarCount < shareeSize) { - avatarLayoutParams = LayoutParams(avatarSize, avatarSize).apply { - setMargins(0, 0, avatarCount * overlapPx, 0) - addRule(ALIGN_PARENT_RIGHT) - } + repeat(avatarCount) { index -> + val avatar = addAvatarView(index) - val avatar = ImageView(context).apply { - layoutParams = avatarLayoutParams - setPadding(avatarBorderSize, avatarBorderSize, avatarBorderSize, avatarBorderSize) - scaleType = ImageView.ScaleType.CENTER_INSIDE - background = borderDrawable - } - - addView(avatar) - avatar.requestLayout() - - if (avatarCount == 0 && sharees.size > MAX_AVATAR_COUNT) { + if (index == 0 && hasOverflow) { avatar.setImageResource(R.drawable.ic_people) viewThemeUtils.platform.tintDrawable(context, avatar.drawable, ColorRole.ON_SURFACE) } else { - sharee = sharees[avatarCount] - when (sharee.shareType) { - ShareType.GROUP, ShareType.EMAIL, ShareType.ROOM, ShareType.CIRCLE -> - viewThemeUtils.files.createAvatar( - sharee.shareType, - avatar, - context - ) - - ShareType.FEDERATED, ShareType.FEDERATED_GROUP -> showFederatedShareAvatar( - context, - sharee.userId!!, - avatarRadius, - resources, - avatar, - viewThemeUtils - ) - - else -> { - avatar.tag = "${sharee.userId}@$serverName" - DisplayUtils.setAvatar( - user, - sharee.userId!!, - sharee.displayName, - this, - avatarRadius, - resources, - avatar, - context, - avatarBorderSize - ) - } - } + bindSharee(avatar, sharees[index], user, serverName, viewThemeUtils) } - avatarCount++ } - // Recalculate container size based on avatar count - val size = overlapPx * (avatarCount - 1) + avatarSize - val rememberParam = layoutParams - rememberParam.width = size - layoutParams = rememberParam + updateLayoutParams { width = overlapPx * (avatarCount - 1) + avatarSize } } - @Suppress("TooGenericExceptionCaught") - private fun showFederatedShareAvatar( - context: Context, - user: String, - avatarRadius: Float, - resources: Resources, + private fun addAvatarView(index: Int): ImageView { + val avatar = ImageView(context).apply { + layoutParams = LayoutParams(avatarSize, avatarSize).apply { + setMargins(0, 0, index * overlapPx, 0) + addRule(ALIGN_PARENT_RIGHT) + } + setPadding(avatarBorderSize, avatarBorderSize, avatarBorderSize, avatarBorderSize) + scaleType = ImageView.ScaleType.CENTER_INSIDE + background = borderDrawable + } + + addView(avatar) + avatar.requestLayout() + return avatar + } + + private fun bindSharee( avatar: ImageView, + sharee: ShareeUser, + user: User, + serverName: String, viewThemeUtils: ViewThemeUtils ) { - val split = user.split("@") - val userId = split.getOrNull(0) ?: user - val server = split.getOrNull(1) - - val url = if (server != null) { - "https://$server/index.php/avatar/$userId/${resources.getInteger(R.integer.file_avatar_px)}" - } else { - // fallback: no federated server, maybe use local avatar - null + when (sharee.shareType) { + ShareType.GROUP, ShareType.EMAIL, ShareType.ROOM, ShareType.CIRCLE, ShareType.PUBLIC_LINK -> + viewThemeUtils.files.createAvatar(sharee.shareType, avatar, context) + + ShareType.FEDERATED, ShareType.FEDERATED_GROUP -> + showFederatedShareAvatar(checkNotNull(sharee.userId), avatar, viewThemeUtils) + + else -> { + val userId = checkNotNull(sharee.userId) + avatar.tag = "$userId@$serverName" + DisplayUtils.setAvatar( + user, + userId, + sharee.displayName, + this, + avatarRadius, + resources, + avatar, + context, + avatarBorderSize + ) + } } + } - val placeholder: Drawable = try { - TextDrawable.createAvatarByUserId(userId, avatarRadius) - } catch (e: Exception) { - Log_OC.e(TAG, "Error calculating RGB value for active account icon.", e) - viewThemeUtils.platform.colorDrawable( - ResourcesCompat - .getDrawable(resources, R.drawable.account_circle_white, null)!!, - ContextCompat.getColor(context, R.color.black) - ) + private fun showFederatedShareAvatar(federatedId: String, avatar: ImageView, viewThemeUtils: ViewThemeUtils) { + val parts = federatedId.split("@") + val userId = parts.first() + val url = parts.getOrNull(1)?.let { server -> + "https://$server/index.php/avatar/$userId/${resources.getInteger(R.integer.file_avatar_px)}" } + val placeholder = createFederatedPlaceholder(userId, viewThemeUtils) avatar.tag = null if (url != null) { @@ -189,15 +154,29 @@ class AvatarGroupLayout @JvmOverloads constructor( } } - override fun avatarGenerated(avatarDrawable: Drawable?, callContext: Any) { - (callContext as ImageView).setImageDrawable(avatarDrawable) + @Suppress("TooGenericExceptionCaught") + private fun createFederatedPlaceholder(userId: String, viewThemeUtils: ViewThemeUtils): Drawable = try { + TextDrawable.createAvatarByUserId(userId, avatarRadius) + } catch (e: Exception) { + Log_OC.e(TAG, "Error calculating RGB value for active account icon.", e) + viewThemeUtils.platform.colorDrawable( + checkNotNull(ResourcesCompat.getDrawable(resources, R.drawable.account_circle_white, null)), + ContextCompat.getColor(context, R.color.black) + ) + } + + override fun avatarGenerated(avatarDrawable: Drawable?, callContext: Any?) { + (callContext as? ImageView)?.setImageDrawable(avatarDrawable) } - override fun shouldCallGeneratedCallback(tag: String?, callContext: Any): Boolean = - (callContext as ImageView).tag == tag + override fun shouldCallGeneratedCallback(tag: String?, callContext: Any?): Boolean = + (callContext as? ImageView)?.let { it.tag == tag } ?: false companion object { private val TAG: String = AvatarGroupLayout::class.java.simpleName private const val MAX_AVATAR_COUNT = 3 + private const val AVATAR_SIZE_DP = 40f + private const val AVATAR_BORDER_DP = 2f + private const val AVATAR_OVERLAP_DP = 24f } } diff --git a/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt b/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt index ccf8152a8f8d..aa344b5be4c1 100644 --- a/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt +++ b/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt @@ -2,6 +2,7 @@ * Nextcloud - Android Client * * SPDX-FileCopyrightText: 2022-2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2026 Alper Ozturk * SPDX-FileCopyrightText: 2022 Álvaro Brey * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only */ @@ -11,14 +12,15 @@ import android.content.Context import android.content.res.ColorStateList import android.graphics.Color import android.graphics.PorterDuff +import android.graphics.PorterDuffColorFilter import android.graphics.drawable.Drawable import android.preference.PreferenceCategory import android.text.Spannable import android.text.SpannableString import android.text.style.ForegroundColorSpan -import android.view.View import android.widget.ImageView import android.widget.LinearLayout +import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.annotation.Px import androidx.annotation.StringRes @@ -34,6 +36,7 @@ import com.nextcloud.android.common.ui.theme.MaterialSchemes import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase import com.nextcloud.android.common.ui.theme.utils.AndroidViewThemeUtils import com.nextcloud.android.common.ui.theme.utils.AndroidXViewThemeUtils +import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.android.common.ui.util.buildColorStateList import com.nextcloud.utils.view.FastScrollPopupBackground import com.owncloud.android.R @@ -54,63 +57,41 @@ class FilesSpecificViewThemeUtils @Inject constructor( private val dynamicColor = MaterialDynamicColors() // not ported to common lib because PreferenceCategory is deprecated + @Suppress("DEPRECATION") fun themePreferenceCategory(category: PreferenceCategory) { - withScheme(category.context) { - val text: Spannable = SpannableString(category.title) - text.setSpan( - ForegroundColorSpan(it.primary), - 0, - text.length, - Spannable.SPAN_INCLUSIVE_INCLUSIVE - ) - category.title = text + withScheme(category.context) { scheme -> + category.title = SpannableString(category.title).apply { + setSpan(ForegroundColorSpan(scheme.primary), 0, length, Spannable.SPAN_INCLUSIVE_INCLUSIVE) + } } } fun createAvatar(type: ShareType?, avatar: ImageView, context: Context) { - fun createAvatarBase(@DrawableRes icon: Int, padding: Int = AvatarPadding.SMALL) { - avatar.setImageResource(icon) - avatar.background = ResourcesCompat.getDrawable( - context.resources, - R.drawable.round_bgnd, - null - ) - avatar.cropToPadding = true - avatar.scaleType = ImageView.ScaleType.CENTER_INSIDE - avatar.setPadding(padding, padding, padding, padding) + fun createAvatarBase(@DrawableRes icon: Int, @Px padding: Int = AvatarPadding.SMALL) = avatar.apply { + setImageResource(icon) + background = ResourcesCompat.getDrawable(context.resources, R.drawable.round_bgnd, null) + cropToPadding = true + scaleType = ImageView.ScaleType.CENTER_INSIDE + setPadding(padding, padding, padding, padding) + } + + fun createThemedAvatar(@DrawableRes icon: Int, @Px padding: Int = AvatarPadding.SMALL) { + createAvatarBase(icon, padding) + androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) } when (type) { - ShareType.GROUP -> { - createAvatarBase(R.drawable.ic_group) - androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) - } + ShareType.GROUP, ShareType.FEDERATED_GROUP -> createThemedAvatar(R.drawable.ic_group) - ShareType.FEDERATED_GROUP -> { - createAvatarBase(R.drawable.ic_group) - androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) - } + ShareType.ROOM -> createThemedAvatar(R.drawable.ic_talk, AvatarPadding.LARGE) - ShareType.ROOM -> { - createAvatarBase(R.drawable.ic_talk, AvatarPadding.LARGE) - androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) - } + ShareType.EMAIL -> createThemedAvatar(R.drawable.ic_email, AvatarPadding.LARGE) - ShareType.CIRCLE -> { - createAvatarBase(R.drawable.ic_circles) - avatar.background.setColorFilter( - context.resources.getColor(R.color.nc_grey), - PorterDuff.Mode.SRC_IN - ) - avatar.drawable.mutate().setColorFilter( - context.resources.getColor(R.color.icon_on_nc_grey), - PorterDuff.Mode.SRC_IN - ) - } + ShareType.PUBLIC_LINK -> createThemedAvatar(R.drawable.ic_link, AvatarPadding.LARGE) - ShareType.EMAIL -> { - createAvatarBase(R.drawable.ic_email, AvatarPadding.LARGE) - androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) + ShareType.CIRCLE -> createAvatarBase(R.drawable.ic_circles).run { + background.colorFilter = srcInColorFilter(context.getColor(R.color.nc_grey)) + drawable.mutate().colorFilter = srcInColorFilter(context.getColor(R.color.icon_on_nc_grey)) } else -> Log_OC.d(TAG, "Unknown share type") @@ -128,138 +109,53 @@ class FilesSpecificViewThemeUtils @Inject constructor( } } - private fun getThumbDrawable(context: Context): Drawable { - val thumbDrawable = - ResourcesCompat.getDrawable( - context.resources, - me.zhanghai.android.fastscroll.R.drawable.afs_md2_thumb, - null - ) - return androidViewThemeUtils.tintPrimaryDrawable(context, thumbDrawable)!! - } + private fun getThumbDrawable(context: Context): Drawable = checkNotNull( + androidViewThemeUtils.tintDrawable( + context, + me.zhanghai.android.fastscroll.R.drawable.afs_md2_thumb, + ColorRole.PRIMARY + ) + ) { "Fast scroller thumb drawable not found" } - private fun getHomeAsUpIcon(isMenu: Boolean): Int { - val icon = if (isMenu) { - R.drawable.ic_menu - } else { - R.drawable.ic_arrow_back - } - return icon + private fun getHomeAsUpDrawable(context: Context, isMenu: Boolean): Drawable { + val icon = if (isMenu) R.drawable.ic_menu else R.drawable.ic_arrow_back + return getDrawable(context, icon) } - /** - * Sets title and colors the actionbar, the title and the back arrow - */ - // TODO move back arrow resource to lib and use lib method directly? + private fun getDrawable(context: Context, @DrawableRes id: Int): Drawable = + checkNotNull(ResourcesCompat.getDrawable(context.resources, id, null)) { "Drawable $id not found" } + @JvmOverloads fun themeActionBar(context: Context, actionBar: ActionBar, title: String, isMenu: Boolean = false) { - val icon = getHomeAsUpIcon(isMenu) - val backArrow = ResourcesCompat.getDrawable( - context.resources, - icon, - null - )!! - androidXViewThemeUtils.themeActionBar( - context, - actionBar, - title, - backArrow - ) + androidXViewThemeUtils.themeActionBar(context, actionBar, title, getHomeAsUpDrawable(context, isMenu)) } - /** - * Sets title and colors the actionbar, the title and the back arrow - */ @JvmOverloads fun themeActionBar(context: Context, actionBar: ActionBar, @StringRes titleRes: Int, isMenu: Boolean = false) { - val title = context.getString(titleRes) - themeActionBar( - context, - actionBar, - title, - isMenu - ) + themeActionBar(context, actionBar, context.getString(titleRes), isMenu) } - /** - * Colors actionbar background and back arrow but not the title - */ @JvmOverloads fun themeActionBar(context: Context, actionBar: ActionBar, isMenu: Boolean = false) { - val backArrow = ResourcesCompat.getDrawable( - context.resources, - getHomeAsUpIcon(isMenu), - null - )!! - androidXViewThemeUtils.themeActionBar(context, actionBar, backArrow) - } - - fun themeTemplateCardView(cardView: MaterialCardView) { - withScheme(cardView.context) { scheme -> - cardView.setStrokeColor( - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_checked) - ), - intArrayOf( - scheme.primary, - scheme.outline - ) - ) - ) - } + androidXViewThemeUtils.themeActionBar(context, actionBar, getHomeAsUpDrawable(context, isMenu)) } - fun themeStatusCardView(cardView: MaterialCardView) { - withScheme(cardView) { scheme -> - cardView.backgroundTintList = - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_checked) - ), - intArrayOf( - scheme.surfaceContainerHighest, - scheme.surface - ) - ) - cardView.setStrokeColor( - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_checked) - ), - intArrayOf( - scheme.onSecondaryContainer, - scheme.outlineVariant - ) - ) - ) + fun themeTemplateCardView(view: MaterialCardView) { + withScheme(view.context) { scheme -> + view.setStrokeColor(checkedColors(scheme.primary, scheme.outline)) } } - fun themeFilledCardView(cardView: MaterialCardView) { - withScheme(cardView) { scheme -> - val background = cardView.context.getColor(R.color.grey_200) - cardView.backgroundTintList = - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_checked), - intArrayOf(-android.R.attr.state_checked) - ), - intArrayOf( - scheme.secondaryContainer, - background - ) - ) + fun themeStatusCardView(view: MaterialCardView) { + withScheme(view) { scheme -> + view.backgroundTintList = checkedColors(scheme.surfaceContainerHighest, scheme.surface) + view.setStrokeColor(checkedColors(scheme.onSecondaryContainer, scheme.outlineVariant)) } } - fun themeAvatarButton(shareImageView: ImageView) { - withScheme(shareImageView.context) { scheme -> - shareImageView.background.setColorFilter(scheme.primary, PorterDuff.Mode.SRC_IN) - shareImageView.drawable.mutate().setColorFilter(scheme.onPrimary, PorterDuff.Mode.SRC_IN) + fun themeFilledCardView(view: MaterialCardView) { + withScheme(view) { scheme -> + view.backgroundTintList = checkedColors(scheme.secondaryContainer, view.context.getColor(R.color.grey_200)) } } @@ -267,62 +163,60 @@ class FilesSpecificViewThemeUtils @Inject constructor( colorUtil.colorToHexString(scheme.primary) } - fun setWhiteBackButton(context: Context, supportActionBar: ActionBar) { - val backArrow = ResourcesCompat.getDrawable(context.resources, R.drawable.ic_arrow_back, null) - val tinted = androidViewThemeUtils.colorDrawable(backArrow!!, Color.WHITE) - supportActionBar.setHomeAsUpIndicator(tinted) + fun setWhiteBackButton(context: Context, actionBar: ActionBar) { + val backArrow = getDrawable(context, R.drawable.ic_arrow_back) + actionBar.setHomeAsUpIndicator(androidViewThemeUtils.colorDrawable(backArrow, Color.WHITE)) } - fun themeContentSearchView(searchView: SearchView) { - withScheme(searchView) { scheme -> - // hacky as no default way is provided - val editText = searchView - .findViewById(androidx.appcompat.R.id.search_src_text) as AppCompatAutoCompleteTextView - val searchPlate = searchView.findViewById(androidx.appcompat.R.id.search_plate) as LinearLayout - val closeButton = searchView.findViewById(androidx.appcompat.R.id.search_close_btn) as ImageView - val searchButton = searchView.findViewById(androidx.appcompat.R.id.search_button) as ImageView - editText.setHintTextColor(scheme.onSurfaceVariant) - editText.highlightColor = scheme.inverseOnSurface - editText.setTextColor(scheme.onSurface) - closeButton.setColorFilter(scheme.onSurface) - searchButton.setColorFilter(scheme.onSurface) - searchPlate.setBackgroundColor(scheme.surfaceContainerHigh) + fun themeContentSearchView(view: SearchView) { + withScheme(view) { scheme -> + view.findViewById(androidx.appcompat.R.id.search_src_text).run { + setHintTextColor(scheme.onSurfaceVariant) + highlightColor = scheme.inverseOnSurface + setTextColor(scheme.onSurface) + } + view.findViewById(androidx.appcompat.R.id.search_close_btn).setColorFilter(scheme.onSurface) + view.findViewById(androidx.appcompat.R.id.search_button).setColorFilter(scheme.onSurface) + view.findViewById(androidx.appcompat.R.id.search_plate) + .setBackgroundColor(scheme.surfaceContainerHigh) } } @JvmOverloads - fun colorNavigationView(navigationView: NavigationView, colorIcons: Boolean = true) { - withScheme(navigationView) { scheme -> - navigationView.run { + fun colorNavigationView(view: NavigationView, colorIcons: Boolean = true) { + withScheme(view) { scheme -> + view.run { itemBackground?.setTintList( - buildColorStateList( - android.R.attr.state_checked to dynamicColor.secondaryContainer().getArgb(scheme), - -android.R.attr.state_checked to Color.TRANSPARENT - ) + checkedColors(dynamicColor.secondaryContainer().getArgb(scheme), Color.TRANSPARENT) ) background.setTintList(ColorStateList.valueOf(dynamicColor.surface().getArgb(scheme))) if (colorIcons) { - itemIconTintList = buildColorStateList( - android.R.attr.state_checked to dynamicColor.onSecondaryContainer().getArgb(scheme), - -android.R.attr.state_checked to dynamicColor.onSurfaceVariant().getArgb(scheme) + itemIconTintList = checkedColors( + dynamicColor.onSecondaryContainer().getArgb(scheme), + dynamicColor.onSurfaceVariant().getArgb(scheme) ) } } } } - fun themeAutoCompleteTextView(autoCompleteTextView: MaterialAutoCompleteTextView) { - withScheme(autoCompleteTextView) { scheme -> - autoCompleteTextView.setTextColor(dynamicColor.onSurface().getArgb(scheme)) - autoCompleteTextView.setHintTextColor(dynamicColor.onSurfaceVariant().getArgb(scheme)) - autoCompleteTextView.setDropDownBackgroundTintList( - ColorStateList.valueOf(dynamicColor.surfaceContainer().getArgb(scheme)) - ) + fun themeAutoCompleteTextView(view: MaterialAutoCompleteTextView) { + withScheme(view) { scheme -> + view.setTextColor(dynamicColor.onSurface().getArgb(scheme)) + view.setHintTextColor(dynamicColor.onSurfaceVariant().getArgb(scheme)) + view.dropDownBackgroundTintList = ColorStateList.valueOf(dynamicColor.surfaceContainer().getArgb(scheme)) } } + private fun checkedColors(@ColorInt checked: Int, @ColorInt unchecked: Int): ColorStateList = buildColorStateList( + android.R.attr.state_checked to checked, + -android.R.attr.state_checked to unchecked + ) + + private fun srcInColorFilter(@ColorInt color: Int) = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN) + companion object { private val TAG = FilesSpecificViewThemeUtils::class.simpleName diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 64157c19efab..d22b428766b5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,6 +5,7 @@ ~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only --> + Run sync now Local contacts Failed to open text editor All files