summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--app/src/main/java/com/wireguard/android/ConfigListFragment.java107
-rw-r--r--app/src/main/res/drawable/ic_action_delete.xml9
-rw-r--r--app/src/main/res/menu/config_list_delete.xml9
-rw-r--r--app/src/main/res/values/strings.xml5
4 files changed, 120 insertions, 10 deletions
diff --git a/app/src/main/java/com/wireguard/android/ConfigListFragment.java b/app/src/main/java/com/wireguard/android/ConfigListFragment.java
index 9dbf77d9..c5c9dbf7 100644
--- a/app/src/main/java/com/wireguard/android/ConfigListFragment.java
+++ b/app/src/main/java/com/wireguard/android/ConfigListFragment.java
@@ -1,21 +1,31 @@
package com.wireguard.android;
+import android.content.res.Resources;
+import android.databinding.ObservableArrayMap;
import android.os.Bundle;
import android.util.Log;
+import android.view.ActionMode;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ListView;
import com.wireguard.android.databinding.ConfigListFragmentBinding;
import com.wireguard.config.Config;
+import java.util.LinkedList;
+import java.util.List;
+
/**
* Fragment containing the list of known WireGuard configurations.
*/
public class ConfigListFragment extends BaseConfigFragment {
+ private ListView listView;
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup parent,
@@ -23,7 +33,9 @@ public class ConfigListFragment extends BaseConfigFragment {
final ConfigListFragmentBinding binding =
ConfigListFragmentBinding.inflate(inflater, parent, false);
binding.setConfigs(VpnService.getInstance().getConfigs());
- final ListView listView = binding.getRoot().findViewById(R.id.config_list);
+ final View root = binding.getRoot();
+ listView = root.findViewById(R.id.config_list);
+ listView.setMultiChoiceModeListener(new ConfigListModeListener());
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(final AdapterView<?> parent, final View view,
@@ -36,18 +48,15 @@ public class ConfigListFragment extends BaseConfigFragment {
@Override
public boolean onItemLongClick(final AdapterView<?> parent, final View view,
final int position, final long id) {
- final Config config = (Config) parent.getItemAtPosition(position);
- final VpnService service = VpnService.getInstance();
- if (config == null || service == null)
- return false;
- if (config.isEnabled())
- service.disable(config.getName());
- else
- service.enable(config.getName());
+ setConfigChecked(null);
+ listView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL);
+ listView.setItemChecked(position, true);
return true;
}
});
- return binding.getRoot();
+ binding.executePendingBindings();
+ setConfigChecked(getCurrentConfig());
+ return root;
}
@Override
@@ -57,5 +66,83 @@ public class ConfigListFragment extends BaseConfigFragment {
final BaseConfigActivity activity = ((BaseConfigActivity) getActivity());
if (activity != null && activity.getCurrentConfig() != config)
activity.setCurrentConfig(config);
+ if (listView != null)
+ setConfigChecked(config);
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ listView = null;
+ }
+
+ private void setConfigChecked(final Config config) {
+ if (config != null) {
+ final int position = VpnService.getInstance().getConfigs().indexOfKey(config.getName());
+ if (position >= 0)
+ listView.setItemChecked(position, true);
+ } else {
+ final int position = listView.getCheckedItemPosition();
+ if (position >= 0)
+ listView.setItemChecked(position, false);
+ }
+ }
+
+ private class ConfigListModeListener implements AbsListView.MultiChoiceModeListener {
+ private final List<Config> configsToRemove = new LinkedList<>();
+
+ @Override
+ public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_action_delete:
+ // Ensure an unmanaged config is never the current config.
+ if (configsToRemove.contains(getCurrentConfig()))
+ setCurrentConfig(null);
+ for (final Config config : configsToRemove)
+ VpnService.getInstance().remove(config.getName());
+ configsToRemove.clear();
+ mode.finish();
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public void onItemCheckedStateChanged(final ActionMode mode, final int position,
+ final long id, final boolean checked) {
+ if (checked)
+ configsToRemove.add((Config) listView.getItemAtPosition(position));
+ else
+ configsToRemove.remove(listView.getItemAtPosition(position));
+ final int count = configsToRemove.size();
+ final Resources resources = listView.getContext().getResources();
+ mode.setTitle(resources.getQuantityString(R.plurals.list_delete_title, count, count));
+ }
+
+ @Override
+ public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
+ mode.getMenuInflater().inflate(R.menu.config_list_delete, menu);
+ return true;
+ }
+
+ @Override
+ public void onDestroyActionMode(final ActionMode mode) {
+ configsToRemove.clear();
+ listView.post(new Runnable() {
+ @Override
+ public void run() {
+ listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
+ // Restore the previous selection (before entering the action mode).
+ setConfigChecked(getCurrentConfig());
+ }
+ });
+ }
+
+ @Override
+ public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
+ configsToRemove.clear();
+ return false;
+ }
}
}
diff --git a/app/src/main/res/drawable/ic_action_delete.xml b/app/src/main/res/drawable/ic_action_delete.xml
new file mode 100644
index 00000000..fe6b85f7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_delete.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/app/src/main/res/menu/config_list_delete.xml b/app/src/main/res/menu/config_list_delete.xml
new file mode 100644
index 00000000..7896d522
--- /dev/null
+++ b/app/src/main/res/menu/config_list_delete.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/menu_action_delete"
+ android:alphabeticShortcut="d"
+ android:icon="@drawable/ic_action_delete"
+ android:showAsAction="always"
+ android:title="@string/delete" />
+</menu>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ab82e7fe..bba997e2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
+ <plurals name="list_delete_title">
+ <item quantity="one">%d configuration selected</item>
+ <item quantity="other">%d configurations selected</item>
+ </plurals>
<string name="app_name">WireGuard</string>
<string name="config_name">Configuration name</string>
<string name="connected">Connected</string>
@@ -19,4 +23,5 @@
<string name="public_key">Public key</string>
<string name="save">Save</string>
<string name="settings">Settings</string>
+ <string name="delete">Delete</string>
</resources>