From 580c97e368cd0d9fa47691f70cc31e9b711581ec Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 15 Nov 2021 14:09:17 +0100 Subject: implement a new fancy on-off-button --- .../bitmaskclient/base/fragments/EipFragment.java | 25 ++- .../leap/bitmaskclient/base/views/MainButton.java | 189 +++++++++++++++++++++ 2 files changed, 199 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java (limited to 'app/src/main/java') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index d8be1cc5..813daac5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -61,7 +61,7 @@ import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.views.LocationButton; -import se.leap.bitmaskclient.base.views.VpnStateImage; +import se.leap.bitmaskclient.base.views.MainButton; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; @@ -105,8 +105,8 @@ public class EipFragment extends Fragment implements Observer { @BindView(R.id.background) AppCompatImageView background; - @BindView(R.id.vpn_state_image) - VpnStateImage vpnStateImage; + @BindView(R.id.main_button) + MainButton mainButton; @BindView(R.id.gateway_location_button) LocationButton locationButton; @@ -272,7 +272,7 @@ public class EipFragment extends Fragment implements Observer { handleIcon(); } - @OnClick(R.id.vpn_state_image) + @OnClick(R.id.main_button) void onVpnStateImageClick() { handleIcon(); } @@ -323,7 +323,7 @@ public class EipFragment extends Fragment implements Observer { private void setMainButtonEnabled(boolean enabled) { locationButton.setEnabled(enabled); - vpnStateImage.setEnabled(enabled); + mainButton.setEnabled(enabled); } public void startEipFromScratch() { @@ -431,8 +431,7 @@ public class EipFragment extends Fragment implements Observer { locationButton.setLocationLoad(UNKNOWN); } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); - vpnStateImage.stopProgress(false); + mainButton.updateState(true, false, false); locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName())); locationButton.setText(VpnStatus.getLastConnectedVpnName()); locationButton.setVisibility(VISIBLE); @@ -444,8 +443,7 @@ public class EipFragment extends Fragment implements Observer { } else if(isOpenVpnRunningWithoutNetwork()){ Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); - vpnStateImage.stopProgress(false); + mainButton.updateState(true, false, true); locationButton.setVisibility(VISIBLE); locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); colorBackgroundALittle(); @@ -466,8 +464,7 @@ public class EipFragment extends Fragment implements Observer { subDescription.setText(R.string.connection_not_connected); } else if (eipStatus.isBlocking()) { setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); - vpnStateImage.stopProgress(false); + mainButton.updateState(true, false, true); colorBackgroundALittle(); locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setVisibility(VISIBLE); @@ -477,8 +474,7 @@ public class EipFragment extends Fragment implements Observer { } else { locationButton.setText(activity.getString(R.string.vpn_button_turn_on)); setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.ic_btn_on_disabled); - vpnStateImage.stopProgress(false); + mainButton.updateState(false, false, false); greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); locationButton.setVisibility(INVISIBLE); @@ -517,8 +513,7 @@ public class EipFragment extends Fragment implements Observer { } private void showConnectionTransitionLayout(boolean isConnecting) { - vpnStateImage.setStateIcon(R.drawable.ic_btn_on_connecting); - vpnStateImage.showProgress(); + mainButton.updateState(true, true, false); if (isConnecting) { colorBackgroundALittle(); } else { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java new file mode 100644 index 00000000..586eb321 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java @@ -0,0 +1,189 @@ +package se.leap.bitmaskclient.base.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.RelativeLayout; + +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; + +import java.lang.ref.WeakReference; + +import se.leap.bitmaskclient.R; + +public class MainButton extends RelativeLayout { + + private static final String TAG = MainButton.class.getSimpleName(); + + interface MainButtonListener { + void onButtonClicked(); + } + + AppCompatImageView glow; + AppCompatImageView shadowDark; + AppCompatImageView shadowLight; + AnimationDrawable glowAnimation; + WeakReference callback; + + private boolean isOn = false; + private boolean isProcessing = false; + private boolean isError = true; + + + + public MainButton(Context context) { + super(context); + initLayout(context); + } + + public MainButton(Context context, AttributeSet attrs) { + super(context, attrs); + initLayout(context); + } + + public MainButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initLayout(context); + } + + + @TargetApi(21) + public MainButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initLayout(context); + } + + public void setMainButtonListener(MainButtonListener callback) { + this.callback = new WeakReference<>(callback); + } + + private void initLayout(Context context) { + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View rootview = inflater.inflate(R.layout.v_main_btn, this, true); + + glow = rootview.findViewById(R.id.vpn_btn_glow); + glowAnimation = (AnimationDrawable) glow.getBackground(); + shadowDark = rootview.findViewById(R.id.vpn_btn_shadow_dark); + shadowLight = rootview.findViewById(R.id.vpn_btn_shadow_light); + + rootview.setOnGenericMotionListener(new OnGenericMotionListener() { + @Override + public boolean onGenericMotion(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_BUTTON_PRESS: + Log.d(TAG, "onbuttonPrees"); + break; + case MotionEvent.ACTION_BUTTON_RELEASE: + Log.d(TAG, "onButtonRelease"); + break; + } + return false; + } + }); + rootview.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + Log.d(TAG, "motion down"); + Drawable drawableDown = context.getResources().getDrawable(R.drawable.on_off_btn_start_2_pressed); + shadowDark.setImageDrawable(drawableDown); + break; + case MotionEvent.ACTION_UP: + Log.d(TAG, "motion up"); + Drawable drawableUp = isOn ? + context.getResources().getDrawable(R.drawable.on_off_btn_start_2_disabled) : + context.getResources().getDrawable(R.drawable.on_off_btn_start_2_enabled); + shadowDark.setImageDrawable(drawableUp); + break; + case MotionEvent.ACTION_CANCEL: + Log.d(TAG, "motion cancelled"); + Drawable drawableRestoreState = isOn ? + context.getResources().getDrawable(R.drawable.on_off_btn_start_2_enabled) : + context.getResources().getDrawable(R.drawable.on_off_btn_start_2_disabled); + shadowDark.setImageDrawable(drawableRestoreState); + break; + } + return false; + } + }); + + } + + + private void stopGlowAnimation() { + AlphaAnimation fadeOutAnimation = new AlphaAnimation(1.0f, 0.0f); + fadeOutAnimation.setDuration(300); + fadeOutAnimation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) {} + + @Override + public void onAnimationEnd(Animation animation) { + glow.setVisibility(GONE); + glowAnimation.stop(); + } + + @Override + public void onAnimationRepeat(Animation animation) {} + }); + glow.startAnimation(fadeOutAnimation); + } + + private void startGlowAnimation() { + glow.setAlpha(1.0f); + glow.setVisibility(VISIBLE); + glowAnimation.start(); + } + + public void updateState(boolean isOn, boolean isProcessing, boolean isError) { + if (this.isOn != isOn) { + this.isOn = isOn; + Drawable drawableRestoreState = isOn ? + getContext().getResources().getDrawable(R.drawable.on_off_btn_start_2_enabled) : + getContext().getResources().getDrawable(R.drawable.on_off_btn_start_2_disabled); + shadowDark.setImageDrawable(drawableRestoreState); + shadowLight.setVisibility(isOn ? VISIBLE : GONE); + } + + if (this.isProcessing != isProcessing) { + if (!isProcessing) { + stopGlowAnimation(); + } else { + startGlowAnimation(); + } + this.isProcessing = isProcessing; + } + + if (this.isError != isError) { + @DrawableRes int drawableResource = isOn ? R.drawable.on_off_btn_start_2_enabled : R.drawable.on_off_btn_start_2_disabled; + if (!isError) { + setImageWithTint(shadowLight, drawableResource, R.color.colorSecondary); + } else { + setImageWithTint(shadowLight, drawableResource, R.color.colorWarning); + } + this.isError = isError; + } + } + + private void setImageWithTint(AppCompatImageView view, @DrawableRes int resourceId, @ColorRes int color) { + view.setImageDrawable(ContextCompat.getDrawable(getContext(), resourceId)); + view.setColorFilter(ContextCompat.getColor(getContext(), color), PorterDuff.Mode.SRC_ATOP); + } + + + +} -- cgit v1.2.3