diff options
20 files changed, 220 insertions, 30 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..18e97411 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 @@ -27,6 +27,7 @@ import android.graphics.ColorMatrixColorFilter; import android.os.Bundle; import android.os.IBinder; import android.os.Vibrator; +import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -37,6 +38,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.AppCompatButton; import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; import androidx.fragment.app.DialogFragment; @@ -61,7 +63,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 +107,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; @@ -267,16 +269,11 @@ public class EipFragment extends Fragment implements Observer { preferences.edit().putBoolean(EIP_RESTART_ON_BOOT, restartOnBoot).apply(); } - @OnClick(R.id.gateway_location_button) + @OnClick(R.id.main_button) void onButtonClick() { handleIcon(); } - @OnClick(R.id.vpn_state_image) - void onVpnStateImageClick() { - handleIcon(); - } - void handleIcon() { if (isOpenVpnRunningWithoutNetwork() || eipStatus.isConnected() || eipStatus.isConnecting()) handleSwitchOff(); @@ -323,7 +320,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 +428,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 +440,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 +461,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 +471,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 +510,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..c5ac4544 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java @@ -0,0 +1,124 @@ +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.util.AttributeSet; +import android.view.LayoutInflater; +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 se.leap.bitmaskclient.R; + +public class MainButton extends RelativeLayout { + + private static final String TAG = MainButton.class.getSimpleName(); + + AppCompatImageView glow; + AppCompatImageView shadowLight; + AnimationDrawable glowAnimation; + + 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); + } + + 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(); + shadowLight = rootview.findViewById(R.id.vpn_btn_shadow_light); + } + + + 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; + 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.colorMainBtnHighlight); + } else { + setImageWithTint(shadowLight, drawableResource, R.color.colorMainBtnError); + } + 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/main_btn_shadow.xml b/app/src/main/res/drawable/main_btn_shadow.xml new file mode 100644 index 00000000..94cf379f --- /dev/null +++ b/app/src/main/res/drawable/main_btn_shadow.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/on_off_btn_start_2_pressed" android:state_pressed="true"/> + <item android:drawable="@drawable/on_off_btn_start_2_enabled"/> +</selector>
\ 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..c4c7a600 --- /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/colorMainBtnHighlight" + /> + + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/vpn_btn_shadow_dark" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:srcCompat="@drawable/main_btn_shadow" + 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..bba7f1b5 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,6 +7,8 @@ <color name="colorError">#ef9a9a</color> <color name="colorSuccess">#a5d6a7</color> <color name="colorDisabled">#AAAAAA</color> + <color name="colorMainBtnHighlight">#03DAC6</color> + <color name="colorMainBtnError">#eF2222</color> <color name="black800">#424242</color> <color name="black800_secondary">#3b3b3b</color> |