diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java index f8b03b2..f9634eb 100644 --- a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java +++ b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java @@ -41,6 +41,7 @@ import com.wireguard.android.model.Tunnel; import com.wireguard.android.util.ExceptionLoggers; import com.wireguard.android.util.ObservableSortedKeyedList; import com.wireguard.android.widget.MonkeyedSnackbar; +import com.wireguard.android.widget.MultiselectableRelativeLayout; import com.wireguard.android.widget.fab.FloatingActionsMenuRecyclerViewScrollListener; import com.wireguard.config.Config; @@ -263,30 +264,20 @@ public class TunnelListFragment extends BaseFragment { super.onPause(); } + private MultiselectableRelativeLayout viewForTunnel(final Tunnel tunnel, final List tunnels) { + return (MultiselectableRelativeLayout)binding.tunnelList.findViewHolderForAdapterPosition(tunnels.indexOf(tunnel)).itemView; + } + @Override public void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) { if (binding == null) return; Application.getTunnelManager().getTunnels().thenAccept(tunnels -> { if (newTunnel != null) - binding.tunnelList.findViewHolderForAdapterPosition(tunnels.indexOf(newTunnel)).itemView.setActivated(true); + viewForTunnel(newTunnel, tunnels).setSingleSelected(true); if (oldTunnel != null) - binding.tunnelList.findViewHolderForAdapterPosition(tunnels.indexOf(oldTunnel)).itemView.setActivated(false); - + viewForTunnel(oldTunnel, tunnels).setSingleSelected(false); }); - - /* Alternative 1: results in sluggish change: - - if (binding.tunnelList.getAdapter() == null) - return; - - - * Alternative 2: results in overly quick change: - - binding.tunnelList.getAdapter().notifyDataSetChanged(); - - * Hence, we go with the above. - */ } private void onTunnelDeletionFinished(final Integer count, @Nullable final Throwable throwable) { @@ -373,10 +364,9 @@ public class TunnelListFragment extends BaseFragment { }); if (actionMode != null) - binding.getRoot().setActivated(actionModeListener.checkedItems.contains(position)); + ((MultiselectableRelativeLayout)binding.getRoot()).setMultiSelected(actionModeListener.checkedItems.contains(position)); else - binding.getRoot().setActivated(getSelectedTunnel() == tunnel); - + ((MultiselectableRelativeLayout)binding.getRoot()).setSingleSelected(getSelectedTunnel() == tunnel); }); } @@ -433,7 +423,6 @@ public class TunnelListFragment extends BaseFragment { public void onDestroyActionMode(final ActionMode mode) { actionMode = null; resources = null; - checkedItems.clear(); binding.tunnelList.getAdapter().notifyDataSetChanged(); } diff --git a/app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java b/app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java new file mode 100644 index 0000000..c64dc32 --- /dev/null +++ b/app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2018 Jason A. Donenfeld . All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.wireguard.android.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.RelativeLayout; + +import com.wireguard.android.R; + +public class MultiselectableRelativeLayout extends RelativeLayout { + public MultiselectableRelativeLayout(final Context context) { + super(context); + } + public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs) { + super(context, attrs); + } + public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs, final int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + private static final int[] STATE_MULTISELECTED = { R.attr.state_multiselected }; + + private boolean multiselected; + + @Override + protected int[] onCreateDrawableState(final int extraSpace) { + if (multiselected) { + final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); + mergeDrawableStates(drawableState, STATE_MULTISELECTED); + return drawableState; + } + return super.onCreateDrawableState(extraSpace); + } + + public void setMultiSelected(final boolean on) { + if (!multiselected) { + multiselected = true; + refreshDrawableState(); + } + setActivated(on); + } + + public void setSingleSelected(final boolean on) { + if (multiselected) { + multiselected = false; + refreshDrawableState(); + } + setActivated(on); + } +} diff --git a/app/src/main/res/drawable/list_item_background.xml b/app/src/main/res/drawable/list_item_background.xml index f064676..d62f323 100644 --- a/app/src/main/res/drawable/list_item_background.xml +++ b/app/src/main/res/drawable/list_item_background.xml @@ -1,12 +1,13 @@ - + - + + + + - diff --git a/app/src/main/res/layout/tunnel_list_item.xml b/app/src/main/res/layout/tunnel_list_item.xml index ba36fe6..cf25b83 100644 --- a/app/src/main/res/layout/tunnel_list_item.xml +++ b/app/src/main/res/layout/tunnel_list_item.xml @@ -25,7 +25,7 @@ type="com.wireguard.android.fragment.TunnelListFragment" /> - - + diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 0000000..85a987f --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file