diff options
author | Eric Kuck <eric@bluelinelabs.com> | 2018-07-11 12:48:18 -0500 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2018-07-11 21:03:22 +0200 |
commit | 5463086e7533f647e4a29a964d4b54a4e79ddca1 (patch) | |
tree | 9bd0a78e4940d15f371e0cca9d7a827e2ba9bf6c | |
parent | 1f7bdd4f5f9fadb51f6c61c453f51533e4886dfa (diff) |
fab: use support library's rendering
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
19 files changed, 108 insertions, 640 deletions
diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java index 88d9c0b7..5969aa9a 100644 --- a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java +++ b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java @@ -35,7 +35,6 @@ import com.wireguard.android.databinding.TunnelListFragmentBinding; import com.wireguard.android.databinding.TunnelListItemBinding; import com.wireguard.android.model.Tunnel; import com.wireguard.android.util.ExceptionLoggers; -import com.wireguard.android.widget.ToggleSwitch; import com.wireguard.config.Config; import java.io.BufferedReader; diff --git a/app/src/main/java/com/wireguard/android/widget/fab/AddFloatingActionButton.java b/app/src/main/java/com/wireguard/android/widget/fab/AddFloatingActionButton.java deleted file mode 100644 index 7dcdd649..00000000 --- a/app/src/main/java/com/wireguard/android/widget/fab/AddFloatingActionButton.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright © 2014 Jerzy Chalupski - * Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget.fab; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Paint.Style; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.shapes.Shape; -import android.support.annotation.ColorRes; -import android.support.annotation.DrawableRes; -import android.support.v4.content.ContextCompat; -import android.util.AttributeSet; - -import com.wireguard.android.R; - -public class AddFloatingActionButton extends FloatingActionButton { - int mPlusColor; - - public AddFloatingActionButton(final Context context) { - this(context, null); - } - - public AddFloatingActionButton(final Context context, final AttributeSet attrs) { - super(context, attrs); - } - - public AddFloatingActionButton(final Context context, final AttributeSet attrs, final int defStyle) { - super(context, attrs, defStyle); - } - - @Override - void init(final Context context, final AttributeSet attributeSet) { - final TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.AddFloatingActionButton, 0, 0); - mPlusColor = attr.getColor(R.styleable.AddFloatingActionButton_fab_plusIconColor, FloatingActionButton.getColorFromTheme(context, android.R.attr.colorBackground, android.R.color.white)); - attr.recycle(); - - super.init(context, attributeSet); - } - - /** - * @return the current Color of plus icon. - */ - public int getPlusColor() { - return mPlusColor; - } - - public void setPlusColor(final int color) { - if (mPlusColor != color) { - mPlusColor = color; - updateBackground(); - } - } - - public void setPlusColorResId(@ColorRes final int plusColor) { - setPlusColor(ContextCompat.getColor(getContext(), plusColor)); - } - - @Override - public void setIcon(@DrawableRes final int icon) { - throw new UnsupportedOperationException("Use FloatingActionButton if you want to use custom icon"); - } - - @Override - Drawable getIconDrawable() { - final float iconSize = getDimension(R.dimen.fab_icon_size); - final float iconHalfSize = iconSize / 2f; - - final float plusSize = getDimension(R.dimen.fab_plus_icon_size); - final float plusHalfStroke = getDimension(R.dimen.fab_plus_icon_stroke) / 2f; - final float plusOffset = (iconSize - plusSize) / 2f; - - final Shape shape = new Shape() { - @Override - public void draw(final Canvas canvas, final Paint paint) { - canvas.drawRect(plusOffset, iconHalfSize - plusHalfStroke, iconSize - plusOffset, iconHalfSize + plusHalfStroke, paint); - canvas.drawRect(iconHalfSize - plusHalfStroke, plusOffset, iconHalfSize + plusHalfStroke, iconSize - plusOffset, paint); - } - }; - - final ShapeDrawable drawable = new ShapeDrawable(shape); - - final Paint paint = drawable.getPaint(); - paint.setColor(mPlusColor); - paint.setStyle(Style.FILL); - paint.setAntiAlias(true); - - return drawable; - } -} diff --git a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButton.java b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButton.java deleted file mode 100644 index 417ae52d..00000000 --- a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButton.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright © 2014 Jerzy Chalupski - * Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget.fab; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.Paint.Style; -import android.graphics.Rect; -import android.graphics.Shader; -import android.graphics.Shader.TileMode; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.ShapeDrawable.ShaderFactory; -import android.graphics.drawable.StateListDrawable; -import android.graphics.drawable.shapes.OvalShape; -import android.support.annotation.ColorRes; -import android.support.annotation.DimenRes; -import android.support.annotation.DrawableRes; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.AppCompatImageButton; -import android.util.AttributeSet; -import android.widget.TextView; - -import com.wireguard.android.R; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -public class FloatingActionButton extends AppCompatImageButton { - - public static final int SIZE_NORMAL = 0; - public static final int SIZE_MINI = 1; - int mColorNormal; - int mColorPressed; - int mColorDisabled; - String mTitle; - boolean mStrokeVisible; - @DrawableRes - private int mIcon; - private Drawable mIconDrawable; - private int mSize; - - private float mCircleSize; - private float mShadowRadius; - private float mShadowOffset; - private int mDrawableSize; - public FloatingActionButton(final Context context) { - this(context, null); - } - - public FloatingActionButton(final Context context, final AttributeSet attrs) { - super(context, attrs); - init(context, attrs); - } - - public FloatingActionButton(final Context context, final AttributeSet attrs, final int defStyle) { - super(context, attrs, defStyle); - init(context, attrs); - } - - public static int getColorFromTheme(final Context context, final int themeResource, @ColorRes final int fallback) { - final TypedArray a = context.obtainStyledAttributes(new int[]{themeResource}); - try { - return a.getColor(0, ContextCompat.getColor(context, fallback)); - } finally { - a.recycle(); - } - } - - void init(final Context context, final AttributeSet attributeSet) { - final TypedArray attr = context.obtainStyledAttributes(attributeSet, - R.styleable.FloatingActionButton, 0, 0); - mColorNormal = attr.getColor(R.styleable.FloatingActionButton_fab_colorNormal, - getColorFromTheme(context, android.R.attr.colorAccent, android.R.color.holo_blue_bright)); - mColorPressed = attr.getColor(R.styleable.FloatingActionButton_fab_colorPressed, - darkenOrLightenColor(mColorNormal)); //TODO(msf): use getColorForState on the accent color from theme instead to get darker states - mColorDisabled = attr.getColor(R.styleable.FloatingActionButton_fab_colorDisabled, - ContextCompat.getColor(context, android.R.color.darker_gray)); //TODO(msf): load from theme - mSize = attr.getInt(R.styleable.FloatingActionButton_fab_size, SIZE_NORMAL); - mIcon = attr.getResourceId(R.styleable.FloatingActionButton_fab_icon, 0); - mTitle = attr.getString(R.styleable.FloatingActionButton_fab_title); - mStrokeVisible = attr.getBoolean(R.styleable.FloatingActionButton_fab_stroke_visible, true); - attr.recycle(); - - updateCircleSize(); - mShadowRadius = getDimension(R.dimen.fab_shadow_radius); - mShadowOffset = getDimension(R.dimen.fab_shadow_offset); - updateDrawableSize(); - - updateBackground(); - } - - private void updateDrawableSize() { - mDrawableSize = (int) (mCircleSize + 2 * mShadowRadius); - } - - private void updateCircleSize() { - mCircleSize = getDimension(mSize == SIZE_NORMAL ? R.dimen.fab_size_normal : R.dimen.fab_size_mini); - } - - @FAB_SIZE - public int getSize() { - return mSize; - } - - public void setSize(@FAB_SIZE final int size) { - if (size != SIZE_MINI && size != SIZE_NORMAL) { - throw new IllegalArgumentException("Use @FAB_SIZE constants only!"); - } - - if (mSize != size) { - mSize = size; - updateCircleSize(); - updateDrawableSize(); - updateBackground(); - } - } - - public void setIcon(@DrawableRes final int icon) { - if (mIcon != icon) { - mIcon = icon; - mIconDrawable = null; - updateBackground(); - } - } - - /** - * @return the current Color for normal state. - */ - public int getColorNormal() { - return mColorNormal; - } - - public void setColorNormal(final int color) { - if (mColorNormal != color) { - mColorNormal = color; - updateBackground(); - } - } - - public void setColorNormalResId(@ColorRes final int colorNormal) { - setColorNormal(ContextCompat.getColor(getContext(), colorNormal)); - } - - /** - * @return the current color for pressed state. - */ - public int getColorPressed() { - return mColorPressed; - } - - public void setColorPressed(final int color) { - if (mColorPressed != color) { - mColorPressed = color; - updateBackground(); - } - } - - public void setColorPressedResId(@ColorRes final int colorPressed) { - setColorPressed(ContextCompat.getColor(getContext(), colorPressed)); - } - - /** - * @return the current color for disabled state. - */ - public int getColorDisabled() { - return mColorDisabled; - } - - public void setColorDisabled(final int color) { - if (mColorDisabled != color) { - mColorDisabled = color; - updateBackground(); - } - } - - public void setColorDisabledResId(@ColorRes final int colorDisabled) { - setColorDisabled(ContextCompat.getColor(getContext(), colorDisabled)); - } - - public boolean isStrokeVisible() { - return mStrokeVisible; - } - - public void setStrokeVisible(final boolean visible) { - if (mStrokeVisible != visible) { - mStrokeVisible = visible; - updateBackground(); - } - } - - float getDimension(@DimenRes final int id) { - return getResources().getDimension(id); - } - - TextView getLabelView() { - return (TextView) getTag(R.id.fab_label); - } - - public String getTitle() { - return mTitle; - } - - public void setTitle(final String title) { - mTitle = title; - final TextView label = getLabelView(); - if (label != null) { - label.setText(title); - } - } - - @Override - protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - setMeasuredDimension(mDrawableSize, mDrawableSize); - } - - void updateBackground() { - final float strokeWidth = getDimension(R.dimen.fab_stroke_width); - final float halfStrokeWidth = strokeWidth / 2f; - - final LayerDrawable layerDrawable = new LayerDrawable( - new Drawable[]{ - //TODO(msf); replace these pngs with programatic elevation - getResources().getDrawable(mSize == SIZE_NORMAL ? R.drawable.fab_bg_normal : R.drawable.fab_bg_mini, null), - createFillDrawable(strokeWidth), - createOuterStrokeDrawable(strokeWidth), - getIconDrawable() - }); - - final int iconOffset = (int) (mCircleSize - getDimension(R.dimen.fab_icon_size)) / 2; - - final int circleInsetHorizontal = (int) (mShadowRadius); - final int circleInsetTop = (int) (mShadowRadius - mShadowOffset); - final int circleInsetBottom = (int) (mShadowRadius + mShadowOffset); - - layerDrawable.setLayerInset(1, - circleInsetHorizontal, - circleInsetTop, - circleInsetHorizontal, - circleInsetBottom); - - layerDrawable.setLayerInset(2, - (int) (circleInsetHorizontal - halfStrokeWidth), - (int) (circleInsetTop - halfStrokeWidth), - (int) (circleInsetHorizontal - halfStrokeWidth), - (int) (circleInsetBottom - halfStrokeWidth)); - - layerDrawable.setLayerInset(3, - circleInsetHorizontal + iconOffset, - circleInsetTop + iconOffset, - circleInsetHorizontal + iconOffset, - circleInsetBottom + iconOffset); - - setBackground(layerDrawable); - } - - Drawable getIconDrawable() { - if (mIconDrawable != null) { - return mIconDrawable; - } else if (mIcon != 0) { - return ContextCompat.getDrawable(getContext(), mIcon); - } else { - return new ColorDrawable(Color.TRANSPARENT); - } - } - - public void setIconDrawable(@NonNull final Drawable iconDrawable) { - if (mIconDrawable != iconDrawable) { - mIcon = 0; - mIconDrawable = iconDrawable; - updateBackground(); - } - } - - private StateListDrawable createFillDrawable(final float strokeWidth) { - final StateListDrawable drawable = new StateListDrawable(); - drawable.addState(new int[]{-android.R.attr.state_enabled}, createCircleDrawable(mColorDisabled, strokeWidth)); - drawable.addState(new int[]{android.R.attr.state_pressed}, createCircleDrawable(mColorPressed, strokeWidth)); - drawable.addState(new int[]{}, createCircleDrawable(mColorNormal, strokeWidth)); - return drawable; - } - - private Drawable createCircleDrawable(final int color, final float strokeWidth) { - final int alpha = Color.alpha(color); - final int opaqueColor = opaque(color); - - final ShapeDrawable fillDrawable = new ShapeDrawable(new OvalShape()); - - final Paint paint = fillDrawable.getPaint(); - paint.setAntiAlias(true); - paint.setColor(opaqueColor); - - final Drawable[] layers = { - fillDrawable, - createInnerStrokesDrawable(opaqueColor, strokeWidth) - }; - - final LayerDrawable drawable = alpha == 255 || !mStrokeVisible - ? new LayerDrawable(layers) - : new TranslucentLayerDrawable(alpha, layers); - - final int halfStrokeWidth = (int) (strokeWidth / 2f); - drawable.setLayerInset(1, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth); - - return drawable; - } - - private static Drawable createOuterStrokeDrawable(final float strokeWidth) { - final ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape()); - - final Paint paint = shapeDrawable.getPaint(); - paint.setAntiAlias(true); - paint.setStrokeWidth(strokeWidth); - paint.setStyle(Style.STROKE); - paint.setColor(Color.BLACK); - paint.setAlpha(opacityToAlpha(0.02f)); - - return shapeDrawable; - } - - private static int opacityToAlpha(final float opacity) { - return (int) (255f * opacity); - } - - private static int darkenColor(final int argb) { - return adjustColorBrightness(argb, 0.9f); - } - - private static int lightenColor(final int argb) { - return adjustColorBrightness(argb, 1.1f); - } - - public static int darkenOrLightenColor(final int argb) { - final float[] hsv = new float[3]; - Color.colorToHSV(argb, hsv); - final float factor; - if (hsv[2] < 0.2) - factor = 1.2f; - else - factor = 0.8f; - - hsv[2] = Math.min(hsv[2] * factor, 1f); - return Color.HSVToColor(Color.alpha(argb), hsv); - } - - private static int adjustColorBrightness(final int argb, final float factor) { - final float[] hsv = new float[3]; - Color.colorToHSV(argb, hsv); - - hsv[2] = Math.min(hsv[2] * factor, 1f); - - return Color.HSVToColor(Color.alpha(argb), hsv); - } - - private static int halfTransparent(final int argb) { - return Color.argb( - Color.alpha(argb) / 2, - Color.red(argb), - Color.green(argb), - Color.blue(argb) - ); - } - - private static int opaque(final int argb) { - return Color.rgb( - Color.red(argb), - Color.green(argb), - Color.blue(argb) - ); - } - - private Drawable createInnerStrokesDrawable(final int color, final float strokeWidth) { - if (!mStrokeVisible) { - return new ColorDrawable(Color.TRANSPARENT); - } - - final ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape()); - - final int bottomStrokeColor = darkenColor(color); - final int bottomStrokeColorHalfTransparent = halfTransparent(bottomStrokeColor); - final int topStrokeColor = lightenColor(color); - final int topStrokeColorHalfTransparent = halfTransparent(topStrokeColor); - - final Paint paint = shapeDrawable.getPaint(); - paint.setAntiAlias(true); - paint.setStrokeWidth(strokeWidth); - paint.setStyle(Style.STROKE); - shapeDrawable.setShaderFactory(new ShaderFactory() { - @Override - public Shader resize(int width, int height) { - return new LinearGradient(width / 2, 0, width / 2, height, - new int[]{topStrokeColor, topStrokeColorHalfTransparent, color, bottomStrokeColorHalfTransparent, bottomStrokeColor}, - new float[]{0f, 0.2f, 0.5f, 0.8f, 1f}, - TileMode.CLAMP - ); - } - }); - - return shapeDrawable; - } - - @Override - public void setVisibility(final int visibility) { - final TextView label = getLabelView(); - if (label != null) { - label.setVisibility(visibility); - } - - super.setVisibility(visibility); - } - - @Retention(RetentionPolicy.SOURCE) - @IntDef({SIZE_NORMAL, SIZE_MINI}) - public @interface FAB_SIZE { - } - - private static final class TranslucentLayerDrawable extends LayerDrawable { - private final int mAlpha; - - private TranslucentLayerDrawable(final int alpha, final Drawable... layers) { - super(layers); - mAlpha = alpha; - } - - @Override - public void draw(final Canvas canvas) { - final Rect bounds = getBounds(); - canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, mAlpha); - super.draw(canvas); - canvas.restore(); - } - } -} diff --git a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java index c56fbe29..cdf30a26 100644 --- a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java +++ b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java @@ -22,6 +22,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Keep; import android.support.annotation.NonNull; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.content.res.ResourcesCompat; import android.support.v7.widget.AppCompatTextView; import android.util.AttributeSet; import android.view.ContextThemeWrapper; @@ -50,11 +52,6 @@ public class FloatingActionsMenu extends ViewGroup { private static final TimeInterpolator EXPAND_INTERPOLATOR = new OvershootInterpolator(); private static final TimeInterpolator COLLAPSE_INTERPOLATOR = new DecelerateInterpolator(3f); private static final TimeInterpolator ALPHA_EXPAND_INTERPOLATOR = new DecelerateInterpolator(); - private int mAddButtonPlusColor; - private int mAddButtonColorNormal; - private int mAddButtonColorPressed; - private int mAddButtonSize; - private boolean mAddButtonStrokeVisible; private int mExpandDirection; private int mButtonSpacing; private int mLabelsMargin; @@ -62,7 +59,7 @@ public class FloatingActionsMenu extends ViewGroup { private boolean mExpanded; private final AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION); private final AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION); - private AddFloatingActionButton mAddButton; + private FloatingActionButton mAddButton; private RotatingDrawable mRotatingDrawable; private int mMaxButtonWidth; private int mMaxButtonHeight; @@ -88,7 +85,7 @@ public class FloatingActionsMenu extends ViewGroup { } private void init(final Context context, final AttributeSet attributeSet) { - mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing) - getResources().getDimension(R.dimen.fab_shadow_radius) - getResources().getDimension(R.dimen.fab_shadow_offset)); + mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing)); mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin); mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset); @@ -96,14 +93,6 @@ public class FloatingActionsMenu extends ViewGroup { setTouchDelegate(mTouchDelegateGroup); final TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionsMenu, 0, 0); - mAddButtonPlusColor = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonPlusIconColor, - FloatingActionButton.getColorFromTheme(context, android.R.attr.colorBackground, android.R.color.white)); - mAddButtonColorNormal = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorNormal, - FloatingActionButton.getColorFromTheme(context, android.R.attr.colorAccent, android.R.color.holo_blue_bright)); - mAddButtonColorPressed = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorPressed, - FloatingActionButton.darkenOrLightenColor(mAddButtonColorNormal)); //TODO(msf): use getColorForState on the accent color from theme instead to get darker states - mAddButtonSize = attr.getInt(R.styleable.FloatingActionsMenu_fab_addButtonSize, FloatingActionButton.SIZE_NORMAL); - mAddButtonStrokeVisible = attr.getBoolean(R.styleable.FloatingActionsMenu_fab_addButtonStrokeVisible, true); mExpandDirection = attr.getInt(R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP); mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionsMenu_fab_labelStyle, 0); mLabelsPosition = attr.getInt(R.styleable.FloatingActionsMenu_fab_labelsPosition, LABELS_ON_LEFT_SIDE); @@ -125,45 +114,30 @@ public class FloatingActionsMenu extends ViewGroup { } private void createAddButton(final Context context) { - mAddButton = new AddFloatingActionButton(context) { - @Override - void updateBackground() { - mPlusColor = mAddButtonPlusColor; - mColorNormal = mAddButtonColorNormal; - mColorPressed = mAddButtonColorPressed; - mStrokeVisible = mAddButtonStrokeVisible; - super.updateBackground(); - } - - @Override - Drawable getIconDrawable() { - final RotatingDrawable rotatingDrawable = new RotatingDrawable(super.getIconDrawable()); - mRotatingDrawable = rotatingDrawable; + final RotatingDrawable rotatingDrawable = new RotatingDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_action_add_inverse, context.getTheme())); + mRotatingDrawable = rotatingDrawable; - final TimeInterpolator interpolator = new OvershootInterpolator(); + final TimeInterpolator interpolator = new OvershootInterpolator(); - final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", EXPANDED_PLUS_ROTATION, COLLAPSED_PLUS_ROTATION); - final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", COLLAPSED_PLUS_ROTATION, EXPANDED_PLUS_ROTATION); + final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", EXPANDED_PLUS_ROTATION, COLLAPSED_PLUS_ROTATION); + final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", COLLAPSED_PLUS_ROTATION, EXPANDED_PLUS_ROTATION); - collapseAnimator.setInterpolator(interpolator); - expandAnimator.setInterpolator(interpolator); + collapseAnimator.setInterpolator(interpolator); + expandAnimator.setInterpolator(interpolator); - mExpandAnimation.play(expandAnimator); - mCollapseAnimation.play(collapseAnimator); - - return rotatingDrawable; - } - }; + mExpandAnimation.play(expandAnimator); + mCollapseAnimation.play(collapseAnimator); + mAddButton = new FloatingActionButton(context); + mAddButton.setImageDrawable(rotatingDrawable); mAddButton.setId(R.id.fab_expand_menu_button); - mAddButton.setSize(mAddButtonSize); mAddButton.setOnClickListener(v -> toggle()); addView(mAddButton, super.generateDefaultLayoutParams()); mButtonsCount++; } - public void addButton(final FloatingActionButton button) { + public void addButton(final LabeledFloatingActionButton button) { addView(button, mButtonsCount - 1); mButtonsCount++; @@ -172,7 +146,7 @@ public class FloatingActionsMenu extends ViewGroup { } } - public void removeButton(final FloatingActionButton button) { + public void removeButton(final LabeledFloatingActionButton button) { removeView(button.getLabelView()); removeView(button); button.setTag(R.id.fab_label, null); @@ -257,9 +231,9 @@ public class FloatingActionsMenu extends ViewGroup { final int addButtonY = expandUp ? b - t - mAddButton.getMeasuredHeight() : 0; // Ensure mAddButton is centered on the line where the buttons should be - final int buttonsHorizontalCenter = mLabelsPosition == LABELS_ON_LEFT_SIDE + final int buttonsHorizontalCenter = (mLabelsPosition == LABELS_ON_LEFT_SIDE ? r - l - mMaxButtonWidth / 2 - : mMaxButtonWidth / 2; + : mMaxButtonWidth / 2); final int addButtonLeft = buttonsHorizontalCenter - mAddButton.getMeasuredWidth() / 2; mAddButton.layout(addButtonLeft, addButtonY, addButtonLeft + mAddButton.getMeasuredWidth(), addButtonY + mAddButton.getMeasuredHeight()); @@ -314,7 +288,7 @@ public class FloatingActionsMenu extends ViewGroup { childY - mButtonSpacing / 2, Math.max(childX + child.getMeasuredWidth(), labelRight), childY + child.getMeasuredHeight() + mButtonSpacing / 2); - mTouchDelegateGroup.addTouchDelegate(new TouchDelegate(touchArea, child)); + mTouchDelegateGroup.addTouchDelegate(new TouchDelegate(new Rect(touchArea), child)); label.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation); label.setAlpha(mExpanded ? 1f : 0f); @@ -407,17 +381,17 @@ public class FloatingActionsMenu extends ViewGroup { for (int i = 0; i < mButtonsCount; i++) { final FloatingActionButton button = (FloatingActionButton) getChildAt(i); - final String title = button.getTitle(); - if (button == mAddButton || title == null || - button.getTag(R.id.fab_label) != null) continue; + if (button instanceof LabeledFloatingActionButton) { + final String title = ((LabeledFloatingActionButton) button).getTitle(); - final AppCompatTextView label = new AppCompatTextView(context); - label.setTextAppearance(context, mLabelsStyle); - label.setText(button.getTitle()); - addView(label); + final AppCompatTextView label = new AppCompatTextView(context); + label.setTextAppearance(context, mLabelsStyle); + label.setText(title); + addView(label); - button.setTag(R.id.fab_label, label); + button.setTag(R.id.fab_label, label); + } } } diff --git a/app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java b/app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java new file mode 100644 index 00000000..a203282e --- /dev/null +++ b/app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2014 Jerzy Chalupski + * Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.wireguard.android.widget.fab; + +import android.content.Context; +import android.content.res.TypedArray; +import android.support.design.widget.FloatingActionButton; +import android.util.AttributeSet; +import android.widget.TextView; + +import com.wireguard.android.R; + +public class LabeledFloatingActionButton extends FloatingActionButton { + + private final String title; + + public LabeledFloatingActionButton(final Context context) { + this(context, null); + } + + public LabeledFloatingActionButton(final Context context, final AttributeSet attrs) { + this(context, attrs, 0); + } + + public LabeledFloatingActionButton(final Context context, final AttributeSet attrs, final int defStyle) { + super(context, attrs, defStyle); + + final TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.LabeledFloatingActionButton, 0, 0); + title = attr.getString(R.styleable.LabeledFloatingActionButton_fab_title); + attr.recycle(); + } + + TextView getLabelView() { + return (TextView) getTag(R.id.fab_label); + } + + public String getTitle() { + return title; + } + + @Override + public void setVisibility(final int visibility) { + final TextView label = getLabelView(); + if (label != null) { + label.setVisibility(visibility); + } + + super.setVisibility(visibility); + } + +} diff --git a/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java b/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java index f9ee8429..f6152934 100644 --- a/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java +++ b/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java @@ -43,13 +43,14 @@ public class TouchDelegateGroup extends TouchDelegate { @Override public boolean onTouchEvent(@NonNull final MotionEvent event) { - if (!mEnabled) return false; + if (!mEnabled) + return false; TouchDelegate delegate = null; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: - for (final TouchDelegate touchDelegate : mTouchDelegates) { + for (final TouchDelegate touchDelegate : mTouchDelegates) { if (touchDelegate.onTouchEvent(event)) { mCurrentTouchDelegate = touchDelegate; return true; diff --git a/app/src/main/res/drawable-hdpi/fab_bg_mini.png b/app/src/main/res/drawable-hdpi/fab_bg_mini.png Binary files differdeleted file mode 100644 index 4b48351c..00000000 --- a/app/src/main/res/drawable-hdpi/fab_bg_mini.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/fab_bg_normal.png b/app/src/main/res/drawable-hdpi/fab_bg_normal.png Binary files differdeleted file mode 100644 index 4daec66d..00000000 --- a/app/src/main/res/drawable-hdpi/fab_bg_normal.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi/fab_bg_mini.png b/app/src/main/res/drawable-mdpi/fab_bg_mini.png Binary files differdeleted file mode 100644 index 218cf044..00000000 --- a/app/src/main/res/drawable-mdpi/fab_bg_mini.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi/fab_bg_normal.png b/app/src/main/res/drawable-mdpi/fab_bg_normal.png Binary files differdeleted file mode 100644 index c157df36..00000000 --- a/app/src/main/res/drawable-mdpi/fab_bg_normal.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi/fab_bg_mini.png b/app/src/main/res/drawable-xhdpi/fab_bg_mini.png Binary files differdeleted file mode 100644 index d56bfe82..00000000 --- a/app/src/main/res/drawable-xhdpi/fab_bg_mini.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi/fab_bg_normal.png b/app/src/main/res/drawable-xhdpi/fab_bg_normal.png Binary files differdeleted file mode 100644 index 41614b93..00000000 --- a/app/src/main/res/drawable-xhdpi/fab_bg_normal.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi/fab_bg_mini.png b/app/src/main/res/drawable-xxhdpi/fab_bg_mini.png Binary files differdeleted file mode 100644 index 1cdd2b1d..00000000 --- a/app/src/main/res/drawable-xxhdpi/fab_bg_mini.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi/fab_bg_normal.png b/app/src/main/res/drawable-xxhdpi/fab_bg_normal.png Binary files differdeleted file mode 100644 index 14608fff..00000000 --- a/app/src/main/res/drawable-xxhdpi/fab_bg_normal.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxxhdpi/fab_bg_mini.png b/app/src/main/res/drawable-xxxhdpi/fab_bg_mini.png Binary files differdeleted file mode 100644 index 6fea6746..00000000 --- a/app/src/main/res/drawable-xxxhdpi/fab_bg_mini.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxxhdpi/fab_bg_normal.png b/app/src/main/res/drawable-xxxhdpi/fab_bg_normal.png Binary files differdeleted file mode 100644 index 0e78ff60..00000000 --- a/app/src/main/res/drawable-xxxhdpi/fab_bg_normal.png +++ /dev/null diff --git a/app/src/main/res/drawable/ic_action_add_inverse.xml b/app/src/main/res/drawable/ic_action_add_inverse.xml new file mode 100644 index 00000000..571e70e7 --- /dev/null +++ b/app/src/main/res/drawable/ic_action_add_inverse.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="?android:attr/colorBackground" + android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" /> +</vector> diff --git a/app/src/main/res/layout/tunnel_list_fragment.xml b/app/src/main/res/layout/tunnel_list_fragment.xml index cad2e094..5aff4739 100644 --- a/app/src/main/res/layout/tunnel_list_fragment.xml +++ b/app/src/main/res/layout/tunnel_list_fragment.xml @@ -23,7 +23,8 @@ android:id="@+id/main_container" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?android:attr/colorBackground"> + android:background="?android:attr/colorBackground" + android:clipChildren="false"> <android.support.v7.widget.RecyclerView android:id="@+id/tunnel_list" @@ -39,27 +40,27 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" - android:layout_margin="8dp" + android:layout_margin="16dp" app:fab_labelStyle="@style/fab_label" - app:fab_labelsPosition="left" - app:layout_dodgeInsetEdges="bottom"> + android:clipChildren="false" + app:fab_labelsPosition="left" > - <com.wireguard.android.widget.fab.FloatingActionButton + <com.wireguard.android.widget.fab.LabeledFloatingActionButton android:id="@+id/create_empty" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{fragment::onRequestCreateConfig}" - app:fab_icon="@drawable/ic_action_edit_inverse" - app:fab_size="mini" + app:fabSize="mini" + app:srcCompat="@drawable/ic_action_edit_inverse" app:fab_title="@string/create_empty" /> - <com.wireguard.android.widget.fab.FloatingActionButton + <com.wireguard.android.widget.fab.LabeledFloatingActionButton android:id="@+id/create_from_file" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{fragment::onRequestImportConfig}" - app:fab_icon="@drawable/ic_action_open_inverse" - app:fab_size="mini" + app:srcCompat="@drawable/ic_action_open_inverse" + app:fabSize="mini" app:fab_title="@string/create_from_file" /> </com.wireguard.android.widget.fab.FloatingActionsMenu> </android.support.design.widget.CoordinatorLayout> diff --git a/app/src/main/res/values/fab.xml b/app/src/main/res/values/fab.xml index e2931595..0f373333 100644 --- a/app/src/main/res/values/fab.xml +++ b/app/src/main/res/values/fab.xml @@ -3,46 +3,18 @@ <item name="fab_expand_menu_button" type="id"/> <item name="fab_label" type="id"/> - <dimen name="fab_size_normal">56dp</dimen> - <dimen name="fab_size_mini">40dp</dimen> - - <dimen name="fab_icon_size">24dp</dimen> - - <dimen name="fab_plus_icon_size">14dp</dimen> - <dimen name="fab_plus_icon_stroke">2dp</dimen> - <dimen name="fab_shadow_offset">3dp</dimen> <dimen name="fab_shadow_radius">9dp</dimen> <dimen name="fab_stroke_width">1dp</dimen> - <dimen name="fab_actions_spacing">16dp</dimen> + <dimen name="fab_actions_spacing">24dp</dimen> <dimen name="fab_labels_margin">8dp</dimen> - <declare-styleable name="FloatingActionButton"> - <attr name="fab_colorPressed" format="color"/> - <attr name="fab_colorDisabled" format="color"/> - <attr name="fab_colorNormal" format="color"/> - <attr name="fab_icon" format="reference"/> - <attr name="fab_size" format="enum"> - <enum name="normal" value="0"/> - <enum name="mini" value="1"/> - </attr> + <declare-styleable name="LabeledFloatingActionButton"> <attr name="fab_title" format="string"/> - <attr name="fab_stroke_visible" format="boolean"/> - </declare-styleable> - <declare-styleable name="AddFloatingActionButton"> - <attr name="fab_plusIconColor" format="color"/> </declare-styleable> <declare-styleable name="FloatingActionsMenu"> - <attr name="fab_addButtonColorPressed" format="color"/> - <attr name="fab_addButtonColorNormal" format="color"/> - <attr name="fab_addButtonSize" format="enum"> - <enum name="normal" value="0"/> - <enum name="mini" value="1"/> - </attr> - <attr name="fab_addButtonPlusIconColor" format="color"/> - <attr name="fab_addButtonStrokeVisible" format="boolean"/> <attr name="fab_labelStyle" format="reference"/> <attr name="fab_labelsPosition" format="enum"> <enum name="left" value="0"/> |