Просмотр исходного кода

widget: rewrite in kotlin

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
master
Jason A. Donenfeld 4 лет назад
Родитель
Сommit
1054e54c89
11 измененных файлов: 359 добавлений и 460 удалений
  1. +1
    -2
      ui/src/main/java/com/wireguard/android/widget/EdgeToEdge.kt
  2. +0
    -57
      ui/src/main/java/com/wireguard/android/widget/KeyInputFilter.java
  3. +46
    -0
      ui/src/main/java/com/wireguard/android/widget/KeyInputFilter.kt
  4. +0
    -61
      ui/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java
  5. +49
    -0
      ui/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.kt
  6. +0
    -56
      ui/src/main/java/com/wireguard/android/widget/NameInputFilter.java
  7. +45
    -0
      ui/src/main/java/com/wireguard/android/widget/NameInputFilter.kt
  8. +0
    -221
      ui/src/main/java/com/wireguard/android/widget/SlashDrawable.java
  9. +174
    -0
      ui/src/main/java/com/wireguard/android/widget/SlashDrawable.kt
  10. +0
    -63
      ui/src/main/java/com/wireguard/android/widget/ToggleSwitch.java
  11. +44
    -0
      ui/src/main/java/com/wireguard/android/widget/ToggleSwitch.kt

+ 1
- 2
ui/src/main/java/com/wireguard/android/widget/EdgeToEdge.kt Просмотреть файл

@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget
@@ -15,7 +15,6 @@ import com.google.android.material.floatingactionbutton.ExtendedFloatingActionBu
*/

object EdgeToEdge {

@JvmStatic
fun setUpRoot(root: ViewGroup) {
root.systemUiVisibility =


+ 0
- 57
ui/src/main/java/com/wireguard/android/widget/KeyInputFilter.java Просмотреть файл

@@ -1,57 +0,0 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package com.wireguard.android.widget;

import android.text.InputFilter;
import android.text.SpannableStringBuilder;
import android.text.Spanned;

import com.wireguard.crypto.Key;
import com.wireguard.util.NonNullForAll;

import androidx.annotation.Nullable;

/**
* InputFilter for entering WireGuard private/public keys encoded with base64.
*/

@NonNullForAll
public class KeyInputFilter implements InputFilter {
private static boolean isAllowed(final char c) {
return Character.isLetterOrDigit(c) || c == '+' || c == '/';
}

public static InputFilter newInstance() {
return new KeyInputFilter();
}

@Nullable
@Override
public CharSequence filter(final CharSequence source,
final int sStart, final int sEnd,
final Spanned dest,
final int dStart, final int dEnd) {
SpannableStringBuilder replacement = null;
int rIndex = 0;
final int dLength = dest.length();
for (int sIndex = sStart; sIndex < sEnd; ++sIndex) {
final char c = source.charAt(sIndex);
final int dIndex = dStart + (sIndex - sStart);
// Restrict characters to the base64 character set.
// Ensure adding this character does not push the length over the limit.
if (((dIndex + 1 < Key.Format.BASE64.getLength() && isAllowed(c)) ||
(dIndex + 1 == Key.Format.BASE64.getLength() && c == '=')) &&
dLength + (sIndex - sStart) < Key.Format.BASE64.getLength()) {
++rIndex;
} else {
if (replacement == null)
replacement = new SpannableStringBuilder(source, sStart, sEnd);
replacement.delete(rIndex, rIndex + 1);
}
}
return replacement;
}
}

+ 46
- 0
ui/src/main/java/com/wireguard/android/widget/KeyInputFilter.kt Просмотреть файл

@@ -0,0 +1,46 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget

import android.text.InputFilter
import android.text.SpannableStringBuilder
import android.text.Spanned
import com.wireguard.crypto.Key

/**
* InputFilter for entering WireGuard private/public keys encoded with base64.
*/
class KeyInputFilter : InputFilter {
override fun filter(source: CharSequence,
sStart: Int, sEnd: Int,
dest: Spanned,
dStart: Int, dEnd: Int): CharSequence? {
var replacement: SpannableStringBuilder? = null
var rIndex = 0
val dLength = dest.length
for (sIndex in sStart until sEnd) {
val c = source[sIndex]
val dIndex = dStart + (sIndex - sStart)
// Restrict characters to the base64 character set.
// Ensure adding this character does not push the length over the limit.
if ((dIndex + 1 < Key.Format.BASE64.length && isAllowed(c) ||
dIndex + 1 == Key.Format.BASE64.length && c == '=') &&
dLength + (sIndex - sStart) < Key.Format.BASE64.length) {
++rIndex
} else {
if (replacement == null) replacement = SpannableStringBuilder(source, sStart, sEnd)
replacement.delete(rIndex, rIndex + 1)
}
}
return replacement
}

companion object {
private fun isAllowed(c: Char) = Character.isLetterOrDigit(c) || c == '+' || c == '/'

@JvmStatic
fun newInstance() = KeyInputFilter()
}
}

+ 0
- 61
ui/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java Просмотреть файл

@@ -1,61 +0,0 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package com.wireguard.android.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;

import com.wireguard.android.R;
import com.wireguard.util.NonNullForAll;

@NonNullForAll
public class MultiselectableRelativeLayout extends RelativeLayout {
private static final int[] STATE_MULTISELECTED = {R.attr.state_multiselected};
private boolean multiselected;

public MultiselectableRelativeLayout(final Context context) {
super(context);
}

public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs) {
super(context, attrs);
}

public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
protected int[] onCreateDrawableState(final int extraSpace) {
if (multiselected) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
mergeDrawableStates(drawableState, STATE_MULTISELECTED);
return drawableState;
}
return super.onCreateDrawableState(extraSpace);
}

public void setMultiSelected(final boolean on) {
if (!multiselected) {
multiselected = true;
refreshDrawableState();
}
setActivated(on);
}

public void setSingleSelected(final boolean on) {
if (multiselected) {
multiselected = false;
refreshDrawableState();
}
setActivated(on);
}
}

