Show different color for multiselection

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2018-07-30 15:26:33 +02:00
parent d5cde43158
commit 75dfa0643b
5 changed files with 80 additions and 27 deletions

View File

@ -41,6 +41,7 @@ import com.wireguard.android.model.Tunnel;
import com.wireguard.android.util.ExceptionLoggers; import com.wireguard.android.util.ExceptionLoggers;
import com.wireguard.android.util.ObservableSortedKeyedList; import com.wireguard.android.util.ObservableSortedKeyedList;
import com.wireguard.android.widget.MonkeyedSnackbar; import com.wireguard.android.widget.MonkeyedSnackbar;
import com.wireguard.android.widget.MultiselectableRelativeLayout;
import com.wireguard.android.widget.fab.FloatingActionsMenuRecyclerViewScrollListener; import com.wireguard.android.widget.fab.FloatingActionsMenuRecyclerViewScrollListener;
import com.wireguard.config.Config; import com.wireguard.config.Config;
@ -263,30 +264,20 @@ public class TunnelListFragment extends BaseFragment {
super.onPause(); super.onPause();
} }
private MultiselectableRelativeLayout viewForTunnel(final Tunnel tunnel, final List tunnels) {
return (MultiselectableRelativeLayout)binding.tunnelList.findViewHolderForAdapterPosition(tunnels.indexOf(tunnel)).itemView;
}
@Override @Override
public void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) { public void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
if (binding == null) if (binding == null)
return; return;
Application.getTunnelManager().getTunnels().thenAccept(tunnels -> { Application.getTunnelManager().getTunnels().thenAccept(tunnels -> {
if (newTunnel != null) if (newTunnel != null)
binding.tunnelList.findViewHolderForAdapterPosition(tunnels.indexOf(newTunnel)).itemView.setActivated(true); viewForTunnel(newTunnel, tunnels).setSingleSelected(true);
if (oldTunnel != null) 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) { private void onTunnelDeletionFinished(final Integer count, @Nullable final Throwable throwable) {
@ -373,10 +364,9 @@ public class TunnelListFragment extends BaseFragment {
}); });
if (actionMode != null) if (actionMode != null)
binding.getRoot().setActivated(actionModeListener.checkedItems.contains(position)); ((MultiselectableRelativeLayout)binding.getRoot()).setMultiSelected(actionModeListener.checkedItems.contains(position));
else 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) { public void onDestroyActionMode(final ActionMode mode) {
actionMode = null; actionMode = null;
resources = null; resources = null;
checkedItems.clear(); checkedItems.clear();
binding.tunnelList.getAdapter().notifyDataSetChanged(); binding.tunnelList.getAdapter().notifyDataSetChanged();
} }

View File

@ -0,0 +1,57 @@
/*
* Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. 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);
}
}

View File

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item> <item>
<selector> <selector>
<item android:state_activated="true"> <item app:state_multiselected="true" android:state_activated="true">
<color android:color="?android:attr/colorControlHighlight" />
<!-- TODO(msf): depending on whether or not we are in multiselect mode, choose instead:
<color android:color="?android:attr/colorControlActivated" /> <color android:color="?android:attr/colorControlActivated" />
--> </item>
<item app:state_multiselected="false" android:state_activated="true">
<color android:color="?android:attr/colorControlHighlight" />
</item> </item>
</selector> </selector>
</item> </item>

View File

@ -25,7 +25,7 @@
type="com.wireguard.android.fragment.TunnelListFragment" /> type="com.wireguard.android.fragment.TunnelListFragment" />
</data> </data>
<RelativeLayout <com.wireguard.android.widget.MultiselectableRelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/list_item_background" android:background="@drawable/list_item_background"
@ -51,5 +51,5 @@
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
app:checked="@{item.state == State.UP}" app:checked="@{item.state == State.UP}"
app:onBeforeCheckedChanged="@{fragment::setTunnelState}" /> app:onBeforeCheckedChanged="@{fragment::setTunnelState}" />
</RelativeLayout> </com.wireguard.android.widget.MultiselectableRelativeLayout>
</layout> </layout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Multiselected">
<attr name="state_multiselected" format="boolean"/>
</declare-styleable>
</resources>