SelectionMode without ActionMode added, use of previous ListSelectionHelper as new SelectableHelper, so ListViews still can be available.

This commit is contained in:
Lucas Legrand 2018-07-18 11:20:07 +02:00
parent e8f04f3d7c
commit 801a9a6708
6 changed files with 371 additions and 264 deletions

View file

@ -26,14 +26,10 @@ import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper; import android.support.v7.widget.helper.ItemTouchHelper;
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.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
@ -47,10 +43,13 @@ import org.linphone.core.ChatRoom;
import org.linphone.core.ChatRoomListenerStub; import org.linphone.core.ChatRoomListenerStub;
import org.linphone.core.Core; import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub; import org.linphone.core.CoreListenerStub;
import org.linphone.core.EventLog;
import org.linphone.fragments.FragmentsAvailable; import org.linphone.fragments.FragmentsAvailable;
import org.linphone.ui.SelectableHelper;
import org.linphone.ui.SwipeController; import org.linphone.ui.SwipeController;
import org.linphone.ui.SwipeControllerActions; import org.linphone.ui.SwipeControllerActions;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -61,12 +60,8 @@ import static org.linphone.fragments.FragmentsAvailable.CHAT_LIST;
* Sources: Linphone + https://enoent.fr/blog/2015/01/18/recyclerview-basics/ * Sources: Linphone + https://enoent.fr/blog/2015/01/18/recyclerview-basics/
* */ * */
public class ChatListFragment extends Fragment implements ContactsUpdatedListener, ChatRoomsAdapter.ChatRoomViewHolder.ClickListener { public class ChatListFragment extends Fragment implements ContactsUpdatedListener, ChatRoomsAdapter.ChatRoomViewHolder.ClickListener, SelectableHelper.DeleteListener {
private ActionModeCallback actionModeCallback = new ActionModeCallback();
private ActionMode actionMode;
private LinearLayout mEditTopBar, mTopBar;
private ImageView mEditButton, mSelectAllButton, mDeselectAllButton,mDeleteButton, mCancelButton;
private RecyclerView mChatRoomsList; private RecyclerView mChatRoomsList;
private TextView mNoChatHistory; private TextView mNoChatHistory;
private ImageView mNewDiscussionButton, mBackToCallButton; private ImageView mNewDiscussionButton, mBackToCallButton;
@ -77,6 +72,7 @@ public class ChatListFragment extends Fragment implements ContactsUpdatedListene
private ChatRoomListenerStub mChatRoomListener; private ChatRoomListenerStub mChatRoomListener;
private Context mContext; private Context mContext;
public List<ChatRoom> mRooms; public List<ChatRoom> mRooms;
private SelectableHelper mSelectionHelper;
@Override @Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -91,37 +87,36 @@ public class ChatListFragment extends Fragment implements ContactsUpdatedListene
//Views definition //Views definition
mChatRoomsList = view.findViewById(R.id.chatList); mChatRoomsList = view.findViewById(R.id.chatList);
mWaitLayout = view.findViewById(R.id.waitScreen); mWaitLayout = view.findViewById(R.id.waitScreen);
mEditTopBar = view.findViewById(R.id.edit_list);
mTopBar = view.findViewById(R.id.top_bar);
mSelectAllButton = view.findViewById(R.id.select_all);
mDeselectAllButton = view.findViewById(R.id.deselect_all);
mDeleteButton= view.findViewById(R.id.delete);
mEditButton = view.findViewById(R.id.edit);
mCancelButton = view.findViewById(R.id.cancel);
mNewDiscussionButton = view.findViewById(R.id.new_discussion); mNewDiscussionButton = view.findViewById(R.id.new_discussion);
mBackToCallButton = view.findViewById(R.id.back_in_call); mBackToCallButton = view.findViewById(R.id.back_in_call);
//Creation and affectation of adapter to the RecyclerView //Creation and affectation of adapter to the RecyclerView
mChatRoomsAdapter = new ChatRoomsAdapter(mContext, R.layout.chatlist_cell, mRooms,this); mSelectionHelper = new SelectableHelper(view, this);
mChatRoomsAdapter = new ChatRoomsAdapter(mContext, R.layout.chatlist_cell, mRooms,this, mSelectionHelper);
mChatRoomsList.setAdapter(mChatRoomsAdapter); mChatRoomsList.setAdapter(mChatRoomsAdapter);
mSelectionHelper.setAdapter(mChatRoomsAdapter);
mSelectionHelper.setDialogMessage(R.string.chat_room_delete_dialog);
//Initialize the LayoutManager //Initialize the LayoutManager
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext);
mChatRoomsList.setLayoutManager(layoutManager); mChatRoomsList.setLayoutManager(layoutManager);
mWaitLayout.setVisibility(View.GONE); mWaitLayout.setVisibility(View.GONE);
//All commentend code below, until line 145, have to be uncommented to allow swipe actions.
//Actions allowed by swipe buttons //Actions allowed by swipe buttons
final SwipeController swipeController = new SwipeController(new SwipeControllerActions() { /*final SwipeController swipeController = new SwipeController(new SwipeControllerActions() {
@Override *//*@Override
public void onLeftClicked(int position) { public void onLeftClicked(int position) {
super.onLeftClicked(position); super.onLeftClicked(position);
} }*//*
@Override @Override
public void onRightClicked(int position) { public void onRightClicked(int position) {
@ -131,8 +126,9 @@ public class ChatListFragment extends Fragment implements ContactsUpdatedListene
//Initialize swipe detection //Initialize swipe detection
ItemTouchHelper itemTouchhelper = new ItemTouchHelper(swipeController);
itemTouchhelper.attachToRecyclerView(mChatRoomsList); ItemTouchHelper itemTouchHelper = new ItemTouchHelper(swipeController);
itemTouchHelper.attachToRecyclerView(mChatRoomsList);
//Add swipe buttons //Add swipe buttons
mChatRoomsList.addItemDecoration(new RecyclerView.ItemDecoration() { mChatRoomsList.addItemDecoration(new RecyclerView.ItemDecoration() {
@ -141,17 +137,12 @@ public class ChatListFragment extends Fragment implements ContactsUpdatedListene
swipeController.onDraw(c); swipeController.onDraw(c);
} }
}); });
*/
// Buttons onClickListeners definitions // Buttons onClickListeners definitions
mEditButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Start selection mode
actionMode = getActivity().startActionMode(actionModeCallback);
}
});
mNewDiscussionButton.setOnClickListener(new View.OnClickListener() { mNewDiscussionButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
@ -207,8 +198,9 @@ public class ChatListFragment extends Fragment implements ContactsUpdatedListene
@Override @Override
public void onItemClicked(int position) { public void onItemClicked(int position) {
if (actionMode != null) { if (mChatRoomsAdapter.isEditionEnabled()) {
toggleSelection(position); mChatRoomsAdapter.toggleSelection(position);
}else{ }else{
ChatRoom room = (ChatRoom) mChatRoomsAdapter.getItem(position); ChatRoom room = (ChatRoom) mChatRoomsAdapter.getItem(position);
LinphoneActivity.instance().goToChat(room.getPeerAddress().asString(),null); LinphoneActivity.instance().goToChat(room.getPeerAddress().asString(),null);
@ -217,143 +209,15 @@ public class ChatListFragment extends Fragment implements ContactsUpdatedListene
@Override @Override
public boolean onItemLongClicked(int position) { public boolean onItemLongClicked(int position) {
if (actionMode == null) { if (mChatRoomsAdapter.isEditionEnabled()!=true) {
//Start selection mode //Start selection mode
actionMode = getActivity().startActionMode(actionModeCallback); mSelectionHelper.enterEditionMode();
} }
toggleSelection(position);
return true;
}
/*Switch selection state of an item and handle
* selection buttons visibility
*/
private void toggleSelection(int position) {
mChatRoomsAdapter.toggleSelection(position); mChatRoomsAdapter.toggleSelection(position);
int count = mChatRoomsAdapter.getSelectedItemCount();
if (count < mChatRoomsAdapter.getItemCount()) {
mDeselectAllButton.setVisibility(View.GONE);
mSelectAllButton.setVisibility(View.VISIBLE);
}else{
mSelectAllButton.setVisibility(View.GONE);
mDeselectAllButton.setVisibility(View.VISIBLE);
}
mChatRoomsAdapter.notifyItemChanged(position);
actionMode.invalidate();
}
//Selection mode (ActionMode)
private class ActionModeCallback implements ActionMode.Callback {
@SuppressWarnings("unused")
private final String TAG = ActionModeCallback.class.getSimpleName();
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
actionMode=mode;
mTopBar.setVisibility(View.GONE);
mEditTopBar.setVisibility(View.VISIBLE);
//Transmits ActionMode current state to the adapter
for (Integer i = 0; i <= mChatRoomsAdapter.getItemCount(); i++) {
mChatRoomsAdapter.setEditionMode(mode);
}
/*
* Inflate custom menu, example for future plans
*mode.getMenuInflater().inflate (R.menu.edit_list_menu, menu);
*/
mCancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
actionMode.finish();
}
});
/*Way to disable the sliding menu (left)
* mSideMenu=(DrawerLayout) getActivity().findViewById(R.id.side_menu);
* mSideMenu.setDrawerLockMode(1);
* */
//Add all non-selected items to the selection
mSelectAllButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (Integer i = 0; i < mChatRoomsAdapter.getItemCount(); i++) {
if (!mChatRoomsAdapter.isSelected(i)) {
toggleSelection(i);
}
}
}
});
//Remove all selected items from the selection
mDeselectAllButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (Integer i = 0; i < mChatRoomsAdapter.getItemCount(); i++) {
if (mChatRoomsAdapter.isSelected(i)) {
toggleSelection(i);
}
}
}
});
mDeleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mChatRoomsAdapter.removeItems(mChatRoomsAdapter.getSelectedItems());
actionMode.finish();
}
});
return true; return true;
} }
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
/*
Meant to execute actions as Contextual Action Bar item is clicked,
unused in our case as the CAB isn't used.
No need for clickListeners.
Example below for future evolution.
case R.id.delete:
return true
*/
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mChatRoomsAdapter.clearSelection();
mTopBar.setVisibility(View.VISIBLE);
mEditTopBar.setVisibility(View.GONE);
actionMode = null;
mChatRoomsAdapter.setEditionMode(actionMode);
}
}
//ActionMode ending
//Existing functions before RecyclerView conversion //Existing functions before RecyclerView conversion
@ -408,6 +272,34 @@ public class ChatListFragment extends Fragment implements ContactsUpdatedListene
} }
@Override
public void onDeleteSelection(Object[] objectsToDelete) {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
mChatRoomDeletionPendingCount = objectsToDelete.length;
for (Object obj : objectsToDelete) {
ChatRoom room = (ChatRoom)obj;
for (EventLog eventLog : room.getHistoryEvents(0)) {
if (eventLog.getType() == EventLog.Type.ConferenceChatMessage) {
ChatMessage message = eventLog.getChatMessage();
if (message.getAppdata() != null && !message.isOutgoing()) {
File file = new File(message.getAppdata());
if (file.exists()) {
file.delete(); // Delete downloaded file from incoming message that will be deleted
}
}
}
}
room.addListener(mChatRoomListener);
lc.deleteChatRoom(room);
}
if (mChatRoomDeletionPendingCount > 0) {
mWaitLayout.setVisibility(View.VISIBLE);
}
}
@Override @Override
public void onContactsUpdated() { public void onContactsUpdated() {
if (!LinphoneActivity.isInstanciated() || LinphoneActivity.instance().getCurrentFragment() != CHAT_LIST) if (!LinphoneActivity.isInstanciated() || LinphoneActivity.instance().getCurrentFragment() != CHAT_LIST)

View file

@ -21,15 +21,12 @@ package org.linphone.chat;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.ActionMode;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import org.linphone.LinphoneManager; import org.linphone.LinphoneManager;
@ -40,11 +37,11 @@ import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact; import org.linphone.contacts.LinphoneContact;
import org.linphone.core.ChatMessage; import org.linphone.core.ChatMessage;
import org.linphone.core.ChatRoom; import org.linphone.core.ChatRoom;
import org.linphone.core.ChatRoomListener;
import org.linphone.core.ChatRoomListenerStub; import org.linphone.core.ChatRoomListenerStub;
import org.linphone.core.Core; import org.linphone.core.Core;
import org.linphone.core.EventLog; import org.linphone.core.EventLog;
import org.linphone.ui.SelectableAdapter; import org.linphone.ui.SelectableAdapter;
import org.linphone.ui.SelectableHelper;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@ -96,14 +93,14 @@ public class ChatRoomsAdapter extends SelectableAdapter<ChatRoomsAdapter.ChatRoo
} }
//Handle the onClick/onLongClick event for the ViewHolder //Handle the onClick/onLongClick event for the ViewHolder
@Override // @Override
public void onClick(View v) { public void onClick(View v) {
if (listener != null) { if (listener != null) {
listener.onItemClicked(getAdapterPosition()); listener.onItemClicked(getAdapterPosition());
} }
} }
@Override // @Override
public boolean onLongClick(View v) { public boolean onLongClick(View v) {
if (listener != null) { if (listener != null) {
return listener.onItemLongClicked(getAdapterPosition()); return listener.onItemLongClicked(getAdapterPosition());
@ -170,12 +167,10 @@ public class ChatRoomsAdapter extends SelectableAdapter<ChatRoomsAdapter.ChatRoo
private ChatRoomListenerStub mListener; private ChatRoomListenerStub mListener;
private int itemResource; private int itemResource;
private ChatRoomViewHolder.ClickListener clickListener; private ChatRoomViewHolder.ClickListener clickListener;
private boolean editionMode;
public ChatRoomsAdapter(Context context, int itemResource, List<ChatRoom> mRooms, ChatRoomViewHolder.ClickListener clickListener) { public ChatRoomsAdapter(Context context, int itemResource, List<ChatRoom> mRooms, ChatRoomViewHolder.ClickListener clickListener, SelectableHelper helper) {
super(); super(helper);
this.editionMode = false;
this.clickListener = clickListener; this.clickListener = clickListener;
this.mRooms = mRooms; this.mRooms = mRooms;
this.mContext = context; this.mContext = context;
@ -204,25 +199,25 @@ public class ChatRoomsAdapter extends SelectableAdapter<ChatRoomsAdapter.ChatRoo
//Bind datas to the ViewHolder //Bind datas to the ViewHolder
ChatRoom room = this.mRooms.get(position); ChatRoom room = this.mRooms.get(position);
//Shows checkboxes when ActionMode enabled //Shows checkboxes when ActionMode enabled
holder.delete.setVisibility(this.editionMode == true ? View.VISIBLE : View.INVISIBLE); holder.delete.setVisibility(this.isEditionEnabled() == true ? View.VISIBLE : View.INVISIBLE);
holder.unreadMessages.setVisibility(this.editionMode == false ? View.VISIBLE : View.INVISIBLE); holder.unreadMessages.setVisibility(this.isEditionEnabled() == false ? View.VISIBLE : View.INVISIBLE);
//Set checkbox checked if item selected //Set checkbox checked if item selected
holder.delete.setChecked(isSelected(position) ? true : false); holder.delete.setChecked(isSelected(position) ? true : false);
//Bind the chatroom object to the holder //Bind the chatroom object to the holder
holder.bindChatRoom(room); holder.bindChatRoom(room);
} }
//Let know the adapter if ActionMode is enabled // Let know the adapter if ActionMode is enabled
public void setEditionMode(ActionMode actionMode) { // public void setEditionMode(ActionMode actionMode) {
if ( actionMode != null) { // if ( isEditionEnabled() == true) {
this.editionMode=true; // this.editionMode=true;
this.notifyDataSetChanged(); //Needed to update the whole list checkboxes // this.notifyDataSetChanged(); //Needed to update the whole list checkboxes
} else { // } else {
this.editionMode=false; // this.editionMode=false;
this.notifyDataSetChanged(); // this.notifyDataSetChanged();
} // }
//
} // }
public void refresh() { public void refresh() {
mRooms = new ArrayList<>(Arrays.asList(LinphoneManager.getLc().getChatRooms())); mRooms = new ArrayList<>(Arrays.asList(LinphoneManager.getLc().getChatRooms()));
@ -242,6 +237,7 @@ public class ChatRoomsAdapter extends SelectableAdapter<ChatRoomsAdapter.ChatRoo
room.removeListener(mListener); room.removeListener(mListener);
} }
mRooms.clear(); mRooms.clear();
notifyDataSetChanged();
} }
@ -253,52 +249,52 @@ public class ChatRoomsAdapter extends SelectableAdapter<ChatRoomsAdapter.ChatRoo
mRooms.remove(position); mRooms.remove(position);
notifyItemRemoved(position); notifyItemRemoved(position);
} }
//
public void removeItems(List<Integer> positions) { // public void removeItems(List<Integer> positions) {
// Reverse-sort the list // // Reverse-sort the list
Collections.sort(positions, new Comparator<Integer>() { // Collections.sort(positions, new Comparator<Integer>() {
@Override // @Override
public int compare(Integer lhs, Integer rhs) { // public int compare(Integer lhs, Integer rhs) {
return rhs - lhs; // return rhs - lhs;
} // }
}); // });
//
// Split the list in ranges // // Split the list in ranges
while (!positions.isEmpty()) { // while (!positions.isEmpty()) {
if (positions.size() == 1) { // if (positions.size() == 1) {
removeItem(positions.get(0)); // removeItem(positions.get(0));
positions.remove(0); // positions.remove(0);
//
} else { // } else {
int count = 1; // int count = 1;
while (positions.size() > count && positions.get(count).equals(positions.get(count - 1) - 1)) { // while (positions.size() > count && positions.get(count).equals(positions.get(count - 1) - 1)) {
++count; // ++count;
} // }
//
if (count == 1) { // if (count == 1) {
removeItem(positions.get(0)); // removeItem(positions.get(0));
} else { // } else {
removeRange(positions.get(count - 1), count); // removeRange(positions.get(count - 1), count);
} // }
//
for (int i = 0; i < count; ++i) { // for (int i = 0; i < count; ++i) {
positions.remove(0); // positions.remove(0);
} // }
} // }
} // }
} // }
//
private void removeRange(int positionStart, int itemCount) { // private void removeRange(int positionStart, int itemCount) {
for (int i = 0; i < itemCount; ++i) { // for (int i = 0; i < itemCount; ++i) {
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); // Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
cleanRoom(positionStart); // cleanRoom(positionStart);
lc.deleteChatRoom(mRooms.get(positionStart)); // lc.deleteChatRoom(mRooms.get(positionStart));
mRooms.remove(positionStart); // mRooms.remove(positionStart);
} // }
notifyItemRangeRemoved(positionStart, itemCount); // notifyItemRangeRemoved(positionStart, itemCount);
} // }
//
//Delete downloaded file from incoming message that will be deleted // //Delete downloaded file from incoming message that will be deleted
private void cleanRoom (int position) { private void cleanRoom (int position) {
for (EventLog eventLog : mRooms.get(position).getHistoryEvents(0)) { for (EventLog eventLog : mRooms.get(position).getHistoryEvents(0)) {
@ -326,6 +322,7 @@ public class ChatRoomsAdapter extends SelectableAdapter<ChatRoomsAdapter.ChatRoo
return this.mRooms.size(); return this.mRooms.size();
} }
@Override
public Object getItem(int position) { public Object getItem(int position) {
return mRooms.get(position); return mRooms.get(position);
} }

View file

@ -2,6 +2,7 @@ package org.linphone.ui;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.SparseBooleanArray; import android.util.SparseBooleanArray;
import android.widget.CompoundButton;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -9,13 +10,36 @@ import java.util.List;
public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> { public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final String TAG = SelectableAdapter.class.getSimpleName(); private static final String TAG = SelectableAdapter.class.getSimpleName();
private SparseBooleanArray mSelectedItems;
private boolean mIsEditionEnabled=false;
private SelectableHelper mListHelper;
private SparseBooleanArray selectedItems; public SelectableAdapter(SelectableHelper helper) {
mSelectedItems = new SparseBooleanArray();
mListHelper = helper;
public SelectableAdapter() { }
selectedItems = new SparseBooleanArray(); private CompoundButton.OnCheckedChangeListener mDeleteCheckboxListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
Integer position = (Integer)compoundButton.getTag();
mListHelper.updateSelectionButtons(mSelectedItems.size() == 0, mSelectedItems.size() == getItemCount());
}
};
public CompoundButton.OnCheckedChangeListener getDeleteListener() {
return mDeleteCheckboxListener;
}
public boolean isEditionEnabled() {
return mIsEditionEnabled;
} }
public void enableEdition(boolean set) {
mIsEditionEnabled = set;
mSelectedItems.clear();
notifyDataSetChanged();
}
/** /**
* Indicates if the item at position position is selected * Indicates if the item at position position is selected
* @param position Position of the item to check * @param position Position of the item to check
@ -30,31 +54,33 @@ public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder> exte
* @param position Position of the item to toggle the selection status for * @param position Position of the item to toggle the selection status for
*/ */
public void toggleSelection(int position) { public void toggleSelection(int position) {
if (selectedItems.get(position, false)) { if (mSelectedItems.get(position, false)) {
selectedItems.delete(position); mSelectedItems.delete(position);
} else { } else {
selectedItems.put(position, true); mSelectedItems.put(position, true);
} }
mListHelper.updateSelectionButtons(getSelectedItemCount() == 0, getSelectedItemCount() == getItemCount());
notifyItemChanged(position); notifyItemChanged(position);
} }
/** /**
* Clear the selection status for all items * Clear the selection status for all items
*/ */
public void clearSelection() { // public void clearSelection() {
List<Integer> selection = getSelectedItems(); // List<Integer> selection = getSelectedItems();
selectedItems.clear(); // mSelectedItems.clear();
for (Integer i : selection) { // for (Integer i : selection) {
notifyItemChanged(i); // notifyItemChanged(i);
} // }
} // }
/** /**
* Count the selected items * Count the selected items
* @return Selected items count * @return Selected items count
*/ */
public int getSelectedItemCount() { public int getSelectedItemCount() {
return selectedItems.size(); return mSelectedItems.size();
} }
/** /**
@ -62,10 +88,28 @@ public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder> exte
* @return List of selected items ids * @return List of selected items ids
*/ */
public List<Integer> getSelectedItems() { public List<Integer> getSelectedItems() {
List<Integer> items = new ArrayList<>(selectedItems.size()); List<Integer> items = new ArrayList<>(mSelectedItems.size());
for (int i = 0; i < selectedItems.size(); ++i) { for (int i = 0; i < mSelectedItems.size(); ++i) {
items.add(selectedItems.keyAt(i)); items.add(mSelectedItems.keyAt(i));
} }
return items; return items;
} }
public void selectAll() {
for (Integer i = 0; i < getItemCount(); i++) {
mSelectedItems.put(i, true);
notifyItemChanged(i);
}
mListHelper.updateSelectionButtons(false, true);
// notifyDataSetChanged();
}
public void deselectAll() {
mSelectedItems.clear();
mListHelper.updateSelectionButtons(true, false);
notifyDataSetChanged();
}
public abstract Object getItem(int position);
} }