+ 49
- 0
ui/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.kt Просмотреть файл

@@ -0,0 +1,49 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.RelativeLayout
import com.wireguard.android.R

class MultiselectableRelativeLayout : RelativeLayout {
private var multiselected = false

constructor(context: Context?) : super(context) {}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {}

override fun onCreateDrawableState(extraSpace: Int): IntArray {
if (multiselected) {
val drawableState = super.onCreateDrawableState(extraSpace + 1)
View.mergeDrawableStates(drawableState, STATE_MULTISELECTED)
return drawableState
}
return super.onCreateDrawableState(extraSpace)
}

fun setMultiSelected(on: Boolean) {
if (!multiselected) {
multiselected = true
refreshDrawableState()
}
isActivated = on
}

fun setSingleSelected(on: Boolean) {
if (multiselected) {
multiselected = false
refreshDrawableState()
}
isActivated = on
}

companion object {
private val STATE_MULTISELECTED = intArrayOf(R.attr.state_multiselected)
}
}

+ 0
- 56
ui/src/main/java/com/wireguard/android/widget/NameInputFilter.java Просмотреть файл

@@ -1,56 +0,0 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package com.wireguard.android.widget;

import android.text.InputFilter;
import android.text.SpannableStringBuilder;
import android.text.Spanned;

import com.wireguard.android.backend.Tunnel;
import com.wireguard.util.NonNullForAll;

import androidx.annotation.Nullable;

/**
* InputFilter for entering WireGuard configuration names (Linux interface names).
*/

@NonNullForAll
public class NameInputFilter implements InputFilter {
private static boolean isAllowed(final char c) {
return Character.isLetterOrDigit(c) || "_=+.-".indexOf(c) >= 0;
}

public static InputFilter newInstance() {
return new NameInputFilter();
}

@Nullable
@Override
public CharSequence filter(final CharSequence source,
final int sStart, final int sEnd,
final Spanned dest,
final int dStart, final int dEnd) {
SpannableStringBuilder replacement = null;
int rIndex = 0;
final int dLength = dest.length();
for (int sIndex = sStart; sIndex < sEnd; ++sIndex) {
final char c = source.charAt(sIndex);
final int dIndex = dStart + (sIndex - sStart);
// Restrict characters to those valid in interfaces.
// Ensure adding this character does not push the length over the limit.
if ((dIndex < Tunnel.NAME_MAX_LENGTH && isAllowed(c)) &&
dLength + (sIndex - sStart) < Tunnel.NAME_MAX_LENGTH) {
++rIndex;
} else {
if (replacement == null)
replacement = new SpannableStringBuilder(source, sStart, sEnd);
replacement.delete(rIndex, rIndex + 1);
}
}
return replacement;
}
}

