summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorcyBerta <cyberta@riseup.net>2021-11-21 19:36:46 +0100
committercyBerta <cyberta@riseup.net>2021-11-21 19:39:52 +0100
commita6cd31ae8624f830454adc627ac3a6be323a5333 (patch)
treeeadd921ce162958c35b7fc0be1b5fc21b359c2cb /app
parent4ebcedd733efce56c91ef21c9b5b167a7820db12 (diff)
implement new gateway selection UI, using same UX principles as for desktop
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java120
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/models/Location.java25
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java90
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java50
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java2
-rw-r--r--app/src/main/res/drawable/check_bold.xml8
-rw-r--r--app/src/main/res/drawable/cust_checkbox.xml27
-rw-r--r--app/src/main/res/layout/f_gateway_selection.xml80
-rw-r--r--app/src/main/res/layout/s_layout.xml12
-rw-r--r--app/src/main/res/layout/v_select_text_list_item.xml86
-rw-r--r--app/src/main/res/layout/v_simple_checkbox.xml32
-rw-r--r--app/src/main/res/values/strings.xml7
12 files changed, 379 insertions, 160 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java
index c98abd74..12aedb12 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java
@@ -17,6 +17,7 @@
package se.leap.bitmaskclient.base.fragments;
import android.app.Activity;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
@@ -26,10 +27,6 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.widget.AppCompatButton;
-import androidx.appcompat.widget.AppCompatImageView;
-import androidx.appcompat.widget.AppCompatTextView;
-import androidx.core.view.LayoutInflaterCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -45,14 +42,12 @@ import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.base.MainActivity;
import se.leap.bitmaskclient.base.models.Location;
import se.leap.bitmaskclient.base.utils.PreferenceHelper;
-import se.leap.bitmaskclient.base.views.LocationIndicator;
+import se.leap.bitmaskclient.base.views.SelectLocationEntry;
import se.leap.bitmaskclient.eip.EIP;
import se.leap.bitmaskclient.eip.EipCommand;
import se.leap.bitmaskclient.eip.EipStatus;
import se.leap.bitmaskclient.eip.GatewaysManager;
-import static android.view.View.GONE;
-import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
@@ -61,7 +56,7 @@ import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT;
import static se.leap.bitmaskclient.base.models.Constants.LOCATION;
interface LocationListSelectionListener {
- void onLocationSelected(Location location);
+ void onLocationManuallySelected(Location location);
}
public class GatewaySelectionFragment extends Fragment implements Observer, LocationListSelectionListener {
@@ -71,9 +66,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca
private RecyclerView recyclerView;
private LocationListAdapter locationListAdapter;
- private AppCompatTextView currentLocationDescription;
- private AppCompatTextView currentLocation;
- private AppCompatButton autoSelectionButton;
+ private SelectLocationEntry recommendedLocation;
private GatewaysManager gatewaysManager;
private EipStatus eipStatus;
@@ -100,8 +93,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initRecyclerView();
- initAutoSelectionButton();
- initCurrentLocationInfoPanel();
+ initRecommendedLocationEntry();
}
@Override
@@ -120,40 +112,40 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca
recyclerView.setVisibility(VISIBLE);
}
- private void initAutoSelectionButton() {
- autoSelectionButton = getActivity().findViewById(R.id.automatic_gateway_selection_btn);
- autoSelectionButton.setOnClickListener(v -> {
+ private void initRecommendedLocationEntry() {
+ recommendedLocation = getActivity().findViewById(R.id.recommended_location);
+ recommendedLocation.setTitle(getString(R.string.gateway_selection_automatic_location));
+ recommendedLocation.showDivider(true);
+ recommendedLocation.setOnClickListener(v -> {
+ recommendedLocation.setSelected(true);
+ locationListAdapter.unselectAll();
startEipService(null);
});
+ updateRecommendedLocation();
}
- private void initCurrentLocationInfoPanel() {
- currentLocationDescription = getActivity().findViewById(R.id.current_location_description);
- currentLocation = getActivity().findViewById(R.id.current_location);
- setLocationDescription(EipStatus.getInstance(), PreferenceHelper.getPreferredCity(getContext()));
- }
-
- private void setLocationDescription(EipStatus eipStatus, String preferredCity) {
- if (eipStatus.isConnected()) {
- currentLocationDescription.setText(preferredCity == null ?
- R.string.gateway_selection_automatic_location :
- R.string.gateway_selection_manual_location);
- currentLocation.setText(VpnStatus.getLastConnectedVpnName());
- currentLocation.setVisibility(VISIBLE);
- } else if (preferredCity == null) {
- currentLocationDescription.setText(R.string.gateway_selection_automatic_not_connected);
- currentLocation.setVisibility(INVISIBLE);
- } else {
- currentLocationDescription.setText(R.string.gateway_selection_manual_not_connected);
- currentLocation.setText(preferredCity);
- currentLocation.setVisibility(VISIBLE);
+ private void updateRecommendedLocation() {
+ Location location = new Location();
+ boolean isManualSelection = PreferenceHelper.getPreferredCity(getContext()) != null;
+ if (!isManualSelection && eipStatus.isConnected()) {
+ try {
+ location = gatewaysManager.getLocation(VpnStatus.getCurrentlyConnectingVpnName()).clone();
+ } catch (NullPointerException | CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
}
+ location.selected = !isManualSelection;
+ recommendedLocation.setLocation(location);
}
protected void startEipService(String preferredCity) {
new Thread(() -> {
- PreferenceHelper.setPreferredCity(getContext(), preferredCity);
- EipCommand.startVPN(getContext(), false);
+ Context context = getContext();
+ if (context == null) {
+ return;
+ }
+ PreferenceHelper.setPreferredCity(context, preferredCity);
+ EipCommand.startVPN(context, false);
Intent intent = new Intent(getContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setAction(ACTION_SHOW_VPN_FRAGMENT);
@@ -162,7 +154,8 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca
}
@Override
- public void onLocationSelected(Location location) {
+ public void onLocationManuallySelected(Location location) {
+ recommendedLocation.setSelected(false);
String name = location.name;
Connection.TransportType selectedTransport = PreferenceHelper.getUseBridges(getContext()) ? OBFS4 : OPENVPN;
if (location.supportedTransports.contains(selectedTransport)) {
@@ -185,32 +178,25 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca
@Override
public void update(Observable o, Object arg) {
if (o instanceof EipStatus) {
+ eipStatus = (EipStatus) o;
Activity activity = getActivity();
if (activity != null) {
- activity.runOnUiThread(() -> setLocationDescription((EipStatus) o, PreferenceHelper.getPreferredCity(getContext())));
+ activity.runOnUiThread(this::updateRecommendedLocation);
}
}
}
static class LocationListAdapter extends RecyclerView.Adapter<LocationListAdapter.ViewHolder> {
private static final String TAG = LocationListAdapter.class.getSimpleName();
- private List<Location> values;
+ private final List<Location> values;
private final WeakReference<LocationListSelectionListener> callback;
static class ViewHolder extends RecyclerView.ViewHolder {
- public AppCompatTextView locationLabel;
- public LocationIndicator locationIndicator;
- public AppCompatImageView bridgeView;
- public AppCompatImageView selectedView;
- public View layout;
+ public SelectLocationEntry entry;
- public ViewHolder(View v) {
+ public ViewHolder(SelectLocationEntry v) {
super(v);
- layout = v;
- locationLabel = v.findViewById(R.id.location);
- locationIndicator = v.findViewById(R.id.quality);
- bridgeView = v.findViewById(R.id.bridge_image);
- selectedView = v.findViewById(R.id.selected);
+ entry = v;
}
}
@@ -224,8 +210,10 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca
notifyItemRemoved(position);
}
- public void updateData(List<Location> data) {
- values = data;
+ public void unselectAll() {
+ for (Location l : values) {
+ l.selected = false;
+ }
notifyDataSetChanged();
}
@@ -238,35 +226,27 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca
@Override
public LocationListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
- LayoutInflater inflater = LayoutInflater.from(
- parent.getContext());
- View v = inflater.inflate(R.layout.v_select_text_list_item, parent, false);
- return new ViewHolder(v);
+ SelectLocationEntry entry = new SelectLocationEntry(parent.getContext());
+ return new ViewHolder(entry);
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
final Location location = values.get(position);
- holder.locationLabel.setText(location.name);
- holder.layout.setOnClickListener(v -> {
- Log.d(TAG, "view at position clicked: " + position);
+ holder.entry.setLocation(location);
+ holder.entry.setOnClickListener(v -> {
+ Log.d(TAG, "onClick view at position clicked: " + position);
LocationListSelectionListener listener = callback.get();
if (listener != null) {
- for (Location l : values) {
- l.selected = false;
- }
- location.selected = !location.selected;
+ unselectAll();
+ location.selected = true;
+ listener.onLocationManuallySelected(location);
notifyDataSetChanged();
- listener.onLocationSelected(location);
}
});
- holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad));
- holder.bridgeView.setVisibility(location.supportedTransports.contains(OBFS4) ? VISIBLE : GONE);
- holder.selectedView.setVisibility(location.selected ? VISIBLE : INVISIBLE);
}
-
@Override
public int getItemCount() {
return values.size();
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java
index 3eb82f22..599a358a 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java
@@ -18,16 +18,20 @@
package se.leap.bitmaskclient.base.models;
import androidx.annotation.NonNull;
+
import java.util.HashSet;
+
import de.blinkt.openvpn.core.connection.Connection;
-public class Location {
- @NonNull public String name;
- @NonNull public HashSet<Connection.TransportType> supportedTransports;
+public class Location implements Cloneable {
+ @NonNull public String name = "";
+ @NonNull public HashSet<Connection.TransportType> supportedTransports = new HashSet<>();
public double averageLoad;
public int numberOfGateways;
public boolean selected;
+ public Location() {}
+
public Location(@NonNull String name, double averageLoad, int numberOfGateways, @NonNull HashSet<Connection.TransportType> supportedTransports, boolean selected) {
this.name = name;
this.averageLoad = averageLoad;
@@ -36,6 +40,10 @@ public class Location {
this.selected = selected;
}
+ public boolean hasLocationInfo() {
+ return numberOfGateways != 0 && supportedTransports.size() != 0 && !name.isEmpty();
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -60,4 +68,15 @@ public class Location {
result = 31 * result + numberOfGateways;
return result;
}
+
+ @Override
+ public Location clone() throws CloneNotSupportedException {
+ Location copy = (Location) super.clone();
+ copy.name = this.name;
+ copy.supportedTransports = (HashSet<Connection.TransportType>) this.supportedTransports.clone();
+ copy.numberOfGateways = this.numberOfGateways;
+ copy.averageLoad = this.averageLoad;
+ return copy;
+ }
+
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java
new file mode 100644
index 00000000..f85df4ca
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java
@@ -0,0 +1,90 @@
+package se.leap.bitmaskclient.base.views;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.appcompat.widget.AppCompatImageView;
+import androidx.appcompat.widget.AppCompatTextView;
+
+import de.blinkt.openvpn.core.connection.Connection;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.base.models.Location;
+import se.leap.bitmaskclient.eip.GatewaysManager.Load;
+
+public class SelectLocationEntry extends RelativeLayout {
+
+ private static final String TAG = SelectLocationEntry.class.getSimpleName();
+ AppCompatTextView title;
+ AppCompatTextView locationText;
+ SimpleCheckBox selectedView;
+ AppCompatImageView bridgesView;
+ LocationIndicator locationIndicator;
+ View divider;
+
+ // private OnClickListener onClickListener;
+
+ public SelectLocationEntry(Context context) {
+ super(context);
+ initLayout(context);
+ }
+
+ public SelectLocationEntry(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initLayout(context);
+ }
+
+ public SelectLocationEntry(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initLayout(context);
+ }
+
+ @TargetApi(21)
+ public SelectLocationEntry(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_select_text_list_item, this, true);
+ title = rootview.findViewById(R.id.title);
+ locationIndicator = rootview.findViewById(R.id.quality);
+ locationText = rootview.findViewById(R.id.location);
+ bridgesView = rootview.findViewById(R.id.bridge_image);
+ selectedView = rootview.findViewById(R.id.selected);
+ divider = rootview.findViewById(R.id.divider);
+ }
+
+ public void setTitle(String text) {
+ title.setText(text);
+ title.setVisibility(text != null ? VISIBLE : GONE);
+ }
+ public void setLocation(Location location) {
+ boolean valid = location.hasLocationInfo();
+ locationText.setVisibility(valid ? VISIBLE : GONE);
+ locationIndicator.setVisibility(valid ? VISIBLE : GONE);
+ bridgesView.setVisibility(valid ? VISIBLE : GONE);
+ locationText.setText(location.name);
+ locationIndicator.setLoad(Load.getLoadByValue(location.averageLoad));
+ bridgesView.setVisibility(location.supportedTransports.contains(Connection.TransportType.OBFS4) ? VISIBLE : GONE);
+ selectedView.setChecked(location.selected);
+ }
+
+ public void showDivider(boolean show) {
+ divider.setVisibility(show ? VISIBLE : GONE);
+ }
+
+ public void setSelected(boolean selected) {
+ selectedView.setChecked(selected);
+ }
+
+ public boolean isSelected() {
+ return selectedView.checkView.getVisibility() == VISIBLE;
+ }
+
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java b/app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java
new file mode 100644
index 00000000..7cd790db
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java
@@ -0,0 +1,50 @@
+package se.leap.bitmaskclient.base.views;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.appcompat.widget.AppCompatImageView;
+
+import se.leap.bitmaskclient.R;
+
+public class SimpleCheckBox extends RelativeLayout {
+
+ AppCompatImageView checkView;
+
+
+ public SimpleCheckBox(Context context) {
+ super(context);
+ initLayout(context);
+ }
+
+ public SimpleCheckBox(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initLayout(context);
+ }
+
+ public SimpleCheckBox(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initLayout(context);
+ }
+
+ @TargetApi(21)
+ public SimpleCheckBox(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_simple_checkbox, this, true);
+ this.checkView = rootview.findViewById(R.id.check_view);
+ }
+
+ public void setChecked(boolean checked) {
+ this.checkView.setVisibility(checked ? VISIBLE : INVISIBLE);
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
index 8e3e20df..92a6af5a 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -155,7 +155,7 @@ public class GatewaysManager {
Log.d(TAG, "getGatewayLocations - new averageLoad (" + name + " - " + gateway.getHost()+ "): " + averageLoad);
Location location = new Location(
- gateway.getName(),
+ name,
averageLoad
/*gateway.getFullness()*/,
1,
diff --git a/app/src/main/res/drawable/check_bold.xml b/app/src/main/res/drawable/check_bold.xml
new file mode 100644
index 00000000..836bd3bf
--- /dev/null
+++ b/app/src/main/res/drawable/check_bold.xml
@@ -0,0 +1,8 @@
+<!-- drawable/check_bold.xml -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path android:fillColor="#000" android:pathData="M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z" />
+</vector> \ No newline at end of file
diff --git a/app/src/main/res/drawable/cust_checkbox.xml b/app/src/main/res/drawable/cust_checkbox.xml
new file mode 100644
index 00000000..1fa45d09
--- /dev/null
+++ b/app/src/main/res/drawable/cust_checkbox.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_pressed="true" >
+ <shape android:shape="rectangle" >
+ <corners android:radius="4dp" />
+ <padding android:left="8dp" android:right="8dp"/>
+ <solid android:color="@color/black800_high_transparent"/>
+ <stroke android:width="1dp" android:color="@color/colorPrimaryDark"/>
+ </shape>
+ </item>
+ <item android:state_focused="true">
+ <shape android:shape="rectangle" >
+ <corners android:radius="4dp" />
+ <padding android:left="8dp" android:right="8dp"/>
+ <solid android:color="@color/black_transparent"/>
+ <stroke android:width="1dp" android:color="@color/black800_transparent"/>
+ </shape>
+ </item>
+ <item >
+ <shape android:shape="rectangle" >
+ <corners android:radius="4dp" />
+ <padding android:left="8dp" android:right="8dp"/>
+ <solid android:color="@android:color/transparent"/>
+ <stroke android:width="1dp" android:color="@color/black800_transparent"/>
+ </shape>
+ </item>
+</selector> \ No newline at end of file
diff --git a/app/src/main/res/layout/f_gateway_selection.xml b/app/src/main/res/layout/f_gateway_selection.xml
index a5034182..643ae988 100644
--- a/app/src/main/res/layout/f_gateway_selection.xml
+++ b/app/src/main/res/layout/f_gateway_selection.xml
@@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:padding="@dimen/stdpadding"
tools:context=".base.fragments.GatewaySelectionFragment">
<LinearLayout
@@ -15,39 +15,53 @@
tools:visibility="visible"
android:layout_alignParentTop="true"
>
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/current_location_description"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:paddingStart="@dimen/activity_horizontal_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingEnd="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingBottom="@dimen/activity_vertical_margin"
+ android:orientation="horizontal">
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/recommended_title"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ android:text="@string/gateway_selection_recommended"
+ android:layout_gravity="bottom"
+ />
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_lightning_bolt"
+ />
- android:text="@string/gateway_selection_automatic_location" />
+ </LinearLayout>
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/current_location"
+ <se.leap.bitmaskclient.base.views.SelectLocationEntry
+ android:id="@+id/recommended_location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:paddingStart="@dimen/activity_horizontal_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingEnd="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingBottom="@dimen/activity_vertical_margin"
- tools:text="Paris" />
+ android:layout_marginStart="4dp"
+ android:layout_marginLeft="4dp"
+ android:clickable="true"
+ android:focusable="true"
+ />
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/manual_title"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="normal"
+ android:paddingTop="15dp"
+ android:text="@string/gateway_selection_manually"
+ android:layout_gravity="bottom"
+ />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gatewaySelection_list"
android:layout_below="@id/current_location_container"
- android:layout_above="@+id/vpn_button_container"
+ android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/stdpadding"
@@ -58,28 +72,8 @@
android:visibility="gone"
tools:visibility="visible"
android:scrollbars="vertical"
+ tools:listitem="@layout/v_select_text_list_item"
>
-
</androidx.recyclerview.widget.RecyclerView>
- <LinearLayout
- android:id="@+id/vpn_button_container"
- android:orientation="horizontal"
- android:gravity="end"
- android:layout_alignParentBottom="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="@dimen/activity_margin"
- >
-
- <androidx.appcompat.widget.AppCompatButton
- android:id="@+id/automatic_gateway_selection_btn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/gateway_selection_recommended_location"
- android:textColor="@color/button_state_font_color"
- />
- </LinearLayout>
-
-
</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/s_layout.xml b/app/src/main/res/layout/s_layout.xml
deleted file mode 100644
index d5717a5b..00000000
--- a/app/src/main/res/layout/s_layout.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <Button
- android:id="@+id/buttontest"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:text="A"/>
-
-</ScrollView>
diff --git a/app/src/main/res/layout/v_select_text_list_item.xml b/app/src/main/res/layout/v_select_text_list_item.xml
index b0cfac34..a6f78b3f 100644
--- a/app/src/main/res/layout/v_select_text_list_item.xml
+++ b/app/src/main/res/layout/v_select_text_list_item.xml
@@ -1,75 +1,107 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/item_container"
- android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
- android:clickable="true"
- android:focusable="true"
android:background="?attr/selectableItemBackground">
<!-- views are composed right to left -->
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/selected"
- android:layout_width="40dp"
- android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:src="@drawable/ic_check_bold"
- android:tint="@color/green200"
- android:visibility="invisible"
- android:paddingTop="10dp"
- android:paddingBottom="10dp"
- android:paddingRight="10dp"
- android:paddingEnd="10dp"
- tools:visibility="visible"
- />
<se.leap.bitmaskclient.base.views.LocationIndicator
android:id="@+id/quality"
android:layout_width="30dp"
- android:layout_height="match_parent"
- android:layout_toLeftOf="@id/selected"
- android:layout_toStartOf="@id/selected"
- android:layout_margin="10dp"
+ android:layout_height="25dp"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_marginBottom="12dp"
+ android:layout_marginLeft="@dimen/standard_margin"
+ android:layout_marginRight="@dimen/standard_margin"
tools:visibility="visible"
+ android:visibility="visible"
+ android:layout_alignBottom="@+id/location"
/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/bridge_image"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="40dp"
+ android:paddingBottom="5dp"
android:scaleType="fitXY"
android:layout_toStartOf="@id/quality"
android:layout_toLeftOf="@id/quality"
android:src="@drawable/ic_bridge_36"
tools:visibility="visible"
android:visibility="gone"
+ android:layout_alignBottom="@+id/location"
+ />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toEndOf="@+id/selected"
+ android:layout_toRightOf="@+id/selected"
+ android:layout_toStartOf="@id/bridge_image"
+ android:layout_toLeftOf="@id/bridge_image"
+ android:layout_alignParentTop="true"
+ android:ellipsize="end"
+ android:gravity="center_vertical"
+ android:paddingStart="@dimen/standard_margin"
+ android:paddingLeft="@dimen/standard_margin"
+ android:paddingEnd="@dimen/standard_margin"
+ android:paddingRight="@dimen/standard_margin"
+ android:paddingTop="10dp"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ tools:text="this is an interesting text"
+ android:visibility="gone"
+ tools:visibility="gone"
/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_alignParentLeft="true"
+ android:layout_toEndOf="@+id/selected"
+ android:layout_toRightOf="@+id/selected"
android:layout_toStartOf="@id/bridge_image"
android:layout_toLeftOf="@id/bridge_image"
+ android:layout_below="@id/title"
android:ellipsize="end"
android:gravity="center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeightLarge"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:paddingStart="@dimen/standard_margin"
android:paddingLeft="@dimen/standard_margin"
android:paddingEnd="@dimen/standard_margin"
android:paddingRight="@dimen/standard_margin"
+ android:paddingTop="8dp"
android:textAppearance="?android:attr/textAppearanceListItem"
android:textStyle="bold"
+ tools:visibility="visible"
+ android:visibility="visible"
tools:text="Paris" />
+
+ <se.leap.bitmaskclient.base.views.SimpleCheckBox
+ android:id="@+id/selected"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginLeft="4dp"
+ android:layout_marginBottom="@dimen/stdpadding"
+ android:layout_centerVertical="true"
+ android:src="@drawable/ic_check_bold"
+ android:tint="@color/green200"
+ android:visibility="visible"
+ tools:visibility="visible" />
+
+
<View
+ android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@android:color/darker_gray"
- android:layout_alignParentBottom="true"
+ android:layout_below="@id/location"
+ android:visibility="visible"
/>
</RelativeLayout>
diff --git a/app/src/main/res/layout/v_simple_checkbox.xml b/app/src/main/res/layout/v_simple_checkbox.xml
new file mode 100644
index 00000000..57f6f816
--- /dev/null
+++ b/app/src/main/res/layout/v_simple_checkbox.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent" android:layout_height="match_parent"
+ >
+
+ <View
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@+id/check_view"
+ android:layout_alignBottom="@+id/check_view"
+ android:layout_alignLeft="@+id/check_view"
+ android:layout_alignRight="@+id/check_view"
+ android:layout_alignStart="@+id/check_view"
+ android:layout_alignEnd="@+id/check_view"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="2dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginBottom="2dp"
+ android:background="@drawable/cust_checkbox"
+ />
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/check_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:srcCompat="@drawable/check_bold"
+ android:tint="@color/colorSuccess"
+ android:layout_centerInParent="true"
+ />
+
+
+</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7c0c46f0..9d62cc3b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -153,11 +153,10 @@
<string name="gateway_selection_title">Select location</string>
<string name="gateway_selection_warning">%s will find the best connection for you.</string>
<string name="gateway_selection_recommended_location">Use recommended location</string>
+ <string name="gateway_selection_recommended">Recommended</string>
+ <string name="gateway_selection_manually">Manually select</string>
+ <string name="gateway_selection_automatic_location">Automatically use best connection.</string>
<string name="gateway_selection_automatic">Automatic</string>
- <string name="gateway_selection_manual_location">Your traffic is currently routed through: </string>
- <string name="gateway_selection_manual_not_connected">Your traffic will be routed through: </string>
- <string name="gateway_selection_automatic_location">Your traffic is automatically routed through the best location:</string>
- <string name="gateway_selection_automatic_not_connected">Your traffic will be automatically routed through the best location.</string>
<string name="finding_best_connection">Finding best connection…</string>
<string name="reconnecting">Reconnecting…</string>
<string name="tor_starting">Starting bridges for censorship circumvention…</string>