View file

@ -0,0 +1,174 @@
/*
SelectableHelper.java
Copyright (C) 2017 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.linphone.ui;
import android.app.Dialog;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.linphone.R;
import org.linphone.activities.LinphoneActivity;
public class SelectableHelper {
private ImageView mEditButton, mSelectAllButton, mDeselectAllButton, mDeleteSelectionButton, mCancelButton;
private LinearLayout mEditTopBar, mTopBar;
private SelectableAdapter<RecyclerView.ViewHolder> mAdapter;
private DeleteListener mDeleteListener;
private Context mContext;
private int mDialogDeleteMessageResourceId;
public void setDialogMessage(int id) {
mDialogDeleteMessageResourceId = id;
}
public interface DeleteListener {
void onDeleteSelection(Object[] objectsToDelete);
}
public SelectableHelper(View view, DeleteListener listener) {
mContext = view.getContext();
mDeleteListener = listener;
mEditTopBar = view.findViewById(R.id.edit_list);
mTopBar = view.findViewById(R.id.top_bar);
mCancelButton = view.findViewById(R.id.cancel);
mCancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
quitEditionMode();
}
});
mEditButton = view.findViewById(R.id.edit);
mEditButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mAdapter.getItemCount() > 0) {
mAdapter.enableEdition(true);
mTopBar.setVisibility(View.GONE);
mEditTopBar.setVisibility(View.VISIBLE);
}
}
});
mSelectAllButton = view.findViewById(R.id.select_all);
mSelectAllButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mAdapter.selectAll();
}
});
mDeselectAllButton = view.findViewById(R.id.deselect_all);
mDeselectAllButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mAdapter.deselectAll();
}
});
mDeleteSelectionButton = view.findViewById(R.id.delete);
mDeleteSelectionButton.setEnabled(false);
mDeleteSelectionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Dialog dialog = LinphoneActivity.instance().displayDialog(mContext.getString(mDialogDeleteMessageResourceId));
Button delete = dialog.findViewById(R.id.delete_button);
Button cancel = dialog.findViewById(R.id.cancel);
delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mDeleteListener.onDeleteSelection(getSelectedObjects());
dialog.dismiss();
quitEditionMode();
}
});
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dialog.dismiss();
quitEditionMode();
}
});
dialog.show();
}
});
mDialogDeleteMessageResourceId = R.string.delete_text;
}
public void setAdapter(SelectableAdapter adapter) {
mAdapter=adapter;
}
public void updateSelectionButtons(boolean isSelectionEmpty, boolean isSelectionFull) {
if (isSelectionEmpty) {
mDeleteSelectionButton.setEnabled(false);
} else {
mDeleteSelectionButton.setEnabled(true);
}
if (isSelectionFull) {
mSelectAllButton.setVisibility(View.GONE);
mDeselectAllButton.setVisibility(View.VISIBLE);
} else {
mSelectAllButton.setVisibility(View.VISIBLE);
mDeselectAllButton.setVisibility(View.GONE);
}
}
private void quitEditionMode() {
mAdapter.enableEdition(false);
mTopBar.setVisibility(View.VISIBLE);
mEditTopBar.setVisibility(View.GONE);
mDeleteSelectionButton.setEnabled(false);
mSelectAllButton.setVisibility(View.VISIBLE);
mDeselectAllButton.setVisibility(View.GONE);
}
public void enterEditionMode() {
mAdapter.enableEdition(true);
mTopBar.setVisibility(View.GONE);
mEditTopBar.setVisibility(View.VISIBLE);
mDeleteSelectionButton.setEnabled(false);
mSelectAllButton.setVisibility(View.GONE);
mDeselectAllButton.setVisibility(View.VISIBLE);
}
private Object[] getSelectedObjects() {
Object objects[] = new Object[mAdapter.getSelectedItemCount()];
int index = 0;
for (Integer i : mAdapter.getSelectedItems()) {
objects[index] = mAdapter.getItem(i);
index++;
}
return objects;
}
}

View file

@ -14,7 +14,7 @@ import static android.support.v7.widget.helper.ItemTouchHelper.LEFT;
enum ButtonsState { enum ButtonsState {
GONE, GONE,
LEFT_VISIBLE, // LEFT_VISIBLE,
RIGHT_VISIBLE RIGHT_VISIBLE
} }
/* /*
@ -70,7 +70,7 @@ public class SwipeController extends Callback {
if (actionState == ACTION_STATE_SWIPE) { if (actionState == ACTION_STATE_SWIPE) {
if (buttonShowedState != ButtonsState.GONE) { if (buttonShowedState != ButtonsState.GONE) {
if (buttonShowedState == ButtonsState.LEFT_VISIBLE) dX = Math.max(dX, buttonWidth); // if (buttonShowedState == ButtonsState.LEFT_VISIBLE) dX = Math.max(dX, buttonWidth);
if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) dX = Math.min(dX, -buttonWidth); if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) dX = Math.min(dX, -buttonWidth);
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}else { }else {
@ -91,10 +91,10 @@ public class SwipeController extends Callback {
View itemView = viewHolder.itemView; View itemView = viewHolder.itemView;
Paint p = new Paint(); Paint p = new Paint();
RectF leftButton = new RectF(itemView.getLeft(), itemView.getTop(), itemView.getLeft() + buttonWidthWithoutPadding, itemView.getBottom()); // RectF leftButton = new RectF(itemView.getLeft(), itemView.getTop(), itemView.getLeft() + buttonWidthWithoutPadding, itemView.getBottom());
p.setColor(Color.BLUE); // p.setColor(Color.BLUE);
c.drawRoundRect(leftButton, corners, corners, p); // c.drawRoundRect(leftButton, corners, corners, p);
drawText("EDIT", c, leftButton, p); // drawText("EDIT", c, leftButton, p);
RectF rightButton = new RectF(itemView.getRight() - buttonWidthWithoutPadding, itemView.getTop(), itemView.getRight(), itemView.getBottom()); RectF rightButton = new RectF(itemView.getRight() - buttonWidthWithoutPadding, itemView.getTop(), itemView.getRight(), itemView.getBottom());
p.setColor(Color.RED); p.setColor(Color.RED);
@ -102,10 +102,10 @@ public class SwipeController extends Callback {
drawText("DELETE", c, rightButton, p); drawText("DELETE", c, rightButton, p);
buttonInstance = null; buttonInstance = null;
if (buttonShowedState == ButtonsState.LEFT_VISIBLE) { /* if (buttonShowedState == ButtonsState.LEFT_VISIBLE) {
buttonInstance = leftButton; buttonInstance = leftButton;
} }
else if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) { else */if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) {
buttonInstance = rightButton; buttonInstance = rightButton;
} }
@ -137,7 +137,7 @@ public class SwipeController extends Callback {
swipeBack = event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP; swipeBack = event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP;
if (swipeBack) { if (swipeBack) {
if (dX < -buttonWidth) buttonShowedState = ButtonsState.RIGHT_VISIBLE; if (dX < -buttonWidth) buttonShowedState = ButtonsState.RIGHT_VISIBLE;
else if (dX > buttonWidth) buttonShowedState = ButtonsState.LEFT_VISIBLE; // else if (dX > buttonWidth) buttonShowedState = ButtonsState.LEFT_VISIBLE;
if (buttonShowedState != ButtonsState.GONE) { if (buttonShowedState != ButtonsState.GONE) {
setTouchDownListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); setTouchDownListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
@ -184,10 +184,10 @@ public class SwipeController extends Callback {
setItemsClickable(recyclerView, true); setItemsClickable(recyclerView, true);
swipeBack = false; swipeBack = false;
if (buttonsActions != null && buttonInstance != null && buttonInstance.contains(event.getX(), event.getY())) { if (buttonsActions != null && buttonInstance != null && buttonInstance.contains(event.getX(), event.getY())) {
if (buttonShowedState == ButtonsState.LEFT_VISIBLE) { /*if (buttonShowedState == ButtonsState.LEFT_VISIBLE) {
buttonsActions.onLeftClicked(viewHolder.getAdapterPosition()); buttonsActions.onLeftClicked(viewHolder.getAdapterPosition());
} }
else if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) { else */if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) {
buttonsActions.onRightClicked(viewHolder.getAdapterPosition()); buttonsActions.onRightClicked(viewHolder.getAdapterPosition());
} }
} }

View file

@ -1,7 +1,7 @@
package org.linphone.ui; package org.linphone.ui;
public abstract class SwipeControllerActions { public abstract class SwipeControllerActions {
public void onLeftClicked(int position) {} // public void onLeftClicked(int position) {}
public void onRightClicked(int position) {} public void onRightClicked(int position) {}
} }