+ 45
- 0
ui/src/main/java/com/wireguard/android/widget/NameInputFilter.kt Просмотреть файл

@@ -0,0 +1,45 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget

import android.text.InputFilter
import android.text.SpannableStringBuilder
import android.text.Spanned
import com.wireguard.android.backend.Tunnel

/**
* InputFilter for entering WireGuard configuration names (Linux interface names).
*/
class NameInputFilter : InputFilter {
override fun filter(source: CharSequence,
sStart: Int, sEnd: Int,
dest: Spanned,
dStart: Int, dEnd: Int): CharSequence? {
var replacement: SpannableStringBuilder? = null
var rIndex = 0
val dLength = dest.length
for (sIndex in sStart until sEnd) {
val c = source[sIndex]
val dIndex = dStart + (sIndex - sStart)
// Restrict characters to those valid in interfaces.
// Ensure adding this character does not push the length over the limit.
if (dIndex < Tunnel.NAME_MAX_LENGTH && isAllowed(c) &&
dLength + (sIndex - sStart) < Tunnel.NAME_MAX_LENGTH) {
++rIndex
} else {
if (replacement == null) replacement = SpannableStringBuilder(source, sStart, sEnd)
replacement.delete(rIndex, rIndex + 1)
}
}
return replacement
}

companion object {
private fun isAllowed(c: Char) = Character.isLetterOrDigit(c) || "_=+.-".indexOf(c) >= 0

@JvmStatic
fun newInstance() = NameInputFilter()
}
}

+ 0
- 221
ui/src/main/java/com/wireguard/android/widget/SlashDrawable.java Просмотреть файл

