diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/NowPlayingScreen.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/NowPlayingScreen.kt index 5adafd1d..bde37820 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/NowPlayingScreen.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/NowPlayingScreen.kt @@ -4,24 +4,26 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import code.name.monkey.retromusic.R +enum class NowPlayingScreen constructor( + @param:StringRes @field:StringRes + val titleRes: Int, + @param:DrawableRes @field:DrawableRes val drawableResId: Int, + val id: Int +) { + + NORMAL(R.string.normal, R.drawable.np_normal, 0), + FLAT(R.string.flat, R.drawable.np_flat, 1), + FIT(R.string.fit, R.drawable.np_fit, 12), + TINY(R.string.tiny, R.drawable.np_tiny, 7), + PEAK(R.string.peak, R.drawable.np_peak, 14), -enum class NowPlayingScreen constructor(@param:StringRes @field:StringRes - val titleRes: Int, - @param:DrawableRes @field:DrawableRes val drawableResId: Int, - val id: Int) { ADAPTIVE(R.string.adaptive, R.drawable.np_adaptive, 10), BLUR(R.string.blur, R.drawable.np_blur, 4), BLUR_CARD(R.string.blur_card, R.drawable.np_blur_card, 9), CARD(R.string.card, R.drawable.np_card, 6), COLOR(R.string.color, R.drawable.np_color, 5), - FIT(R.string.fit, R.drawable.np_fit, 12), - FLAT(R.string.flat, R.drawable.np_flat, 1), FULL(R.string.full, R.drawable.np_full, 2), MATERIAL(R.string.material, R.drawable.np_material, 11), - NORMAL(R.string.normal, R.drawable.np_normal, 0), PLAIN(R.string.plain, R.drawable.np_plain, 3), - TINY(R.string.tiny, R.drawable.np_tiny, 7), SIMPLE(R.string.simple, R.drawable.np_simple, 8), - PEAK(R.string.peak, R.drawable.np_peak, 14) - } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/color/ColorPlaybackControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/color/ColorPlaybackControlsFragment.kt index edc02023..c73e6ff9 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/color/ColorPlaybackControlsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/color/ColorPlaybackControlsFragment.kt @@ -26,8 +26,11 @@ import kotlinx.android.synthetic.main.fragment_color_player_playback_controls.so import kotlinx.android.synthetic.main.fragment_color_player_playback_controls.songTotalTime import kotlinx.android.synthetic.main.fragment_color_player_playback_controls.text import kotlinx.android.synthetic.main.fragment_color_player_playback_controls.title -import kotlinx.android.synthetic.main.fragment_player_playback_controls.* - +import kotlinx.android.synthetic.main.fragment_player_playback_controls.nextButton +import kotlinx.android.synthetic.main.fragment_player_playback_controls.playPauseButton +import kotlinx.android.synthetic.main.fragment_player_playback_controls.previousButton +import kotlinx.android.synthetic.main.fragment_player_playback_controls.repeatButton +import kotlinx.android.synthetic.main.fragment_player_playback_controls.shuffleButton class ColorPlaybackControlsFragment : AbsPlayerControlsFragment() { @@ -91,7 +94,6 @@ class ColorPlaybackControlsFragment : AbsPlayerControlsFragment() { updateShuffleState() } - fun setDark(textColor: Int, background: Int) { setDark(textColor) TintHelper.setTintAuto(playPauseButton, background, false) @@ -123,15 +125,13 @@ class ColorPlaybackControlsFragment : AbsPlayerControlsFragment() { playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler()) } - private fun updatePlayPauseDrawableState() { when { MusicPlayerRemote.isPlaying -> playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp) - else -> playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_32dp) + else -> playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp) } } - private fun setUpMusicControllers() { setUpPlayPauseFab() setUpPrevNext() @@ -157,7 +157,10 @@ class ColorPlaybackControlsFragment : AbsPlayerControlsFragment() { override fun updateShuffleState() { when (MusicPlayerRemote.shuffleMode) { - MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter( + lastPlaybackControlsColor, + PorterDuff.Mode.SRC_IN + ) else -> shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN) } } @@ -183,14 +186,13 @@ class ColorPlaybackControlsFragment : AbsPlayerControlsFragment() { } } - public override fun show() { playPauseButton!!.animate() - .scaleX(1f) - .scaleY(1f) - .rotation(360f) - .setInterpolator(DecelerateInterpolator()) - .start() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(DecelerateInterpolator()) + .start() } public override fun hide() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerPlaybackControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerPlaybackControlsFragment.kt index 94592c03..1576e72a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerPlaybackControlsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerPlaybackControlsFragment.kt @@ -36,7 +36,6 @@ import kotlinx.android.synthetic.main.fragment_player_playback_controls.songTota import kotlinx.android.synthetic.main.fragment_player_playback_controls.text import kotlinx.android.synthetic.main.fragment_player_playback_controls.title - class PlayerPlaybackControlsFragment : AbsPlayerControlsFragment() { private var lastPlaybackControlsColor: Int = 0 @@ -48,8 +47,10 @@ class PlayerPlaybackControlsFragment : AbsPlayerControlsFragment() { progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View? { + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { return inflater.inflate(R.layout.fragment_player_playback_controls, container, false) } @@ -72,10 +73,12 @@ class PlayerPlaybackControlsFragment : AbsPlayerControlsFragment() { val colorBg = ATHUtil.resolveColor(requireContext(), android.R.attr.colorBackground) if (ColorUtil.isColorLight(colorBg)) { lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(requireContext(), true) - lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(requireContext(), true) + lastDisabledPlaybackControlsColor = + MaterialValueHelper.getSecondaryDisabledTextColor(requireContext(), true) } else { lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(requireContext(), false) - lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(requireContext(), false) + lastDisabledPlaybackControlsColor = + MaterialValueHelper.getPrimaryDisabledTextColor(requireContext(), false) } val colorFinal = if (PreferenceUtil.getInstance(requireContext()).adaptiveColor) { @@ -84,7 +87,11 @@ class PlayerPlaybackControlsFragment : AbsPlayerControlsFragment() { ThemeStore.accentColor(requireContext()) }.ripAlpha() - TintHelper.setTintAuto(playPauseButton, MaterialValueHelper.getPrimaryTextColor(requireContext(), ColorUtil.isColorLight(colorFinal)), false) + TintHelper.setTintAuto( + playPauseButton, + MaterialValueHelper.getPrimaryTextColor(requireContext(), ColorUtil.isColorLight(colorFinal)), + false + ) TintHelper.setTintAuto(playPauseButton, colorFinal, true) ViewUtil.setProgressDrawable(progressSlider, colorFinal, false) @@ -173,7 +180,10 @@ class PlayerPlaybackControlsFragment : AbsPlayerControlsFragment() { override fun updateShuffleState() { when (MusicPlayerRemote.shuffleMode) { - MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter( + lastPlaybackControlsColor, + PorterDuff.Mode.SRC_IN + ) else -> shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN) } } @@ -201,11 +211,11 @@ class PlayerPlaybackControlsFragment : AbsPlayerControlsFragment() { public override fun show() { playPauseButton!!.animate() - .scaleX(1f) - .scaleY(1f) - .rotation(360f) - .setInterpolator(DecelerateInterpolator()) - .start() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(DecelerateInterpolator()) + .start() } public override fun hide() { @@ -223,8 +233,10 @@ class PlayerPlaybackControlsFragment : AbsPlayerControlsFragment() { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { if (fromUser) { MusicPlayerRemote.seekTo(progress) - onUpdateProgressViews(MusicPlayerRemote.songProgressMillis, - MusicPlayerRemote.songDurationMillis) + onUpdateProgressViews( + MusicPlayerRemote.songProgressMillis, + MusicPlayerRemote.songDurationMillis + ) } } }) @@ -241,5 +253,4 @@ class PlayerPlaybackControlsFragment : AbsPlayerControlsFragment() { songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong()) songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong()) } - } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/plain/PlainPlaybackControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/plain/PlainPlaybackControlsFragment.kt index a083153b..f7c7911d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/plain/PlainPlaybackControlsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/plain/PlainPlaybackControlsFragment.kt @@ -26,10 +26,14 @@ import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.ViewUtil -import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.* -import kotlinx.android.synthetic.main.media_button.playPauseButton -import kotlinx.android.synthetic.main.media_button.repeatButton -import kotlinx.android.synthetic.main.media_button.shuffleButton +import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.nextButton +import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.playPauseButton +import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.previousButton +import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.progressSlider +import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.repeatButton +import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.shuffleButton +import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.songCurrentProgress +import kotlinx.android.synthetic.main.fragment_plain_controls_fragment.songTotalTime /** * @author Hemanth S (h4h13). @@ -41,7 +45,6 @@ class PlainPlaybackControlsFragment : AbsPlayerControlsFragment() { private var lastDisabledPlaybackControlsColor: Int = 0 private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper - override fun onPlayStateChanged() { updatePlayPauseDrawableState() } @@ -70,7 +73,6 @@ class PlainPlaybackControlsFragment : AbsPlayerControlsFragment() { return inflater.inflate(R.layout.fragment_plain_controls_fragment, container, false) } - override fun onResume() { super.onResume() progressViewUpdateHelper.start() @@ -118,7 +120,6 @@ class PlainPlaybackControlsFragment : AbsPlayerControlsFragment() { previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) } - override fun setDark(color: Int) { val colorBg = ATHUtil.resolveColor(context!!, android.R.attr.colorBackground) if (ColorUtil.isColorLight(colorBg)) { @@ -136,7 +137,11 @@ class PlainPlaybackControlsFragment : AbsPlayerControlsFragment() { } volumeFragment?.setTintable(colorFinal) - TintHelper.setTintAuto(playPauseButton, MaterialValueHelper.getPrimaryTextColor(context!!, ColorUtil.isColorLight(colorFinal)), false) + TintHelper.setTintAuto( + playPauseButton, + MaterialValueHelper.getPrimaryTextColor(context!!, ColorUtil.isColorLight(colorFinal)), + false + ) TintHelper.setTintAuto(playPauseButton, colorFinal, true) ViewUtil.setProgressDrawable(progressSlider, colorFinal.ripAlpha(), true) @@ -152,7 +157,10 @@ class PlainPlaybackControlsFragment : AbsPlayerControlsFragment() { override fun updateShuffleState() { when (MusicPlayerRemote.shuffleMode) { - MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter( + lastPlaybackControlsColor, + PorterDuff.Mode.SRC_IN + ) else -> shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN) } } @@ -180,11 +188,11 @@ class PlainPlaybackControlsFragment : AbsPlayerControlsFragment() { public override fun show() { playPauseButton!!.animate() - .scaleX(1f) - .scaleY(1f) - .rotation(360f) - .setInterpolator(DecelerateInterpolator()) - .start() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(DecelerateInterpolator()) + .start() } public override fun hide() { @@ -202,8 +210,10 @@ class PlainPlaybackControlsFragment : AbsPlayerControlsFragment() { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { if (fromUser) { MusicPlayerRemote.seekTo(progress) - onUpdateProgressViews(MusicPlayerRemote.songProgressMillis, - MusicPlayerRemote.songDurationMillis) + onUpdateProgressViews( + MusicPlayerRemote.songProgressMillis, + MusicPlayerRemote.songDurationMillis + ) } } }) @@ -219,16 +229,16 @@ class PlainPlaybackControlsFragment : AbsPlayerControlsFragment() { pivotY = (height / 2).toFloat() animate().setDuration(200) - .setInterpolator(DecelerateInterpolator()) - .scaleX(1.1f) - .scaleY(1.1f) - .withEndAction { - animate().setDuration(200) - .setInterpolator(AccelerateInterpolator()) - .scaleX(1f) - .scaleY(1f) - .alpha(1f).start() - }.start() + .setInterpolator(DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction { + animate().setDuration(200) + .setInterpolator(AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f).start() + }.start() } } @@ -251,5 +261,4 @@ class PlainPlaybackControlsFragment : AbsPlayerControlsFragment() { songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong()) songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong()) } - } diff --git a/app/src/main/res/drawable/round_window.xml b/app/src/main/res/drawable/round_window.xml index 40a02af8..cf357a43 100755 --- a/app/src/main/res/drawable/round_window.xml +++ b/app/src/main/res/drawable/round_window.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/layout-xlarge-land/fragment_player_playback_controls.xml b/app/src/main/res/layout-xlarge-land/fragment_player_playback_controls.xml index 6ab13512..1d104566 100755 --- a/app/src/main/res/layout-xlarge-land/fragment_player_playback_controls.xml +++ b/app/src/main/res/layout-xlarge-land/fragment_player_playback_controls.xml @@ -66,7 +66,7 @@ tools:ignore="MissingPrefix" tools:tint="@color/md_black_1000" /> - + android:background="#C0000000" /> - - - + - + - + - - - + - + android:gravity="center_vertical|left|end" + android:singleLine="true" + android:textColor="@color/md_white_1000" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/progressSlider" + tools:ignore="RtlHardcoded,RtlSymmetry" + tools:text="00:00" /> - - android:gravity="center_vertical|left|end" - android:paddingLeft="8dp" - android:singleLine="true" - android:textColor="@color/md_white_1000" - android:textSize="12sp" - tools:ignore="RtlHardcoded,RtlSymmetry" - tools:text="00:00" /> - - - - - - - - - - - + android:layout_centerVertical="true" + android:layout_marginTop="16dp" + android:layout_toLeftOf="@id/songTotalTime" + android:layout_toRightOf="@id/songCurrentProgress" + android:maxHeight="3dp" + android:progressDrawable="@drawable/color_progress_seek" + android:splitTrack="false" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/text" + tools:ignore="RtlHardcoded,UnusedAttribute" + tools:progress="20" /> - + - + - + - + + + - \ No newline at end of file + android:layout_marginBottom="8dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@+id/playPauseButton" + tools:background="@color/md_red_400" + tools:layout_height="52dp" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_lock_screen_playback_controls.xml b/app/src/main/res/layout/fragment_lock_screen_playback_controls.xml index ae795ddd..0616c2d0 100644 --- a/app/src/main/res/layout/fragment_lock_screen_playback_controls.xml +++ b/app/src/main/res/layout/fragment_lock_screen_playback_controls.xml @@ -1,216 +1,191 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/playback_controls" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center_vertical" + android:orientation="vertical" + tools:ignore="MissingPrefix"> - + - + - + - - + + - + - - + + - + + - + - + - + - + - - - - - - - - - - + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_material_playback_controls.xml b/app/src/main/res/layout/fragment_material_playback_controls.xml index 2c1997a9..4ed2b129 100644 --- a/app/src/main/res/layout/fragment_material_playback_controls.xml +++ b/app/src/main/res/layout/fragment_material_playback_controls.xml @@ -16,6 +16,7 @@ android:paddingStart="12dp" android:paddingEnd="12dp" app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> @@ -102,98 +103,90 @@ android:paddingStart="16dp" android:paddingEnd="16dp" android:textAppearance="@style/TextViewBody1" - app:layout_constraintBottom_toTopOf="@+id/playerMediaControllerContainer" + app:layout_constraintBottom_toTopOf="@+id/playPauseButton" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/titleContainer" tools:text="@tools:sample/lorem/random" /> - + + + + + app:srcCompat="@drawable/ic_pause_white_64dp" + tools:tint="@color/md_black_1000" /> - + - + - - - - - - - - - @@ -58,92 +59,78 @@ tools:progress="20" /> - + + + + + tools:backgroundTint="@color/md_green_500" + tools:srcCompat="@drawable/ic_play_arrow_white_32dp" /> - + - - - - - - - - - - + - \ No newline at end of file + + + diff --git a/app/src/main/res/layout/fragment_player_playback_controls.xml b/app/src/main/res/layout/fragment_player_playback_controls.xml index c07a57b7..6088a761 100755 --- a/app/src/main/res/layout/fragment_player_playback_controls.xml +++ b/app/src/main/res/layout/fragment_player_playback_controls.xml @@ -15,8 +15,6 @@ android:layout_height="28dp" android:paddingStart="12dp" android:paddingEnd="12dp" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> @@ -95,7 +89,6 @@ tools:text="@tools:sample/lorem/random" /> - - - + + + + + app:srcCompat="@drawable/ic_pause_white_64dp" + tools:tint="@color/md_black_1000" /> - + - - - - - - - - - - - + - @@ -11,17 +12,23 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" + android:layout_marginTop="8dp" android:gravity="center" - android:padding="16dp" + android:padding="8dp" android:textAppearance="@style/TextViewHeadline6" - tools:text="Card layout" /> - + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="@tools:sample/full_names" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1d828b35..afa707a4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -814,4 +814,5 @@ Blacklist No songs playing Nothing to see + diff --git a/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TintHelper.java b/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TintHelper.java index 037e2ca1..3f04d133 100755 --- a/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TintHelper.java +++ b/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TintHelper.java @@ -17,7 +17,6 @@ import android.widget.RadioButton; import android.widget.SeekBar; import android.widget.Switch; import android.widget.TextView; - import androidx.annotation.CheckResult; import androidx.annotation.ColorInt; import androidx.annotation.DrawableRes; @@ -27,386 +26,15 @@ import androidx.appcompat.widget.AppCompatEditText; import androidx.appcompat.widget.SwitchCompat; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; - -import com.google.android.material.floatingactionbutton.FloatingActionButton; - -import java.lang.reflect.Field; - import code.name.monkey.appthemehelper.R; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import java.lang.reflect.Field; /** * @author afollestad, plusCubed */ public final class TintHelper { - @SuppressLint("PrivateResource") - @ColorInt - private static int getDefaultRippleColor(@NonNull Context context, boolean useDarkRipple) { - // Light ripple is actually translucent black, and vice versa - return ContextCompat.getColor(context, useDarkRipple ? - R.color.ripple_material_light : R.color.ripple_material_dark); - } - - @NonNull - private static ColorStateList getDisabledColorStateList(@ColorInt int normal, @ColorInt int disabled) { - return new ColorStateList(new int[][]{ - new int[]{-android.R.attr.state_enabled}, - new int[]{android.R.attr.state_enabled} - }, new int[]{ - disabled, - normal - }); - } - - @SuppressWarnings("deprecation") - public static void setTintSelector(@NonNull View view, @ColorInt final int color, final boolean darker, final boolean useDarkTheme) { - final boolean isColorLight = ColorUtil.INSTANCE.isColorLight(color); - final int disabled = ContextCompat.getColor(view.getContext(), useDarkTheme ? R.color.ate_button_disabled_dark : R.color.ate_button_disabled_light); - final int pressed = ColorUtil.INSTANCE.shiftColor(color, darker ? 0.9f : 1.1f); - final int activated = ColorUtil.INSTANCE.shiftColor(color, darker ? 1.1f : 0.9f); - final int rippleColor = getDefaultRippleColor(view.getContext(), isColorLight); - final int textColor = ContextCompat.getColor(view.getContext(), isColorLight ? R.color.ate_primary_text_light : R.color.ate_primary_text_dark); - - final ColorStateList sl; - if (view instanceof Button) { - sl = getDisabledColorStateList(color, disabled); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && - view.getBackground() instanceof RippleDrawable) { - RippleDrawable rd = (RippleDrawable) view.getBackground(); - rd.setColor(ColorStateList.valueOf(rippleColor)); - } - - // Disabled text color state for buttons, may get overridden later by ATE tags - final Button button = (Button) view; - button.setTextColor(getDisabledColorStateList(textColor, ContextCompat.getColor(view.getContext(), useDarkTheme ? R.color.ate_button_text_disabled_dark : R.color.ate_button_text_disabled_light))); - } else if (view instanceof FloatingActionButton) { - // FloatingActionButton doesn't support disabled state? - sl = new ColorStateList(new int[][]{ - new int[]{-android.R.attr.state_pressed}, - new int[]{android.R.attr.state_pressed} - }, new int[]{ - color, - pressed - }); - - final FloatingActionButton fab = (FloatingActionButton) view; - fab.setRippleColor(rippleColor); - fab.setBackgroundTintList(sl); - if (fab.getDrawable() != null) - fab.setImageDrawable(createTintedDrawable(fab.getDrawable(), textColor)); - return; - } else { - sl = new ColorStateList( - new int[][]{ - new int[]{-android.R.attr.state_enabled}, - new int[]{android.R.attr.state_enabled}, - new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}, - new int[]{android.R.attr.state_enabled, android.R.attr.state_activated}, - new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} - }, - new int[]{ - disabled, - color, - pressed, - activated, - activated - } - ); - } - - Drawable drawable = view.getBackground(); - if (drawable != null) { - drawable = createTintedDrawable(drawable, sl); - ViewUtil.INSTANCE.setBackgroundCompat(view, drawable); - } - - if (view instanceof TextView && !(view instanceof Button)) { - final TextView tv = (TextView) view; - tv.setTextColor(getDisabledColorStateList(textColor, ContextCompat.getColor(view.getContext(), isColorLight ? R.color.ate_text_disabled_light : R.color.ate_text_disabled_dark))); - } - } - - public static void setTintAuto(final @NonNull View view, final @ColorInt int color, - boolean background) { - setTintAuto(view, color, background, ATHUtil.INSTANCE.isWindowBackgroundDark(view.getContext())); - } - - @SuppressWarnings("deprecation") - public static void setTintAuto(final @NonNull View view, final @ColorInt int color, - boolean background, final boolean isDark) { - if (!background) { - if (view instanceof RadioButton) - setTint((RadioButton) view, color, isDark); - else if (view instanceof SeekBar) - setTint((SeekBar) view, color, isDark); - else if (view instanceof ProgressBar) - setTint((ProgressBar) view, color); - else if (view instanceof EditText) - setTint((EditText) view, color, isDark); - else if (view instanceof CheckBox) - setTint((CheckBox) view, color, isDark); - else if (view instanceof ImageView) - setTint((ImageView) view, color); - else if (view instanceof Switch) - setTint((Switch) view, color, isDark); - else if (view instanceof SwitchCompat) - setTint((SwitchCompat) view, color, isDark); - else background = true; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && - !background && view.getBackground() instanceof RippleDrawable) { - // Ripples for the above views (e.g. when you tap and hold a switch or checkbox) - RippleDrawable rd = (RippleDrawable) view.getBackground(); - @SuppressLint("PrivateResource") final int unchecked = ContextCompat.getColor(view.getContext(), - isDark ? R.color.ripple_material_dark : R.color.ripple_material_light); - final int checked = ColorUtil.INSTANCE.adjustAlpha(color, 0.4f); - final ColorStateList sl = new ColorStateList( - new int[][]{ - new int[]{-android.R.attr.state_activated, -android.R.attr.state_checked}, - new int[]{android.R.attr.state_activated}, - new int[]{android.R.attr.state_checked} - }, - new int[]{ - unchecked, - checked, - checked - } - ); - rd.setColor(sl); - } - } - if (background) { - // Need to tint the background of a view - if (view instanceof FloatingActionButton || view instanceof Button) { - setTintSelector(view, color, false, isDark); - } else if (view.getBackground() != null) { - Drawable drawable = view.getBackground(); - if (drawable != null) { - drawable = createTintedDrawable(drawable, color); - ViewUtil.INSTANCE.setBackgroundCompat(view, drawable); - } - } - } - } - - - public static void setTint(@NonNull RadioButton radioButton, @ColorInt int color, boolean useDarker) { - ColorStateList sl = new ColorStateList(new int[][]{ - new int[]{-android.R.attr.state_enabled}, - new int[]{android.R.attr.state_enabled, -android.R.attr.state_checked}, - new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} - }, new int[]{ - // Rdio button includes own alpha for disabled state - ColorUtil.INSTANCE.stripAlpha(ContextCompat.getColor(radioButton.getContext(), useDarker ? R.color.ate_control_disabled_dark : R.color.ate_control_disabled_light)), - ContextCompat.getColor(radioButton.getContext(), useDarker ? R.color.ate_control_normal_dark : R.color.ate_control_normal_light), - color - }); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - radioButton.setButtonTintList(sl); - } else { - Drawable d = createTintedDrawable(ContextCompat.getDrawable(radioButton.getContext(), R.drawable.abc_btn_radio_material), sl); - radioButton.setButtonDrawable(d); - } - } - - public static void setTint(@NonNull SeekBar seekBar, @ColorInt int color, boolean useDarker) { - final ColorStateList s1 = getDisabledColorStateList(color, ContextCompat.getColor(seekBar.getContext(), useDarker ? R.color.ate_control_disabled_dark : R.color.ate_control_disabled_light)); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - seekBar.setThumbTintList(s1); - seekBar.setProgressTintList(s1); - } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) { - Drawable progressDrawable = createTintedDrawable(seekBar.getProgressDrawable(), s1); - seekBar.setProgressDrawable(progressDrawable); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - Drawable thumbDrawable = createTintedDrawable(seekBar.getThumb(), s1); - seekBar.setThumb(thumbDrawable); - } - } else { - PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN; - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { - mode = PorterDuff.Mode.MULTIPLY; - } - if (seekBar.getIndeterminateDrawable() != null) - seekBar.getIndeterminateDrawable().setColorFilter(color, mode); - if (seekBar.getProgressDrawable() != null) - seekBar.getProgressDrawable().setColorFilter(color, mode); - } - } - - public static void setTint(@NonNull ProgressBar progressBar, @ColorInt int color) { - setTint(progressBar, color, false); - } - - public static void setTint(@NonNull ProgressBar progressBar, @ColorInt int color, boolean skipIndeterminate) { - ColorStateList sl = ColorStateList.valueOf(color); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - progressBar.setProgressTintList(sl); - progressBar.setSecondaryProgressTintList(sl); - if (!skipIndeterminate) - progressBar.setIndeterminateTintList(sl); - } else { - PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN; - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { - mode = PorterDuff.Mode.MULTIPLY; - } - if (!skipIndeterminate && progressBar.getIndeterminateDrawable() != null) - progressBar.getIndeterminateDrawable().setColorFilter(color, mode); - if (progressBar.getProgressDrawable() != null) - progressBar.getProgressDrawable().setColorFilter(color, mode); - } - } - - public static void setTint(@NonNull EditText editText, @ColorInt int color, boolean useDarker) { - final ColorStateList editTextColorStateList = new ColorStateList(new int[][]{ - new int[]{-android.R.attr.state_enabled}, - new int[]{android.R.attr.state_enabled, -android.R.attr.state_pressed, -android.R.attr.state_focused}, - new int[]{} - }, new int[]{ - ContextCompat.getColor(editText.getContext(), useDarker ? R.color.ate_text_disabled_dark : R.color.ate_text_disabled_light), - ContextCompat.getColor(editText.getContext(), useDarker ? R.color.ate_control_normal_dark : R.color.ate_control_normal_light), - color - }); - if (editText instanceof AppCompatEditText) { - ((AppCompatEditText) editText).setSupportBackgroundTintList(editTextColorStateList); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - editText.setBackgroundTintList(editTextColorStateList); - } - setCursorTint(editText, color); - } - - public static void setTint(@NonNull CheckBox box, @ColorInt int color, boolean useDarker) { - ColorStateList sl = new ColorStateList(new int[][]{ - new int[]{-android.R.attr.state_enabled}, - new int[]{android.R.attr.state_enabled, -android.R.attr.state_checked}, - new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} - }, new int[]{ - ContextCompat.getColor(box.getContext(), useDarker ? R.color.ate_control_disabled_dark : R.color.ate_control_disabled_light), - ContextCompat.getColor(box.getContext(), useDarker ? R.color.ate_control_normal_dark : R.color.ate_control_normal_light), - color - }); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - box.setButtonTintList(sl); - } else { - Drawable drawable = createTintedDrawable(ContextCompat.getDrawable(box.getContext(), R.drawable.abc_btn_check_material), sl); - box.setButtonDrawable(drawable); - } - } - - public static void setTint(@NonNull ImageView image, @ColorInt int color) { - image.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); - } - - private static Drawable modifySwitchDrawable(@NonNull Context context, @NonNull Drawable from, @ColorInt int tint, boolean thumb, boolean compatSwitch, boolean useDarker) { - if (useDarker) { - tint = ColorUtil.INSTANCE.shiftColor(tint, 1.1f); - } - tint = ColorUtil.INSTANCE.adjustAlpha(tint, (compatSwitch && !thumb) ? 0.5f : 1.0f); - int disabled; - int normal; - if (thumb) { - disabled = ContextCompat.getColor(context, useDarker ? R.color.ate_switch_thumb_disabled_dark : R.color.ate_switch_thumb_disabled_light); - normal = ContextCompat.getColor(context, useDarker ? R.color.ate_switch_thumb_normal_dark : R.color.ate_switch_thumb_normal_light); - } else { - disabled = ContextCompat.getColor(context, useDarker ? R.color.ate_switch_track_disabled_dark : R.color.ate_switch_track_disabled_light); - normal = ContextCompat.getColor(context, useDarker ? R.color.ate_switch_track_normal_dark : R.color.ate_switch_track_normal_light); - } - - // Stock switch includes its own alpha - if (!compatSwitch) { - normal = ColorUtil.INSTANCE.stripAlpha(normal); - } - - final ColorStateList sl = new ColorStateList( - new int[][]{ - new int[]{-android.R.attr.state_enabled}, - new int[]{android.R.attr.state_enabled, -android.R.attr.state_activated, -android.R.attr.state_checked}, - new int[]{android.R.attr.state_enabled, android.R.attr.state_activated}, - new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} - }, - new int[]{ - disabled, - normal, - tint, - tint - } - ); - return createTintedDrawable(from, sl); - } - - public static void setTint(@NonNull Switch switchView, @ColorInt int color, boolean useDarker) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return; - if (switchView.getTrackDrawable() != null) { - switchView.setTrackDrawable(modifySwitchDrawable(switchView.getContext(), - switchView.getTrackDrawable(), color, false, false, useDarker)); - } - if (switchView.getThumbDrawable() != null) { - switchView.setThumbDrawable(modifySwitchDrawable(switchView.getContext(), - switchView.getThumbDrawable(), color, true, false, useDarker)); - } - } - - public static void setTint(@NonNull SwitchCompat switchView, @ColorInt int color, boolean useDarker) { - if (switchView.getTrackDrawable() != null) { - switchView.setTrackDrawable(modifySwitchDrawable(switchView.getContext(), - switchView.getTrackDrawable(), color, false, true, useDarker)); - } - if (switchView.getThumbDrawable() != null) { - switchView.setThumbDrawable(modifySwitchDrawable(switchView.getContext(), - switchView.getThumbDrawable(), color, true, true, useDarker)); - } - } - - @CheckResult - @Nullable - public static Drawable createTintedDrawable(Context context, - @DrawableRes int res, @ColorInt int color) { - Drawable drawable = ContextCompat.getDrawable(context, res); - return createTintedDrawable(drawable, color); - } - - - // This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise. - @CheckResult - @Nullable - public static Drawable createTintedDrawable(@Nullable Drawable drawable, @ColorInt int color) { - if (drawable == null) return null; - drawable = DrawableCompat.wrap(drawable.mutate()); - DrawableCompat.setTintMode(drawable, PorterDuff.Mode.SRC_IN); - DrawableCompat.setTint(drawable, color); - return drawable; - } - - // This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise. - @CheckResult - @Nullable - public static Drawable createTintedDrawable(@Nullable Drawable drawable, @NonNull ColorStateList sl) { - if (drawable == null) return null; - drawable = DrawableCompat.wrap(drawable.mutate()); - DrawableCompat.setTintList(drawable, sl); - return drawable; - } - - public static void setCursorTint(@NonNull EditText editText, @ColorInt int color) { - try { - Field fCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); - fCursorDrawableRes.setAccessible(true); - int mCursorDrawableRes = fCursorDrawableRes.getInt(editText); - Field fEditor = TextView.class.getDeclaredField("mEditor"); - fEditor.setAccessible(true); - Object editor = fEditor.get(editText); - Class clazz = editor.getClass(); - Field fCursorDrawable = clazz.getDeclaredField("mCursorDrawable"); - fCursorDrawable.setAccessible(true); - Drawable[] drawables = new Drawable[2]; - drawables[0] = ContextCompat.getDrawable(editText.getContext(), mCursorDrawableRes); - drawables[0] = createTintedDrawable(drawables[0], color); - drawables[1] = ContextCompat.getDrawable(editText.getContext(), mCursorDrawableRes); - drawables[1] = createTintedDrawable(drawables[1], color); - fCursorDrawable.set(editor, drawables); - } catch (Exception e) { - e.printStackTrace(); - } - } @SuppressWarnings("JavaReflectionMemberAccess") public static void colorHandles(@NonNull TextView view, int color) { try { @@ -448,4 +76,411 @@ public final class TintHelper { e.printStackTrace(); } } + + @CheckResult + @Nullable + public static Drawable createTintedDrawable(Context context, + @DrawableRes int res, @ColorInt int color) { + Drawable drawable = ContextCompat.getDrawable(context, res); + return createTintedDrawable(drawable, color); + } + + // This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise. + @CheckResult + @Nullable + public static Drawable createTintedDrawable(@Nullable Drawable drawable, @ColorInt int color) { + if (drawable == null) { + return null; + } + drawable = DrawableCompat.wrap(drawable.mutate()); + DrawableCompat.setTintMode(drawable, PorterDuff.Mode.SRC_IN); + DrawableCompat.setTint(drawable, color); + return drawable; + } + + // This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise. + @CheckResult + @Nullable + public static Drawable createTintedDrawable(@Nullable Drawable drawable, @NonNull ColorStateList sl) { + if (drawable == null) { + return null; + } + drawable = DrawableCompat.wrap(drawable.mutate()); + DrawableCompat.setTintList(drawable, sl); + return drawable; + } + + public static void setCursorTint(@NonNull EditText editText, @ColorInt int color) { + try { + Field fCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); + fCursorDrawableRes.setAccessible(true); + int mCursorDrawableRes = fCursorDrawableRes.getInt(editText); + Field fEditor = TextView.class.getDeclaredField("mEditor"); + fEditor.setAccessible(true); + Object editor = fEditor.get(editText); + Class clazz = editor.getClass(); + Field fCursorDrawable = clazz.getDeclaredField("mCursorDrawable"); + fCursorDrawable.setAccessible(true); + Drawable[] drawables = new Drawable[2]; + drawables[0] = ContextCompat.getDrawable(editText.getContext(), mCursorDrawableRes); + drawables[0] = createTintedDrawable(drawables[0], color); + drawables[1] = ContextCompat.getDrawable(editText.getContext(), mCursorDrawableRes); + drawables[1] = createTintedDrawable(drawables[1], color); + fCursorDrawable.set(editor, drawables); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void setTint(@NonNull RadioButton radioButton, @ColorInt int color, boolean useDarker) { + ColorStateList sl = new ColorStateList(new int[][]{ + new int[]{-android.R.attr.state_enabled}, + new int[]{android.R.attr.state_enabled, -android.R.attr.state_checked}, + new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} + }, new int[]{ + // Rdio button includes own alpha for disabled state + ColorUtil.INSTANCE.stripAlpha(ContextCompat.getColor(radioButton.getContext(), + useDarker ? R.color.ate_control_disabled_dark : R.color.ate_control_disabled_light)), + ContextCompat.getColor(radioButton.getContext(), + useDarker ? R.color.ate_control_normal_dark : R.color.ate_control_normal_light), + color + }); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + radioButton.setButtonTintList(sl); + } else { + Drawable d = createTintedDrawable( + ContextCompat.getDrawable(radioButton.getContext(), R.drawable.abc_btn_radio_material), sl); + radioButton.setButtonDrawable(d); + } + } + + public static void setTint(@NonNull SeekBar seekBar, @ColorInt int color, boolean useDarker) { + final ColorStateList s1 = getDisabledColorStateList(color, ContextCompat.getColor(seekBar.getContext(), + useDarker ? R.color.ate_control_disabled_dark : R.color.ate_control_disabled_light)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + seekBar.setThumbTintList(s1); + seekBar.setProgressTintList(s1); + } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) { + Drawable progressDrawable = createTintedDrawable(seekBar.getProgressDrawable(), s1); + seekBar.setProgressDrawable(progressDrawable); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + Drawable thumbDrawable = createTintedDrawable(seekBar.getThumb(), s1); + seekBar.setThumb(thumbDrawable); + } + } else { + PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN; + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { + mode = PorterDuff.Mode.MULTIPLY; + } + if (seekBar.getIndeterminateDrawable() != null) { + seekBar.getIndeterminateDrawable().setColorFilter(color, mode); + } + if (seekBar.getProgressDrawable() != null) { + seekBar.getProgressDrawable().setColorFilter(color, mode); + } + } + } + + public static void setTint(@NonNull ProgressBar progressBar, @ColorInt int color) { + setTint(progressBar, color, false); + } + + public static void setTint(@NonNull ProgressBar progressBar, @ColorInt int color, boolean skipIndeterminate) { + ColorStateList sl = ColorStateList.valueOf(color); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + progressBar.setProgressTintList(sl); + progressBar.setSecondaryProgressTintList(sl); + if (!skipIndeterminate) { + progressBar.setIndeterminateTintList(sl); + } + } else { + PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN; + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { + mode = PorterDuff.Mode.MULTIPLY; + } + if (!skipIndeterminate && progressBar.getIndeterminateDrawable() != null) { + progressBar.getIndeterminateDrawable().setColorFilter(color, mode); + } + if (progressBar.getProgressDrawable() != null) { + progressBar.getProgressDrawable().setColorFilter(color, mode); + } + } + } + + public static void setTint(@NonNull EditText editText, @ColorInt int color, boolean useDarker) { + final ColorStateList editTextColorStateList = new ColorStateList(new int[][]{ + new int[]{-android.R.attr.state_enabled}, + new int[]{android.R.attr.state_enabled, -android.R.attr.state_pressed, -android.R.attr.state_focused}, + new int[]{} + }, new int[]{ + ContextCompat.getColor(editText.getContext(), + useDarker ? R.color.ate_text_disabled_dark : R.color.ate_text_disabled_light), + ContextCompat.getColor(editText.getContext(), + useDarker ? R.color.ate_control_normal_dark : R.color.ate_control_normal_light), + color + }); + if (editText instanceof AppCompatEditText) { + ((AppCompatEditText) editText).setSupportBackgroundTintList(editTextColorStateList); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + editText.setBackgroundTintList(editTextColorStateList); + } + setCursorTint(editText, color); + } + + public static void setTint(@NonNull CheckBox box, @ColorInt int color, boolean useDarker) { + ColorStateList sl = new ColorStateList(new int[][]{ + new int[]{-android.R.attr.state_enabled}, + new int[]{android.R.attr.state_enabled, -android.R.attr.state_checked}, + new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} + }, new int[]{ + ContextCompat.getColor(box.getContext(), + useDarker ? R.color.ate_control_disabled_dark : R.color.ate_control_disabled_light), + ContextCompat.getColor(box.getContext(), + useDarker ? R.color.ate_control_normal_dark : R.color.ate_control_normal_light), + color + }); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + box.setButtonTintList(sl); + } else { + Drawable drawable = createTintedDrawable( + ContextCompat.getDrawable(box.getContext(), R.drawable.abc_btn_check_material), sl); + box.setButtonDrawable(drawable); + } + } + + public static void setTint(@NonNull ImageView image, @ColorInt int color) { + image.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); + } + + public static void setTint(@NonNull Switch switchView, @ColorInt int color, boolean useDarker) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + return; + } + if (switchView.getTrackDrawable() != null) { + switchView.setTrackDrawable(modifySwitchDrawable(switchView.getContext(), + switchView.getTrackDrawable(), color, false, false, useDarker)); + } + if (switchView.getThumbDrawable() != null) { + switchView.setThumbDrawable(modifySwitchDrawable(switchView.getContext(), + switchView.getThumbDrawable(), color, true, false, useDarker)); + } + } + + public static void setTint(@NonNull SwitchCompat switchView, @ColorInt int color, boolean useDarker) { + if (switchView.getTrackDrawable() != null) { + switchView.setTrackDrawable(modifySwitchDrawable(switchView.getContext(), + switchView.getTrackDrawable(), color, false, true, useDarker)); + } + if (switchView.getThumbDrawable() != null) { + switchView.setThumbDrawable(modifySwitchDrawable(switchView.getContext(), + switchView.getThumbDrawable(), color, true, true, useDarker)); + } + } + + public static void setTintAuto(final @NonNull View view, final @ColorInt int color, + boolean background) { + setTintAuto(view, color, background, ATHUtil.INSTANCE.isWindowBackgroundDark(view.getContext())); + } + + @SuppressWarnings("deprecation") + public static void setTintAuto(final @NonNull View view, final @ColorInt int color, + boolean background, final boolean isDark) { + if (!background) { + if (view instanceof FloatingActionButton) { + setTint((FloatingActionButton) view, color, isDark); + } else if (view instanceof RadioButton) { + setTint((RadioButton) view, color, isDark); + } else if (view instanceof SeekBar) { + setTint((SeekBar) view, color, isDark); + } else if (view instanceof ProgressBar) { + setTint((ProgressBar) view, color); + } else if (view instanceof EditText) { + setTint((EditText) view, color, isDark); + } else if (view instanceof CheckBox) { + setTint((CheckBox) view, color, isDark); + } else if (view instanceof ImageView) { + setTint((ImageView) view, color); + } else if (view instanceof Switch) { + setTint((Switch) view, color, isDark); + } else if (view instanceof SwitchCompat) { + setTint((SwitchCompat) view, color, isDark); + } else { + background = true; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && + !background && view.getBackground() instanceof RippleDrawable) { + // Ripples for the above views (e.g. when you tap and hold a switch or checkbox) + RippleDrawable rd = (RippleDrawable) view.getBackground(); + @SuppressLint("PrivateResource") final int unchecked = ContextCompat.getColor(view.getContext(), + isDark ? R.color.ripple_material_dark : R.color.ripple_material_light); + final int checked = ColorUtil.INSTANCE.adjustAlpha(color, 0.4f); + final ColorStateList sl = new ColorStateList( + new int[][]{ + new int[]{-android.R.attr.state_activated, -android.R.attr.state_checked}, + new int[]{android.R.attr.state_activated}, + new int[]{android.R.attr.state_checked} + }, + new int[]{ + unchecked, + checked, + checked + } + ); + rd.setColor(sl); + } + } + if (background) { + // Need to tint the background of a view + if (view instanceof FloatingActionButton || view instanceof Button) { + setTintSelector(view, color, false, isDark); + } else if (view.getBackground() != null) { + Drawable drawable = view.getBackground(); + if (drawable != null) { + drawable = createTintedDrawable(drawable, color); + ViewUtil.INSTANCE.setBackgroundCompat(view, drawable); + } + } + } + } + + @SuppressWarnings("deprecation") + public static void setTintSelector(@NonNull View view, @ColorInt final int color, final boolean darker, + final boolean useDarkTheme) { + final boolean isColorLight = ColorUtil.INSTANCE.isColorLight(color); + final int disabled = ContextCompat.getColor(view.getContext(), + useDarkTheme ? R.color.ate_button_disabled_dark : R.color.ate_button_disabled_light); + final int pressed = ColorUtil.INSTANCE.shiftColor(color, darker ? 0.9f : 1.1f); + final int activated = ColorUtil.INSTANCE.shiftColor(color, darker ? 1.1f : 0.9f); + final int rippleColor = getDefaultRippleColor(view.getContext(), isColorLight); + final int textColor = ContextCompat.getColor(view.getContext(), + isColorLight ? R.color.ate_primary_text_light : R.color.ate_primary_text_dark); + + final ColorStateList sl; + if (view instanceof Button) { + sl = getDisabledColorStateList(color, disabled); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && + view.getBackground() instanceof RippleDrawable) { + RippleDrawable rd = (RippleDrawable) view.getBackground(); + rd.setColor(ColorStateList.valueOf(rippleColor)); + } + + // Disabled text color state for buttons, may get overridden later by ATE tags + final Button button = (Button) view; + button.setTextColor(getDisabledColorStateList(textColor, ContextCompat.getColor(view.getContext(), + useDarkTheme ? R.color.ate_button_text_disabled_dark : R.color.ate_button_text_disabled_light))); + } else if (view instanceof FloatingActionButton) { + // FloatingActionButton doesn't support disabled state? + sl = new ColorStateList(new int[][]{ + new int[]{-android.R.attr.state_pressed}, + new int[]{android.R.attr.state_pressed} + }, new int[]{ + color, + pressed + }); + + final FloatingActionButton fab = (FloatingActionButton) view; + fab.setRippleColor(rippleColor); + fab.setBackgroundTintList(sl); + if (fab.getDrawable() != null) { + fab.setImageDrawable(createTintedDrawable(fab.getDrawable(), textColor)); + } + return; + } else { + sl = new ColorStateList( + new int[][]{ + new int[]{-android.R.attr.state_enabled}, + new int[]{android.R.attr.state_enabled}, + new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}, + new int[]{android.R.attr.state_enabled, android.R.attr.state_activated}, + new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} + }, + new int[]{ + disabled, + color, + pressed, + activated, + activated + } + ); + } + + Drawable drawable = view.getBackground(); + if (drawable != null) { + drawable = createTintedDrawable(drawable, sl); + ViewUtil.INSTANCE.setBackgroundCompat(view, drawable); + } + + if (view instanceof TextView && !(view instanceof Button)) { + final TextView tv = (TextView) view; + tv.setTextColor(getDisabledColorStateList(textColor, ContextCompat.getColor(view.getContext(), + isColorLight ? R.color.ate_text_disabled_light : R.color.ate_text_disabled_dark))); + } + } + + @SuppressLint("PrivateResource") + @ColorInt + private static int getDefaultRippleColor(@NonNull Context context, boolean useDarkRipple) { + // Light ripple is actually translucent black, and vice versa + return ContextCompat.getColor(context, useDarkRipple ? + R.color.ripple_material_light : R.color.ripple_material_dark); + } + + @NonNull + private static ColorStateList getDisabledColorStateList(@ColorInt int normal, @ColorInt int disabled) { + return new ColorStateList(new int[][]{ + new int[]{-android.R.attr.state_enabled}, + new int[]{android.R.attr.state_enabled} + }, new int[]{ + disabled, + normal + }); + } + + private static Drawable modifySwitchDrawable(@NonNull Context context, @NonNull Drawable from, @ColorInt int tint, + boolean thumb, boolean compatSwitch, boolean useDarker) { + if (useDarker) { + tint = ColorUtil.INSTANCE.shiftColor(tint, 1.1f); + } + tint = ColorUtil.INSTANCE.adjustAlpha(tint, (compatSwitch && !thumb) ? 0.5f : 1.0f); + int disabled; + int normal; + if (thumb) { + disabled = ContextCompat.getColor(context, + useDarker ? R.color.ate_switch_thumb_disabled_dark : R.color.ate_switch_thumb_disabled_light); + normal = ContextCompat.getColor(context, + useDarker ? R.color.ate_switch_thumb_normal_dark : R.color.ate_switch_thumb_normal_light); + } else { + disabled = ContextCompat.getColor(context, + useDarker ? R.color.ate_switch_track_disabled_dark : R.color.ate_switch_track_disabled_light); + normal = ContextCompat.getColor(context, + useDarker ? R.color.ate_switch_track_normal_dark : R.color.ate_switch_track_normal_light); + } + + // Stock switch includes its own alpha + if (!compatSwitch) { + normal = ColorUtil.INSTANCE.stripAlpha(normal); + } + + final ColorStateList sl = new ColorStateList( + new int[][]{ + new int[]{-android.R.attr.state_enabled}, + new int[]{android.R.attr.state_enabled, -android.R.attr.state_activated, + -android.R.attr.state_checked}, + new int[]{android.R.attr.state_enabled, android.R.attr.state_activated}, + new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} + }, + new int[]{ + disabled, + normal, + tint, + tint + } + ); + return createTintedDrawable(from, sl); + } + + private static void setTint(final FloatingActionButton view, final int color, final boolean isDark) { + view.setImageTintList(ColorStateList.valueOf(color)); + } } \ No newline at end of file