Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Changed
### Deprecated
### Added
- Added `notifyAdapterDataSetChanged()` method to the MultiChoiceAdapter in order to be able to keep a valid internal state of the selected/deselected items. This will then delegate the actual `RecyclerView.Adapter#notifyDataSetChanged()` to do the rest.

### Fixed
### Deleted

Expand All @@ -23,6 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
and other configuration change
- Added `deselect(int position)` method to the MultiChoiceAdapter


## [2.1.0]
### Added
- Possibility to use QuantityStrings for the toolbar while selecting items
Expand Down
3 changes: 3 additions & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,7 @@ It will automatically keep the selection in place when orientation and other con

// Mode
boolean isInSingleClickMode()

// Extra
void notifyAdapterDataSetChanged()
```
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ Extend your adapter to the MultiChoiceAdapter and add it to the RecyclerView as
mMultiChoiceRecyclerView.setAdapter(myAdapter);
```

**N.B.**
- Do not forget to call **super.onBindViewHolder(holder, position);** when binding the view holder

Customize the activation or deactivation just overriding the setActive(View rootView, boolean state) method of the MultiChoiceAdapter
```java
@Override
Expand All @@ -87,6 +84,12 @@ Customize the activation or deactivation just overriding the setActive(View root
}
```

<br>

#### Important notes
- Do not forget to call `super.onBindViewHolder(holder, position)` when binding the view holder
- Use the method `notifyAdapterDataSetChanged()` instead of the classic `notifyDataSetChanged()` in order to let the library refresh the list and keep a correct internal library state.

