Show different color for multiselection
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
		
							parent
							
								
									d5cde43158
								
							
						
					
					
						commit
						75dfa0643b
					
				@ -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();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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/colorControlActivated" />
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					            <item app:state_multiselected="false" android:state_activated="true">
 | 
				
			||||||
                <color android:color="?android:attr/colorControlHighlight" />
 | 
					                <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" />
 | 
					 | 
				
			||||||
                -->
 | 
					 | 
				
			||||||
            </item>
 | 
					            </item>
 | 
				
			||||||
        </selector>
 | 
					        </selector>
 | 
				
			||||||
    </item>
 | 
					    </item>
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										6
									
								
								app/src/main/res/values/attrs.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/src/main/res/values/attrs.xml
									
									
									
									
									
										Normal 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>
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user