ReactSwitch.java → Kotlin (#45931)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/45931

Migration to Kotlin.

Changelog: [Android][Changed] Migrated ReactSwitch to Kotlin

Reviewed By: cortinico

Differential Revision: D60898267

fbshipit-source-id: 530e240a071deb3eff3e463f04edc590de03c594
This commit is contained in:
Blake Friedman
2024-08-08 03:17:26 -07:00
committed by Facebook GitHub Bot
parent b7221238aa
commit 03c0e5e2af
2 changed files with 110 additions and 124 deletions
@@ -1,124 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.views.switchview;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
/**
* Switch that has its value controlled by JS. Whenever the value of the switch changes, we do not
* allow any other changes to that switch until JS sets a value explicitly. This stops the Switch
* from changing its value multiple times, when those changes have not been processed by JS first.
*/
/*package*/ class ReactSwitch extends SwitchCompat {
private boolean mAllowChange;
@Nullable private Integer mTrackColorForFalse;
@Nullable private Integer mTrackColorForTrue;
public ReactSwitch(Context context) {
super(context);
mAllowChange = true;
mTrackColorForFalse = null;
mTrackColorForTrue = null;
}
@Override
public void setChecked(boolean checked) {
if (mAllowChange && isChecked() != checked) {
mAllowChange = false;
super.setChecked(checked);
setTrackColor(checked);
} else {
// Even if mAllowChange is set to false or the checked value hasn't changed, we still must
// call the super method, since it will make sure the thumb is moved back to the correct edge.
// Without calling the super method, the thumb might stuck in the middle of the switch.
super.setChecked(isChecked());
}
}
@Override
public void setBackgroundColor(int color) {
setBackground(
new RippleDrawable(
createRippleDrawableColorStateList(color), new ColorDrawable(color), null));
}
void setColor(Drawable drawable, @Nullable Integer color) {
if (color == null) {
drawable.clearColorFilter();
} else {
drawable.setColorFilter(color, PorterDuff.Mode.MULTIPLY);
}
}
public void setTrackColor(@Nullable Integer color) {
setColor(super.getTrackDrawable(), color);
}
public void setThumbColor(@Nullable Integer color) {
setColor(super.getThumbDrawable(), color);
// Set the ripple color if background is instance of RippleDrawable
if (color != null && super.getBackground() instanceof RippleDrawable) {
ColorStateList customColorState = createRippleDrawableColorStateList(color);
((RippleDrawable) super.getBackground()).setColor(customColorState);
}
}
/*package*/ void setOn(boolean on) {
// If the switch has a different value than the value sent by JS, we must change it.
if (isChecked() != on) {
super.setChecked(on);
setTrackColor(on);
}
mAllowChange = true;
}
public void setTrackColorForTrue(@Nullable Integer color) {
if (color == mTrackColorForTrue) {
return;
}
mTrackColorForTrue = color;
if (isChecked()) {
setTrackColor(mTrackColorForTrue);
}
}
public void setTrackColorForFalse(@Nullable Integer color) {
if (color == mTrackColorForFalse) {
return;
}
mTrackColorForFalse = color;
if (!isChecked()) {
setTrackColor(mTrackColorForFalse);
}
}
private void setTrackColor(boolean checked) {
if (mTrackColorForTrue != null || mTrackColorForFalse != null) {
// Update the track color to reflect the new value. We only want to do this if these
// props were actually set from JS; otherwise we'll just reset the color to the default.
Integer currentTrackColor = checked ? mTrackColorForTrue : mTrackColorForFalse;
setTrackColor(currentTrackColor);
}
}
private ColorStateList createRippleDrawableColorStateList(@Nullable Integer color) {
return new ColorStateList(
new int[][] {new int[] {android.R.attr.state_pressed}}, new int[] {color});
}
}
@@ -0,0 +1,110 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.views.switchview
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.RippleDrawable
import androidx.appcompat.widget.SwitchCompat
/**
* Switch that has its value controlled by JS. Whenever the value of the switch changes, we do not
* allow any other changes to that switch until JS sets a value explicitly. This stops the Switch
* from changing its value multiple times, when those changes have not been processed by JS first.
*/
internal class ReactSwitch(context: Context) : SwitchCompat(context) {
private var allowChange = true
private var trackColorForFalse: Int? = null
private var trackColorForTrue: Int? = null
override fun setChecked(checked: Boolean) {
if (allowChange && isChecked != checked) {
allowChange = false
super.setChecked(checked)
setTrackColor(checked)
} else {
// Even if mAllowChange is set to false or the checked value hasn't changed, we still must
// call the super method, since it will make sure the thumb is moved back to the correct edge.
// Without calling the super method, the thumb might stuck in the middle of the switch.
super.setChecked(isChecked)
}
}
override fun setBackgroundColor(color: Int) {
background =
RippleDrawable(createRippleDrawableColorStateList(color), ColorDrawable(color), null)
}
public fun setColor(drawable: Drawable, color: Int?): Unit {
if (color == null) {
drawable.clearColorFilter()
} else {
drawable.setColorFilter(PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY))
}
}
public fun setTrackColor(color: Int?): Unit {
setColor(super.getTrackDrawable(), color)
}
public fun setThumbColor(color: Int?): Unit {
setColor(super.getThumbDrawable(), color)
// Set the ripple color if background is instance of RippleDrawable
if (color != null && super.getBackground() is RippleDrawable) {
val customColorState = createRippleDrawableColorStateList(color)
(super.getBackground() as RippleDrawable).setColor(customColorState)
}
}
public fun setOn(on: Boolean): Unit {
// If the switch has a different value than the value sent by JS, we must change it.
if (isChecked != on) {
super.setChecked(on)
setTrackColor(on)
}
allowChange = true
}
public fun setTrackColorForTrue(color: Int?): Unit {
if (color == trackColorForTrue) {
return
}
trackColorForTrue = color
if (isChecked) {
setTrackColor(trackColorForTrue)
}
}
public fun setTrackColorForFalse(color: Int?): Unit {
if (color == trackColorForFalse) {
return
}
trackColorForFalse = color
if (!isChecked) {
setTrackColor(trackColorForFalse)
}
}
private fun setTrackColor(checked: Boolean) {
if (trackColorForTrue != null || trackColorForFalse != null) {
// Update the track color to reflect the new value. We only want to do this if these
// props were actually set from JS; otherwise we'll just reset the color to the default.
val currentTrackColor = if (checked) trackColorForTrue else trackColorForFalse
setTrackColor(currentTrackColor)
}
}
private fun createRippleDrawableColorStateList(color: Int): ColorStateList =
ColorStateList(arrayOf(intArrayOf(android.R.attr.state_pressed)), intArrayOf(color))
}