## Features
[Sample features](https://github.com/dvdciri/MultiChoiceRecyclerView/blob/master/FEATURES.md)

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
Expand Down
6 changes: 3 additions & 3 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ machine:
dependencies:
pre:
- echo y | android update sdk --no-ui --all --filter "tools"
- echo y | android update sdk --no-ui --all --filter "build-tools-23.0.3"
- echo y | android update sdk --no-ui --all --filter tool,extra-android-m2repository,extra-android-support,extra-google-google_play_services,extra-google-m2repository,android-23
- echo y | android update sdk --no-ui --all --filter build-tools-23.4.0
- echo y | android update sdk --no-ui --all --filter "build-tools-25.0.0"
- echo y | android update sdk --no-ui --all --filter tool,extra-android-m2repository,extra-android-support,extra-google-google_play_services,extra-google-m2repository,android-25
- echo y | android update sdk --no-ui --all --filter build-tools-25.0.0

test:
override:
Expand Down
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Fri Oct 07 18:10:10 BST 2016
#Fri Mar 10 16:13:49 GMT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
10 changes: 5 additions & 5 deletions library/multichoicerecyclerview/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ checkstyle {
}

ext {
PUBLISH_VERSION = '2.3.0'
SUPPORT_LIBRARY_VERSION = '24.2.1'
BUILD_TOOLS = "23.0.3"
TARGET_SDK = 23
PUBLISH_VERSION = '2.4.0'
SUPPORT_LIBRARY_VERSION = '25.3.1'
BUILD_TOOLS = "25.0.0"
TARGET_SDK = 25

PUBLISH_ARTIFACT_ID = 'multichoicerecyclerview'
PUBLISH_GROUP_ID = 'com.davidecirillo.multichoicerecyclerview'
Expand Down Expand Up @@ -54,7 +54,7 @@ android {
lintOptions {
// if true, stop the gradle build if errors are found
abortOnError true
disable 'GoogleAppIndexingWarning'
disable 'GoogleAppIndexingWarning', 'UnusedResources'
}

buildTypes {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public void selectAll() {
* @return True if the view has been selected, False if the view is already selected or is not part of the item list
*/
public boolean select(int position) {
if (mItemList.containsKey(position) && mItemList.get(position) == State.INACTIVE) {
if (mItemList.containsKey(position) && mItemList.get(position) == State.INACTIVE) {
perform(Action.SELECT, position, true, true);
return true;
}
Expand Down Expand Up @@ -161,12 +161,22 @@ public void onRestoreInstanceState(Bundle savedInstanceState) {
mItemList = (Map<Integer, State>) savedInstanceState.getSerializable(EXTRA_ITEM_LIST);

int selectedListSize = getSelectedItemListInternal().size();
updateToolbarIfNeeded(selectedListSize);
updateMultiChoiceMode(selectedListSize);
processNotifyDataSetChanged();
refreshMultiChoiceModeState(selectedListSize);
}
}

/**
* <b>Use this method instead of {@link RecyclerView.Adapter#notifyDataSetChanged()} for
* notifying a change in the data set.</b>
*
* <b>NOTE: The new data will not keep the current selected status, all the item will be reset to INACTIVE.</b>
*
*/
public void notifyAdapterDataSetChanged() {
notifyAdapterDataSetChangedInternal();
refreshMultiChoiceModeState(getSelectedItemListInternal().size());
}

//endregion

//region Private methods
Expand Down Expand Up @@ -240,9 +250,7 @@ private void perform(Action action, int position, boolean withCallback, boolean

int selectedListSize = getSelectedItemListInternal().size();

updateToolbarIfNeeded(selectedListSize);

updateMultiChoiceMode(selectedListSize);
refreshMultiChoiceModeState(selectedListSize);

processNotifyDataSetChanged();

Expand All @@ -255,19 +263,17 @@ private void perform(Action action, int position, boolean withCallback, boolean
}
}

private void processNotifyDataSetChanged() {
void processNotifyDataSetChanged() {
if (mRecyclerView != null) {
notifyDataSetChanged();
}
}

private void updateToolbarIfNeeded(int selectedListSize) {
private void refreshMultiChoiceModeState(int selectedListSize) {
if ((mIsInMultiChoiceMode || mIsInSingleClickMode || selectedListSize > 0) && mMultiChoiceToolbarHelper != null) {
mMultiChoiceToolbarHelper.updateToolbar(selectedListSize);
}
}

private void updateMultiChoiceMode(int selectedListSize) {
boolean somethingSelected = selectedListSize > 0;
if (mIsInMultiChoiceMode != somethingSelected) {
mIsInMultiChoiceMode = somethingSelected;
Expand All @@ -292,8 +298,7 @@ private void performAll(Action action) {
mItemList.put(i, state);
}

updateToolbarIfNeeded(selectedItems);
updateMultiChoiceMode(selectedItems);
refreshMultiChoiceModeState(selectedItems);

processNotifyDataSetChanged();

Expand All @@ -306,6 +311,14 @@ private void performAll(Action action) {
}
}

private void notifyAdapterDataSetChangedInternal() {
mItemList.clear();
for (int i = 0; i < getItemCount(); i++) {
mItemList.put(i, State.INACTIVE);
}
processNotifyDataSetChanged();
}

@Override
public void onClearButtonPressed() {
performAll(Action.DESELECT);
Expand All @@ -315,9 +328,7 @@ public void onClearButtonPressed() {
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
mRecyclerView = recyclerView;

for (int i = 0; i < getItemCount(); i++) {
mItemList.put(i, State.INACTIVE);
}
notifyAdapterDataSetChangedInternal();
super.onAttachedToRecyclerView(recyclerView);
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -48,7 +48,7 @@ public void setUp() throws Exception {

mViewHolder = new TestViewHolder(mMockItemView);

mMultiChoiceAdapter = new TestAdapter();
mMultiChoiceAdapter = spy(new TestAdapter());
mMultiChoiceAdapter.setItemList(mMockItemList);
mMultiChoiceAdapter.setMultiChoiceSelectionListener(mMockMultiChoiceListener);

Expand All @@ -59,7 +59,7 @@ public void setUp() throws Exception {

@After
public void tearDown() throws Exception {

((TestAdapter) mMultiChoiceAdapter).setItemCountTest(0);
}

@Test
Expand Down Expand Up @@ -353,6 +353,39 @@ public void givenThreeItemWhenDeselectAllThenAllDeselected() throws Exception {
verify(mMockItemList, times(expectedCount)).put(anyInt(), eq(MultiChoiceAdapter.State.INACTIVE));
}

@Test
public void testWhenNotifyAdapterDataSetChangedThenClear() throws Exception {
// Given

// When
mMultiChoiceAdapter.notifyAdapterDataSetChanged();

// Then
verify(mMockItemList, times(1)).clear();
}

@Test
public void testWhenNotifyAdapterDataSetChangedThenItemReset() throws Exception {
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);

// Given
((TestAdapter) mMultiChoiceAdapter).setItemCountTest(10);

// When
mMultiChoiceAdapter.notifyAdapterDataSetChanged();

// Then
verify(mMockItemList, times(10)).put(argumentCaptor.capture(), eq(MultiChoiceAdapter.State.INACTIVE));
}

@Test
public void testWhenNotifyAdapterDataSetChangedThenProcessNotifyDataSetChangedCalled() throws Exception {
mMultiChoiceAdapter.notifyAdapterDataSetChanged();

verify(mMultiChoiceAdapter, times(1)).processNotifyDataSetChanged();

}

private void addInactiveTestItems(int count) {
for (int i = 0; i < count; i++) {
mRealItemList.put(i, MultiChoiceAdapter.State.INACTIVE);
Expand All @@ -368,15 +401,20 @@ private TestViewHolder(View itemView) {
private class TestAdapter extends MultiChoiceAdapter<TestViewHolder> {

private View.OnClickListener mOnClickListener;
private int mTestItemCount;

@Override
public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}

public void setItemCountTest(int anInt) {
mTestItemCount = anInt;
}

@Override
public int getItemCount() {
return 0;
return mTestItemCount;
}

@Override
Expand Down
11 changes: 4 additions & 7 deletions sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ apply plugin: 'android-apt'

ext {
PUBLISH_VERSION = '2.0.0'
SUPPORT_LIBRARY_VERSION = '24.2.1'
BUILD_TOOLS = "23.0.3"
TARGET_SDK = 23
SUPPORT_LIBRARY_VERSION = '25.3.1'
BUILD_TOOLS = "25.0.0"
TARGET_SDK = 25
}

android {
Expand All @@ -26,7 +26,7 @@ android {
}

lintOptions {
abortOnError true
abortOnError false
disable 'Overdraw','UnusedResources','IconLocation','ContentDescription','AppLinksAutoVerifyError','AppLinksAutoVerifyWarning'
}

Expand Down Expand Up @@ -81,9 +81,6 @@ dependencies {
compile "com.android.support:design:${SUPPORT_LIBRARY_VERSION}"
compile 'com.jakewharton:butterknife:8.1.0'
apt 'com.jakewharton:butterknife-compiler:8.1.0'
// RxAndroid - asynchronous operations
compile 'io.reactivex:rxandroid:1.0.1'
compile 'io.reactivex:rxjava:1.0.14'
compile 'com.squareup.picasso:picasso:2.5.2'
// Testing-only dependencies
testCompile 'junit:junit:4.10'
Expand Down
Loading