diff options
author | cyBerta <cyberta@riseup.net> | 2021-11-15 14:09:17 +0100 |
---|---|---|
committer | cyBerta <cyberta@riseup.net> | 2021-11-15 14:09:17 +0100 |
commit | 580c97e368cd0d9fa47691f70cc31e9b711581ec (patch) | |
tree | c164b25493b9f4c7cb0c505a124d3cc30f6386ed /app | |
parent | aeadefa699db964b1a4ca3ee2bbd45a80ae847a7 (diff) |
implement a new fancy on-off-button
Diffstat (limited to 'app')
19 files changed, 277 insertions, 25 deletions
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<MainButtonListener> 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); + } + + + +} diff --git a/app/src/main/res/drawable/main_btn_glow.xml b/app/src/main/res/drawable/main_btn_glow.xml new file mode 100644 index 00000000..e740e96f --- /dev/null +++ b/app/src/main/res/drawable/main_btn_glow.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> + <item android:drawable="@drawable/on_off_btn_start_animation1" android:duration="140" /> + <item android:drawable="@drawable/on_off_btn_start_animation2" android:duration="120" /> + <item android:drawable="@drawable/on_off_btn_start_animation3" android:duration="100" /> + <item android:drawable="@drawable/on_off_btn_start_animation4" android:duration="75" /> + <item android:drawable="@drawable/on_off_btn_start_animation3" android:duration="90" /> + <item android:drawable="@drawable/on_off_btn_start_animation2" android:duration="90" /> + <item android:drawable="@drawable/on_off_btn_start_animation3" android:duration="100" /> + <item android:drawable="@drawable/on_off_btn_start_animation4" android:duration="150" /> + <item android:drawable="@drawable/on_off_btn_start_animation5" android:duration="200" /> + <item android:drawable="@drawable/on_off_btn_start_animation4" android:duration="150" /> + <item android:drawable="@drawable/on_off_btn_start_animation3" android:duration="100" /> + <item android:drawable="@drawable/on_off_btn_start_animation2" android:duration="120" /> +</animation-list>
\ No newline at end of file diff --git a/app/src/main/res/drawable/on_off_btn_fill.png b/app/src/main/res/drawable/on_off_btn_fill.png Binary files differnew file mode 100644 index 00000000..8394ccfb --- /dev/null +++ b/app/src/main/res/drawable/on_off_btn_fill.png diff --git a/app/src/main/res/drawable/on_off_btn_start_2_disabled.png b/app/src/main/res/drawable/on_off_btn_start_2_disabled.png Binary files differnew file mode 100644 index 00000000..4675e48d --- /dev/null +++ b/app/src/main/res/drawable/on_off_btn_start_2_disabled.png diff --git a/app/src/main/res/drawable/on_off_btn_start_2_enabled.png b/app/src/main/res/drawable/on_off_btn_start_2_enabled.png Binary files differnew file mode 100644 index 00000000..383e1076 --- /dev/null +++ b/app/src/main/res/drawable/on_off_btn_start_2_enabled.png diff --git a/app/src/main/res/drawable/on_off_btn_start_2_no_shadow.png b/app/src/main/res/drawable/on_off_btn_start_2_no_shadow.png Binary files differnew file mode 100644 index 00000000..941bdef1 --- /dev/null +++ b/app/src/main/res/drawable/on_off_btn_start_2_no_shadow.png diff --git a/app/src/main/res/drawable/on_off_btn_start_2_pressed.png b/app/src/main/res/drawable/on_off_btn_start_2_pressed.png Binary files differnew file mode 100644 index 00000000..7ff60cdb --- /dev/null +++ b/app/src/main/res/drawable/on_off_btn_start_2_pressed.png diff --git a/app/src/main/res/drawable/on_off_btn_start_animation1.png b/app/src/main/res/drawable/on_off_btn_start_animation1.png Binary files differnew file mode 100644 index 00000000..f9d18488 --- /dev/null +++ b/app/src/main/res/drawable/on_off_btn_start_animation1.png diff --git a/app/src/main/res/drawable/on_off_btn_start_animation2.png b/app/src/main/res/drawable/on_off_btn_start_animation2.png Binary files differnew file mode 100644 index 00000000..33b600c9 --- /dev/null +++ b/app/src/main/res/drawable/on_off_btn_start_animation2.png diff --git a/app/src/main/res/drawable/on_off_btn_start_animation3.png b/app/src/main/res/drawable/on_off_btn_start_animation3.png Binary files differnew file mode 100644 index 00000000..2172107a --- /dev/null +++ b/app/src/main/res/drawable/on_off_btn_start_animation3.png diff --git a/app/src/main/res/drawable/on_off_btn_start_animation4.png b/app/src/main/res/drawable/on_off_btn_start_animation4.png Binary files differnew file mode 100644 index 00000000..8b744462 --- /dev/null +++ b/app/src/main/res/drawable/on_off_btn_start_animation4.png diff --git a/app/src/main/res/drawable/on_off_btn_start_animation5.png b/app/src/main/res/drawable/on_off_btn_start_animation5.png Binary files differnew file mode 100644 index 00000000..11bb16cd --- /dev/null +++ b/app/src/main/res/drawable/on_off_btn_start_animation5.png diff --git a/app/src/main/res/layout-port/f_eip.xml b/app/src/main/res/layout-port/f_eip.xml index 03401d16..a261c8ea 100644 --- a/app/src/main/res/layout-port/f_eip.xml +++ b/app/src/main/res/layout-port/f_eip.xml @@ -42,8 +42,8 @@ android:scaleType="fitXY" app:srcCompat="@drawable/background_eip" /> - <se.leap.bitmaskclient.base.views.VpnStateImage - android:id="@+id/vpn_state_image" + <se.leap.bitmaskclient.base.views.MainButton + android:id="@+id/main_button" android:layout_width="0dp" android:layout_height="0dp" android:layout_margin="@dimen/stdpadding" @@ -58,7 +58,7 @@ android:id="@+id/main_description" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:layout_constraintTop_toBottomOf="@id/vpn_state_image" + app:layout_constraintTop_toBottomOf="@id/main_button" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toTopOf="@+id/sub_description" diff --git a/app/src/main/res/layout-xlarge-port/f_eip.xml b/app/src/main/res/layout-xlarge-port/f_eip.xml index 6a115a8b..839753e6 100644 --- a/app/src/main/res/layout-xlarge-port/f_eip.xml +++ b/app/src/main/res/layout-xlarge-port/f_eip.xml @@ -53,8 +53,8 @@ app:srcCompat="@drawable/background_eip" /> - <se.leap.bitmaskclient.base.views.VpnStateImage - android:id="@+id/vpn_state_image" + <se.leap.bitmaskclient.base.views.MainButton + android:id="@+id/main_button" android:layout_width="0dp" android:layout_height="0dp" android:layout_margin="@dimen/stdpadding" @@ -69,7 +69,7 @@ android:id="@+id/main_description" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:layout_constraintTop_toBottomOf="@id/vpn_state_image" + app:layout_constraintTop_toBottomOf="@id/main_button" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toTopOf="@+id/sub_description" diff --git a/app/src/main/res/layout-xlarge/f_eip.xml b/app/src/main/res/layout-xlarge/f_eip.xml index 1ea7ba4b..34d74805 100644 --- a/app/src/main/res/layout-xlarge/f_eip.xml +++ b/app/src/main/res/layout-xlarge/f_eip.xml @@ -58,8 +58,8 @@ app:srcCompat="@drawable/background_eip" /> - <se.leap.bitmaskclient.base.views.VpnStateImage - android:id="@+id/vpn_state_image" + <se.leap.bitmaskclient.base.views.MainButton + android:id="@+id/main_button" android:layout_width="0dp" android:layout_height="0dp" android:layout_margin="@dimen/stdpadding" diff --git a/app/src/main/res/layout/f_eip.xml b/app/src/main/res/layout/f_eip.xml index e3e8fe0a..b5af785d 100644 --- a/app/src/main/res/layout/f_eip.xml +++ b/app/src/main/res/layout/f_eip.xml @@ -71,8 +71,8 @@ app:srcCompat="@drawable/background_eip" /> - <se.leap.bitmaskclient.base.views.VpnStateImage - android:id="@+id/vpn_state_image" + <se.leap.bitmaskclient.base.views.MainButton + android:id="@+id/main_button" android:layout_width="0dp" android:layout_height="0dp" android:layout_margin="@dimen/stdpadding" diff --git a/app/src/main/res/layout/v_main_btn.xml b/app/src/main/res/layout/v_main_btn.xml new file mode 100644 index 00000000..cf2a3e33 --- /dev/null +++ b/app/src/main/res/layout/v_main_btn.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/vpn_btn_container" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/vpn_btn_glow" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/main_btn_glow" + tools:visibility="visible" + android:visibility="gone" + android:backgroundTint="@color/colorSecondary" + /> + + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/vpn_btn_shadow_dark" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:srcCompat="@drawable/on_off_btn_start_2_enabled" + android:visibility="visible" + /> + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/vpn_btn_shadow_light" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:visibility="gone" + android:visibility="gone" + /> + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/vpn_btn_fill" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:srcCompat="@drawable/on_off_btn_start_2_no_shadow" + android:visibility="visible" + android:tint="@color/colorPrimaryDark" + /> + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/vpn_btn_fill_overlay" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:srcCompat="@drawable/on_off_btn_fill" + tools:visibility="visible" + /> +</RelativeLayout>
\ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 86ac1128..4b77decb 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,6 +7,7 @@ <color name="colorError">#ef9a9a</color> <color name="colorSuccess">#a5d6a7</color> <color name="colorDisabled">#AAAAAA</color> + <color name="colorSecondary">#03DAC6</color> <color name="black800">#424242</color> <color name="black800_secondary">#3b3b3b</color> |