@@ -1,221 +0,0 @@
/*
* Copyright © 2018 The Android Open Source Project
* Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package com.wireguard.android.widget;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.FloatProperty;

import com.wireguard.util.NonNullForAll;

import androidx.annotation.ColorInt;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

@RequiresApi(Build.VERSION_CODES.N)
@NonNullForAll
public class SlashDrawable extends Drawable {

private static final float CENTER_X = 10.65f;
private static final float CENTER_Y = 11.869239f;
private static final float CORNER_RADIUS = Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 0f : 1f;
// Draw the slash washington-monument style; rotate to no-u-turn style
private static final float DEFAULT_ROTATION = -45f;
private static final long QS_ANIM_LENGTH = 350;
private static final float SCALE = 24f;
private static final float SLASH_HEIGHT = 28f;
// These values are derived in un-rotated (vertical) orientation
private static final float SLASH_WIDTH = 1.8384776f;
// Bottom is derived during animation
private static final float LEFT = (CENTER_X - (SLASH_WIDTH / 2)) / SCALE;
private static final float RIGHT = (CENTER_X + (SLASH_WIDTH / 2)) / SCALE;
private static final float TOP = (CENTER_Y - (SLASH_HEIGHT / 2)) / SCALE;
private static final FloatProperty mSlashLengthProp = new FloatProperty<SlashDrawable>("slashLength") {
@Override
public Float get(final SlashDrawable object) {
return object.mCurrentSlashLength;
}

@Override
public void setValue(final SlashDrawable object, final float value) {
object.mCurrentSlashLength = value;
}
};
private final Drawable mDrawable;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Path mPath = new Path();
private final RectF mSlashRect = new RectF(0, 0, 0, 0);
private boolean mAnimationEnabled = true;
// Animate this value on change
private float mCurrentSlashLength;
private float mRotation;
private boolean mSlashed;

public SlashDrawable(final Drawable d) {
mDrawable = d;
}

@SuppressWarnings("deprecation")
@Override
public void draw(final Canvas canvas) {
canvas.save();
final Matrix m = new Matrix();
final int width = getBounds().width();
final int height = getBounds().height();
final float radiusX = scale(CORNER_RADIUS, width);
final float radiusY = scale(CORNER_RADIUS, height);
updateRect(
scale(LEFT, width),
scale(TOP, height),
scale(RIGHT, width),
scale(TOP + mCurrentSlashLength, height)
);

mPath.reset();
// Draw the slash vertically
mPath.addRoundRect(mSlashRect, radiusX, radiusY, Direction.CW);
// Rotate -45 + desired rotation
m.setRotate(mRotation + DEFAULT_ROTATION, width / 2, height / 2);
mPath.transform(m);
canvas.drawPath(mPath, mPaint);

// Rotate back to vertical
m.setRotate(-mRotation - DEFAULT_ROTATION, width / 2, height / 2);
mPath.transform(m);

// Draw another rect right next to the first, for clipping
m.setTranslate(mSlashRect.width(), 0);
mPath.transform(m);
mPath.addRoundRect(mSlashRect, 1.0f * width, 1.0f * height, Direction.CW);
m.setRotate(mRotation + DEFAULT_ROTATION, width / 2, height / 2);
mPath.transform(m);

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
canvas.clipPath(mPath, Region.Op.DIFFERENCE);
else
canvas.clipOutPath(mPath);

mDrawable.draw(canvas);
canvas.restore();
}

@Override
public int getIntrinsicHeight() {
return mDrawable.getIntrinsicHeight();
}

@Override
public int getIntrinsicWidth() {
return mDrawable.getIntrinsicWidth();
}

@SuppressWarnings("deprecation")
@Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}

@Override
protected void onBoundsChange(final Rect bounds) {
super.onBoundsChange(bounds);
mDrawable.setBounds(bounds);
}

private float scale(final float frac, final int width) {
return frac * width;
}

@Override
public void setAlpha(@IntRange(from = 0, to = 255) final int alpha) {
mDrawable.setAlpha(alpha);
mPaint.setAlpha(alpha);
}

public void setAnimationEnabled(final boolean enabled) {
mAnimationEnabled = enabled;
}

@Override
public void setColorFilter(@Nullable final ColorFilter colorFilter) {
mDrawable.setColorFilter(colorFilter);
mPaint.setColorFilter(colorFilter);
}

private void setDrawableTintList(@Nullable final ColorStateList tint) {
mDrawable.setTintList(tint);
}

public void setRotation(final float rotation) {
if (mRotation == rotation)
return;
mRotation = rotation;
invalidateSelf();
}

@SuppressWarnings("unchecked")
public void setSlashed(final boolean slashed) {
if (mSlashed == slashed) return;

mSlashed = slashed;

final float end = mSlashed ? SLASH_HEIGHT / SCALE : 0f;
final float start = mSlashed ? 0f : SLASH_HEIGHT / SCALE;

if (mAnimationEnabled) {
final ObjectAnimator anim = ObjectAnimator.ofFloat(this, mSlashLengthProp, start, end);
anim.addUpdateListener((ValueAnimator valueAnimator) -> invalidateSelf());
anim.setDuration(QS_ANIM_LENGTH);
anim.start();
} else {
mCurrentSlashLength = end;
invalidateSelf();
}
}

@Override
public void setTint(@ColorInt final int tintColor) {
super.setTint(tintColor);
mDrawable.setTint(tintColor);
mPaint.setColor(tintColor);
}

@Override
public void setTintList(@Nullable final ColorStateList tint) {
super.setTintList(tint);
setDrawableTintList(tint);
mPaint.setColor(tint == null ? 0 : tint.getDefaultColor());
invalidateSelf();
}

@Override
public void setTintMode(final Mode tintMode) {
super.setTintMode(tintMode);
mDrawable.setTintMode(tintMode);
}

private void updateRect(final float left, final float top, final float right, final float bottom) {
mSlashRect.left = left;
mSlashRect.top = top;
mSlashRect.right = right;
mSlashRect.bottom = bottom;
}
}

+ 174
- 0
ui/src/main/java/com/wireguard/android/widget/SlashDrawable.kt Просмотреть файл

@@ -0,0 +1,174 @@
/*
* Copyright © 2018 The Android Open Source Project
* Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget

import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.res.ColorStateList
import android.graphics.*
import android.graphics.drawable.Drawable
import android.os.Build
import android.util.FloatProperty
import android.util.Property
import androidx.annotation.ColorInt
import androidx.annotation.IntRange
import androidx.annotation.RequiresApi

@RequiresApi(Build.VERSION_CODES.N)
class SlashDrawable(private val mDrawable: Drawable) : Drawable() {
private val mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private val mPath = Path()
private val mSlashRect = RectF()
private var mAnimationEnabled = true
// Animate this value on change
private var mCurrentSlashLength = 0f
private var mRotation = 0f
private var mSlashed = false

override fun draw(canvas: Canvas) {
canvas.save()
val m = Matrix()
val width = bounds.width()
val height = bounds.height()
val radiusX = scale(CORNER_RADIUS, width)
val radiusY = scale(CORNER_RADIUS, height)
updateRect(
scale(LEFT, width),
scale(TOP, height),
scale(RIGHT, width),
scale(TOP + mCurrentSlashLength, height)
)
mPath.reset()
// Draw the slash vertically
mPath.addRoundRect(mSlashRect, radiusX, radiusY, Path.Direction.CW)
// Rotate -45 + desired rotation
m.setRotate(mRotation + DEFAULT_ROTATION, width / 2f, height / 2f)
mPath.transform(m)
canvas.drawPath(mPath, mPaint)

// Rotate back to vertical
m.setRotate(-mRotation - DEFAULT_ROTATION, width / 2f, height / 2f)
mPath.transform(m)

// Draw another rect right next to the first, for clipping
m.setTranslate(mSlashRect.width(), 0f)
mPath.transform(m)
mPath.addRoundRect(mSlashRect, 1f * width, 1f * height, Path.Direction.CW)
m.setRotate(mRotation + DEFAULT_ROTATION, width / 2f, height / 2f)
mPath.transform(m)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) canvas.clipPath(mPath, Region.Op.DIFFERENCE) else canvas.clipOutPath(mPath)
mDrawable.draw(canvas)
canvas.restore()
}

override fun getIntrinsicHeight() = mDrawable.intrinsicHeight

override fun getIntrinsicWidth() = mDrawable.intrinsicWidth

override fun getOpacity() = PixelFormat.OPAQUE

override fun onBoundsChange(bounds: Rect) {
super.onBoundsChange(bounds)
mDrawable.bounds = bounds
}

private fun scale(frac: Float, width: Int) = frac * width

override fun setAlpha(@IntRange(from = 0, to = 255) alpha: Int) {
mDrawable.alpha = alpha
mPaint.alpha = alpha
}

fun setAnimationEnabled(enabled: Boolean) {
mAnimationEnabled = enabled
}

override fun setColorFilter(colorFilter: ColorFilter?) {
mDrawable.colorFilter = colorFilter
mPaint.colorFilter = colorFilter
}

private fun setDrawableTintList(tint: ColorStateList?) {
mDrawable.setTintList(tint)
}

fun setRotation(rotation: Float) {
if (mRotation == rotation) return
mRotation = rotation
invalidateSelf()
}

fun setSlashed(slashed: Boolean) {
if (mSlashed == slashed) return
mSlashed = slashed
val end = if (mSlashed) SLASH_HEIGHT / SCALE else 0f
val start = if (mSlashed) 0f else SLASH_HEIGHT / SCALE
if (mAnimationEnabled) {
val anim = ObjectAnimator.ofFloat(this, mSlashLengthProp, start, end)
anim.addUpdateListener { _ -> invalidateSelf() }
anim.duration = QS_ANIM_LENGTH
anim.start()
} else {
mCurrentSlashLength = end
invalidateSelf()
}
}

override fun setTint(@ColorInt tintColor: Int) {
super.setTint(tintColor)
mDrawable.setTint(tintColor)
mPaint.color = tintColor
}

override fun setTintList(tint: ColorStateList?) {
super.setTintList(tint)
setDrawableTintList(tint)
mPaint.color = tint?.defaultColor ?: 0
invalidateSelf()
}

override fun setTintMode(tintMode: PorterDuff.Mode?) {
super.setTintMode(tintMode)
mDrawable.setTintMode(tintMode)
}

private fun updateRect(left: Float, top: Float, right: Float, bottom: Float) {
mSlashRect.left = left
mSlashRect.top = top
mSlashRect.right = right
mSlashRect.bottom = bottom
}

companion object {
private const val CENTER_X = 10.65f
private const val CENTER_Y = 11.869239f
private val CORNER_RADIUS = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) 0f else 1f

// Draw the slash washington-monument style; rotate to no-u-turn style
private const val DEFAULT_ROTATION = -45f
private const val QS_ANIM_LENGTH: Long = 350
private const val SCALE = 24f
private const val SLASH_HEIGHT = 28f

// These values are derived in un-rotated (vertical) orientation
private const val SLASH_WIDTH = 1.8384776f

// Bottom is derived during animation
private const val LEFT = (CENTER_X - SLASH_WIDTH / 2) / SCALE
private const val RIGHT = (CENTER_X + SLASH_WIDTH / 2) / SCALE
private const val TOP = (CENTER_Y - SLASH_HEIGHT / 2) / SCALE
private val mSlashLengthProp: FloatProperty<SlashDrawable> = object : FloatProperty<SlashDrawable>("slashLength") {
override fun get(obj: SlashDrawable): Float {
return obj.mCurrentSlashLength
}

override fun setValue(obj: SlashDrawable, value: Float) {
obj.mCurrentSlashLength = value
}
}
}

}

+ 0
- 63
ui/src/main/java/com/wireguard/android/widget/ToggleSwitch.java Просмотреть файл

@@ -1,63 +0,0 @@
/*
* Copyright © 2013 The Android Open Source Project
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package com.wireguard.android.widget;

import android.content.Context;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.widget.Switch;

import com.wireguard.util.NonNullForAll;

import androidx.annotation.Nullable;

@NonNullForAll
public class ToggleSwitch extends Switch {
private boolean isRestoringState;
@Nullable private OnBeforeCheckedChangeListener listener;

public ToggleSwitch(final Context context) {
this(context, null);
}

@SuppressWarnings({"SameParameterValue", "WeakerAccess"})
public ToggleSwitch(final Context context, @Nullable final AttributeSet attrs) {
super(context, attrs);
}

@Override
public void onRestoreInstanceState(final Parcelable state) {
isRestoringState = true;
super.onRestoreInstanceState(state);
isRestoringState = false;
}

@Override
public void setChecked(final boolean checked) {
if (checked == isChecked())
return;
if (isRestoringState || listener == null) {
super.setChecked(checked);
return;
}
setEnabled(false);
listener.onBeforeCheckedChanged(this, checked);
}

public void setCheckedInternal(final boolean checked) {
super.setChecked(checked);
setEnabled(true);
}

public void setOnBeforeCheckedChangeListener(final OnBeforeCheckedChangeListener listener) {
this.listener = listener;
}

public interface OnBeforeCheckedChangeListener {
void onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);
}
}

+ 44
- 0
ui/src/main/java/com/wireguard/android/widget/ToggleSwitch.kt Просмотреть файл

@@ -0,0 +1,44 @@
/*
* Copyright © 2013 The Android Open Source Project
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget

import android.content.Context
import android.os.Parcelable
import android.util.AttributeSet
import android.widget.Switch

class ToggleSwitch @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null) : Switch(context, attrs) {
private var isRestoringState = false
private var listener: OnBeforeCheckedChangeListener? = null
override fun onRestoreInstanceState(state: Parcelable) {
isRestoringState = true
super.onRestoreInstanceState(state)
isRestoringState = false
}

override fun setChecked(checked: Boolean) {
if (checked == isChecked) return
if (isRestoringState || listener == null) {
super.setChecked(checked)
return
}
isEnabled = false
listener!!.onBeforeCheckedChanged(this, checked)
}

fun setCheckedInternal(checked: Boolean) {
super.setChecked(checked)
isEnabled = true
}

fun setOnBeforeCheckedChangeListener(listener: OnBeforeCheckedChangeListener?) {
this.listener = listener
}

interface OnBeforeCheckedChangeListener {
fun onBeforeCheckedChanged(toggleSwitch: ToggleSwitch?, checked: Boolean)
}
}

Загрузка…
Отмена
Сохранить