summaryrefslogtreecommitdiffhomepage
path: root/app
diff options
context:
space:
mode:
authorSamuel Holland <samuel@sholland.org>2017-11-28 20:14:47 -0600
committerSamuel Holland <samuel@sholland.org>2017-11-28 20:14:47 -0600
commit4a672fc05d4b40b2e169bdf7b6212f86c3789de0 (patch)
tree132e6a235a61b8f816223eacc9983b5a0be947d6 /app
parent19f008955963015abbaf0c9fd88492d0eb0a6ace (diff)
ConfigListFragment: Use a floating action menu
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'app')
-rw-r--r--app/build.gradle1
-rw-r--r--app/src/main/java/com/wireguard/android/ConfigActivity.java24
-rw-r--r--app/src/main/java/com/wireguard/android/ConfigListFragment.java100
-rw-r--r--app/src/main/res/drawable/fab_label_background.xml10
-rw-r--r--app/src/main/res/layout/config_list_fragment.xml46
-rw-r--r--app/src/main/res/menu/config_list.xml15
-rw-r--r--app/src/main/res/values/strings.xml3
-rw-r--r--app/src/main/res/values/styles.xml8
8 files changed, 136 insertions, 71 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 11f9edaf..ed84813b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -22,5 +22,6 @@ android {
}
dependencies {
+ implementation 'com.getbase:floatingactionbutton:1.10.1'
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
diff --git a/app/src/main/java/com/wireguard/android/ConfigActivity.java b/app/src/main/java/com/wireguard/android/ConfigActivity.java
index 24284eb1..b92b34e3 100644
--- a/app/src/main/java/com/wireguard/android/ConfigActivity.java
+++ b/app/src/main/java/com/wireguard/android/ConfigActivity.java
@@ -9,7 +9,6 @@ import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
-import com.wireguard.android.backends.VpnService;
import com.wireguard.config.Config;
/**
@@ -18,7 +17,6 @@ import com.wireguard.config.Config;
public class ConfigActivity extends BaseConfigActivity {
private static final String KEY_EDITOR_STATE = "editorState";
- private static final int REQUEST_IMPORT = 1;
private static final String TAG_DETAIL = "detail";
private static final String TAG_EDIT = "edit";
private static final String TAG_LIST = "list";
@@ -134,17 +132,10 @@ public class ConfigActivity extends BaseConfigActivity {
}
@Override
- public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
- if (requestCode == REQUEST_IMPORT) {
- if (resultCode == RESULT_OK)
- VpnService.getInstance().importFrom(data.getData());
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
- }
-
- @Override
public void onBackPressed() {
+ final ConfigListFragment listFragment = (ConfigListFragment) fragments.get(TAG_LIST);
+ if (listFragment.isVisible() && listFragment.tryCollapseMenu())
+ return;
super.onBackPressed();
// The visible fragment is now the one that was on top of the back stack, if there was one.
if (isEditing())
@@ -200,19 +191,10 @@ public class ConfigActivity extends BaseConfigActivity {
// The back arrow in the action bar should act the same as the back button.
onBackPressed();
return true;
- case R.id.menu_action_add:
- startActivity(new Intent(this, AddActivity.class));
- return true;
case R.id.menu_action_edit:
// Try to make the editing fragment visible.
setIsEditing(true);
return true;
- case R.id.menu_action_import:
- final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("*/*");
- startActivityForResult(intent, REQUEST_IMPORT);
- return true;
case R.id.menu_action_save:
// This menu item is handled by the editing fragment.
return false;
diff --git a/app/src/main/java/com/wireguard/android/ConfigListFragment.java b/app/src/main/java/com/wireguard/android/ConfigListFragment.java
index 1067dc73..4b0432aa 100644
--- a/app/src/main/java/com/wireguard/android/ConfigListFragment.java
+++ b/app/src/main/java/com/wireguard/android/ConfigListFragment.java
@@ -1,12 +1,15 @@
package com.wireguard.android;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
@@ -26,28 +29,49 @@ import java.util.List;
*/
public class ConfigListFragment extends BaseConfigFragment {
- private ListView listView;
+ private static final int REQUEST_IMPORT = 1;
+
+ private ConfigListFragmentBinding binding;
@Override
- public void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
+ public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
+ if (requestCode == REQUEST_IMPORT) {
+ if (resultCode == Activity.RESULT_OK)
+ VpnService.getInstance().importFrom(data.getData());
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
}
@Override
- public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
- inflater.inflate(R.menu.config_list, menu);
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup parent,
final Bundle savedInstanceState) {
- final ConfigListFragmentBinding binding =
- ConfigListFragmentBinding.inflate(inflater, parent, false);
+ binding = ConfigListFragmentBinding.inflate(inflater, parent, false);
binding.setConfigs(VpnService.getInstance().getConfigs());
- listView = binding.configList;
- listView.setMultiChoiceModeListener(new ConfigListModeListener());
- listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ binding.addFromFile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View view) {
+ final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("*/*");
+ startActivityForResult(intent, REQUEST_IMPORT);
+ binding.addMenu.collapse();
+ }
+ });
+ binding.addFromScratch.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View view) {
+ startActivity(new Intent(getActivity(), AddActivity.class));
+ binding.addMenu.collapse();
+ }
+ });
+ binding.configList.setMultiChoiceModeListener(new ConfigListModeListener());
+ binding.configList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(final AdapterView<?> parent, final View view,
final int position, final long id) {
@@ -55,16 +79,29 @@ public class ConfigListFragment extends BaseConfigFragment {
setCurrentConfig(config);
}
});
- listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
+ binding.configList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(final AdapterView<?> parent, final View view,
final int position, final long id) {
setConfigChecked(null);
- listView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL);
- listView.setItemChecked(position, true);
+ binding.configList.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL);
+ binding.configList.setItemChecked(position, true);
return true;
}
});
+ binding.configList.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ @SuppressLint("ClickableViewAccessibility")
+ public boolean onTouch(final View view, final MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN &&
+ binding.configList.pointToPosition((int) event.getX(), (int) event.getY())
+ == ListView.INVALID_POSITION) {
+ binding.addMenu.collapse();
+ return true;
+ }
+ return false;
+ }
+ });
binding.executePendingBindings();
setConfigChecked(getCurrentConfig());
return binding.getRoot();
@@ -75,29 +112,36 @@ public class ConfigListFragment extends BaseConfigFragment {
final BaseConfigActivity activity = ((BaseConfigActivity) getActivity());
if (activity != null)
activity.setCurrentConfig(config);
- if (listView != null)
+ if (binding != null)
setConfigChecked(config);
}
@Override
public void onDestroyView() {
super.onDestroyView();
- listView = null;
+ binding = null;
}
private void setConfigChecked(final Config config) {
if (config != null) {
- @SuppressWarnings("unchecked")
- final ObservableMapAdapter<String, Config> adapter =
- (ObservableMapAdapter<String, Config>) listView.getAdapter();
+ @SuppressWarnings("unchecked") final ObservableMapAdapter<String, Config> adapter =
+ (ObservableMapAdapter<String, Config>) binding.configList.getAdapter();
final int position = adapter.getPosition(config.getName());
if (position >= 0)
- listView.setItemChecked(position, true);
+ binding.configList.setItemChecked(position, true);
} else {
- final int position = listView.getCheckedItemPosition();
+ final int position = binding.configList.getCheckedItemPosition();
if (position >= 0)
- listView.setItemChecked(position, false);
+ binding.configList.setItemChecked(position, false);
+ }
+ }
+
+ public boolean tryCollapseMenu() {
+ if (binding != null && binding.addMenu.isExpanded()) {
+ binding.addMenu.collapse();
+ return true;
}
+ return false;
}
private class ConfigListModeListener implements AbsListView.MultiChoiceModeListener {
@@ -124,11 +168,11 @@ public class ConfigListFragment extends BaseConfigFragment {
public void onItemCheckedStateChanged(final ActionMode mode, final int position,
final long id, final boolean checked) {
if (checked)
- configsToRemove.add((Config) listView.getItemAtPosition(position));
+ configsToRemove.add((Config) binding.configList.getItemAtPosition(position));
else
- configsToRemove.remove(listView.getItemAtPosition(position));
+ configsToRemove.remove(binding.configList.getItemAtPosition(position));
final int count = configsToRemove.size();
- final Resources resources = listView.getContext().getResources();
+ final Resources resources = binding.getRoot().getContext().getResources();
mode.setTitle(resources.getQuantityString(R.plurals.list_delete_title, count, count));
}
@@ -141,10 +185,10 @@ public class ConfigListFragment extends BaseConfigFragment {
@Override
public void onDestroyActionMode(final ActionMode mode) {
configsToRemove.clear();
- listView.post(new Runnable() {
+ binding.configList.post(new Runnable() {
@Override
public void run() {
- listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
+ binding.configList.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
// Restore the previous selection (before entering the action mode).
setConfigChecked(getCurrentConfig());
}
diff --git a/app/src/main/res/drawable/fab_label_background.xml b/app/src/main/res/drawable/fab_label_background.xml
new file mode 100644
index 00000000..c0315fd6
--- /dev/null
+++ b/app/src/main/res/drawable/fab_label_background.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="4dp" />
+ <padding
+ android:bottom="4dp"
+ android:left="8dp"
+ android:right="8dp"
+ android:top="4dp" />
+ <solid android:color="?android:attr/colorPrimary" />
+</shape>
diff --git a/app/src/main/res/layout/config_list_fragment.xml b/app/src/main/res/layout/config_list_fragment.xml
index 7e8304e6..b3c48175 100644
--- a/app/src/main/res/layout/config_list_fragment.xml
+++ b/app/src/main/res/layout/config_list_fragment.xml
@@ -10,11 +10,45 @@
type="com.wireguard.android.bindings.ObservableSortedMap&lt;String, com.wireguard.config.Config&gt;" />
</data>
- <ListView
- android:id="@+id/config_list"
+ <RelativeLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:choiceMode="singleChoice"
- app:items="@{configs}"
- app:layout="@{@layout/config_list_item}" />
+ android:layout_height="match_parent">
+
+ <ListView
+ android:id="@+id/config_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:choiceMode="singleChoice"
+ app:items="@{configs}"
+ app:layout="@{@layout/config_list_item}" />
+
+ <com.getbase.floatingactionbutton.FloatingActionsMenu
+ android:id="@+id/add_menu"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_marginBottom="8dp"
+ android:layout_marginEnd="8dp"
+ app:fab_labelStyle="@style/fab_label"
+ app:fab_labelsPosition="left">
+
+ <com.getbase.floatingactionbutton.FloatingActionButton
+ android:id="@+id/add_from_file"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:fab_icon="@drawable/ic_action_save"
+ app:fab_size="mini"
+ app:fab_title="@string/add_from_file" />
+
+ <com.getbase.floatingactionbutton.FloatingActionButton
+ android:id="@+id/add_from_scratch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:fab_icon="@drawable/ic_action_edit"
+ app:fab_size="mini"
+ app:fab_title="@string/add_from_scratch" />
+ </com.getbase.floatingactionbutton.FloatingActionsMenu>
+
+ </RelativeLayout>
</layout>
diff --git a/app/src/main/res/menu/config_list.xml b/app/src/main/res/menu/config_list.xml
deleted file mode 100644
index 0e94e7ff..00000000
--- a/app/src/main/res/menu/config_list.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:id="@+id/menu_action_add"
- android:alphabeticShortcut="n"
- android:icon="@drawable/ic_action_add"
- android:showAsAction="always"
- android:title="@string/add" />
- <item
- android:id="@+id/menu_action_import"
- android:alphabeticShortcut="o"
- android:icon="@drawable/ic_action_open"
- android:showAsAction="ifRoom"
- android:title="@string/import_config" />
-</menu>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4f548672..4687ec49 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,8 +4,9 @@
<item quantity="one">%d configuration selected</item>
<item quantity="other">%d configurations selected</item>
</plurals>
- <string name="add">Add empty config</string>
<string name="add_activity_title">New WireGuard configuration</string>
+ <string name="add_from_file">Add from file</string>
+ <string name="add_from_scratch">Add from scratch</string>
<string name="add_peer">Add peer</string>
<string name="addresses">Addresses</string>
<string name="allowed_ips">Allowed IPs</string>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..11f3e544
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <style name="fab_label" parent="android:TextAppearance.DeviceDefault.Inverse">
+ <item name="android:background">@drawable/fab_label_background</item>
+ </style>
+
+</resources>