ConfigListFragment: Implement config selection and removal
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
f1d97a585a
commit
73217a098a
@ -1,21 +1,31 @@
|
|||||||
package com.wireguard.android;
|
package com.wireguard.android;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.databinding.ObservableArrayMap;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.ActionMode;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.AbsListView;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
import com.wireguard.android.databinding.ConfigListFragmentBinding;
|
import com.wireguard.android.databinding.ConfigListFragmentBinding;
|
||||||
import com.wireguard.config.Config;
|
import com.wireguard.config.Config;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fragment containing the list of known WireGuard configurations.
|
* Fragment containing the list of known WireGuard configurations.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ConfigListFragment extends BaseConfigFragment {
|
public class ConfigListFragment extends BaseConfigFragment {
|
||||||
|
private ListView listView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(final LayoutInflater inflater, final ViewGroup parent,
|
public View onCreateView(final LayoutInflater inflater, final ViewGroup parent,
|
||||||
@ -23,7 +33,9 @@ public class ConfigListFragment extends BaseConfigFragment {
|
|||||||
final ConfigListFragmentBinding binding =
|
final ConfigListFragmentBinding binding =
|
||||||
ConfigListFragmentBinding.inflate(inflater, parent, false);
|
ConfigListFragmentBinding.inflate(inflater, parent, false);
|
||||||
binding.setConfigs(VpnService.getInstance().getConfigs());
|
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() {
|
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(final AdapterView<?> parent, final View view,
|
public void onItemClick(final AdapterView<?> parent, final View view,
|
||||||
@ -36,18 +48,15 @@ public class ConfigListFragment extends BaseConfigFragment {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onItemLongClick(final AdapterView<?> parent, final View view,
|
public boolean onItemLongClick(final AdapterView<?> parent, final View view,
|
||||||
final int position, final long id) {
|
final int position, final long id) {
|
||||||
final Config config = (Config) parent.getItemAtPosition(position);
|
setConfigChecked(null);
|
||||||
final VpnService service = VpnService.getInstance();
|
listView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||||
if (config == null || service == null)
|
listView.setItemChecked(position, true);
|
||||||
return false;
|
|
||||||
if (config.isEnabled())
|
|
||||||
service.disable(config.getName());
|
|
||||||
else
|
|
||||||
service.enable(config.getName());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return binding.getRoot();
|
binding.executePendingBindings();
|
||||||
|
setConfigChecked(getCurrentConfig());
|
||||||
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -57,5 +66,83 @@ public class ConfigListFragment extends BaseConfigFragment {
|
|||||||
final BaseConfigActivity activity = ((BaseConfigActivity) getActivity());
|
final BaseConfigActivity activity = ((BaseConfigActivity) getActivity());
|
||||||
if (activity != null && activity.getCurrentConfig() != config)
|
if (activity != null && activity.getCurrentConfig() != config)
|
||||||
activity.setCurrentConfig(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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
app/src/main/res/drawable/ic_action_delete.xml
Normal file
9
app/src/main/res/drawable/ic_action_delete.xml
Normal file
@ -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>
|
9
app/src/main/res/menu/config_list_delete.xml
Normal file
9
app/src/main/res/menu/config_list_delete.xml
Normal file
@ -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>
|
@ -1,5 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<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="app_name">WireGuard</string>
|
||||||
<string name="config_name">Configuration name</string>
|
<string name="config_name">Configuration name</string>
|
||||||
<string name="connected">Connected</string>
|
<string name="connected">Connected</string>
|
||||||
@ -19,4 +23,5 @@
|
|||||||
<string name="public_key">Public key</string>
|
<string name="public_key">Public key</string>
|
||||||
<string name="save">Save</string>
|
<string name="save">Save</string>
|
||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
|
<string name="delete">Delete</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user