Skip to content

Commit 246d65f

Browse files
committed
The list items of a ListDialog can now be disabled.
1 parent 5b83da4 commit 246d65f

File tree

6 files changed

+261
-30
lines changed

6 files changed

+261
-30
lines changed

library/src/main/java/de/mrapp/android/dialog/AbstractListDialog.java

+16
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ public final void setItemChecked(final int position, final boolean checked) {
111111
decorator.setItemChecked(position, checked);
112112
}
113113

114+
@Override
115+
public final boolean isItemEnabled(final int position) {
116+
return decorator.isItemEnabled(position);
117+
}
118+
119+
@Override
120+
public final void setItemEnabled(final int position, final boolean enabled) {
121+
decorator.setItemEnabled(position, enabled);
122+
}
123+
114124
@Override
115125
public final void setItems(@Nullable final CharSequence[] items,
116126
@Nullable final OnClickListener listener) {
@@ -181,6 +191,12 @@ public final void setOnItemSelectedListener(
181191
decorator.setOnItemSelectedListener(listener);
182192
}
183193

194+
@Override
195+
public final void setOnItemEnabledListener(
196+
@Nullable final ListDialog.OnItemEnabledListener listener) {
197+
decorator.setOnItemEnabledListener(listener);
198+
}
199+
184200
@NonNull
185201
@CallSuper
186202
@Override

library/src/main/java/de/mrapp/android/dialog/adapter/RecyclerViewAdapterWrapper.java

+124-22
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@
2020
import android.widget.Checkable;
2121
import android.widget.FrameLayout;
2222

23-
import java.util.HashSet;
24-
import java.util.Set;
25-
2623
import androidx.annotation.NonNull;
2724
import androidx.annotation.Nullable;
2825
import androidx.recyclerview.widget.RecyclerView;
2926

27+
import java.util.HashSet;
28+
import java.util.Set;
29+
3030
import de.mrapp.android.dialog.R;
31+
import de.mrapp.android.dialog.model.ListDialog.OnItemEnabledListener;
3132
import de.mrapp.android.dialog.model.ListDialog.OnItemSelectedListener;
3233
import de.mrapp.android.util.ThemeUtil;
3334
import de.mrapp.util.Condition;
@@ -238,16 +239,26 @@ public T getWrappedViewHolder() {
238239
*/
239240
private final Handler handler;
240241

242+
/**
243+
* A set, which contains the positions of all disabled items.
244+
*/
245+
private Set<Integer> disabledItems;
246+
241247
/**
242248
* The listener, which is notified, when a list item has been clicked.
243249
*/
244250
private OnItemClickListener itemClickListener;
245251

246252
/**
247-
* The listener, which is notified, when a list item has been selected.
253+
* The listener, which is notified, when a list item has been selected or unselected.
248254
*/
249255
private OnItemSelectedListener itemSelectedListener;
250256

257+
/**
258+
* The listener, which is notified, when a list item has been enabled or disabled.
259+
*/
260+
private OnItemEnabledListener itemEnabledListener;
261+
251262
/**
252263
* Creates a listener, which allows to select a list item when it has been clicked.
253264
*
@@ -294,6 +305,56 @@ public void run() {
294305
};
295306
}
296307

308+
/**
309+
* Sets, whether the list item at a specific position should be enabled, or not.
310+
*
311+
* @param position The position of the list item, whose enable state should be changed, as an {@link
312+
* Integer} value
313+
* @param enabled True, if the list item should be enabled, false otherwise
314+
* @return True, if the enable state of the item at the given position has changed, false
315+
* otherwise
316+
*/
317+
public final boolean setItemEnabledInternally(final int position, final boolean enabled) {
318+
boolean result = false;
319+
320+
if (enabled) {
321+
if (disabledItems != null) {
322+
result = disabledItems.remove(position);
323+
324+
if (disabledItems.isEmpty()) {
325+
disabledItems = null;
326+
}
327+
}
328+
} else {
329+
if (disabledItems == null) {
330+
disabledItems = new HashSet<>();
331+
}
332+
333+
result = disabledItems.add(position);
334+
}
335+
336+
return result;
337+
}
338+
339+
/**
340+
* Sets the enable state of a specific view and all of its children.
341+
*
342+
* @param view The view, whose enable state should be set, as an instance of the class
343+
* {@link View}. The view may not be null
344+
* @param enabled True, if the view should be enabled, false otherwise
345+
*/
346+
private void setViewEnabled(@NonNull final View view, final boolean enabled) {
347+
view.setEnabled(enabled);
348+
349+
if (view instanceof ViewGroup) {
350+
ViewGroup viewGroup = (ViewGroup) view;
351+
352+
for (int i = 0; i < viewGroup.getChildCount(); i++) {
353+
setViewEnabled(viewGroup.getChildAt(i), enabled);
354+
}
355+
}
356+
}
357+
297358
/**
298359
* Creates a new wrapper that encapsulates a recycler view adapter in order to manage the
299360
* selection states of the adapter's list items.
@@ -314,6 +375,7 @@ public RecyclerViewAdapterWrapper(@NonNull final Context context,
314375
this.wrappedAdapter = wrappedAdapter;
315376
this.choiceMode = choiceMode;
316377
this.handler = new Handler(context.getMainLooper());
378+
this.disabledItems = null;
317379
}
318380

319381
/**
@@ -327,7 +389,8 @@ public final void setOnItemClickListener(@Nullable final OnItemClickListener lis
327389
}
328390

329391
/**
330-
* Sets the listener, which should be notified, when a list item has been selected.
392+
* Sets the listener, which should be notified, when a list item has been selected or
393+
* unselected.
331394
*
332395
* @param listener The listener, which should be set, as an instance of the type {@link
333396
* OnItemSelectedListener} or null, if no listener should be notified
@@ -336,6 +399,16 @@ public final void setOnItemSelectedListener(@Nullable final OnItemSelectedListen
336399
this.itemSelectedListener = listener;
337400
}
338401

402+
/**
403+
* Sets the listener, which should be notified, when a list item has been enabled or disabled.
404+
*
405+
* @param listener The listener, which should be set, as an instance of the type
406+
* {@link OnItemEnabledListener} or null, if no listener should be notified
407+
*/
408+
public final void setOnItemEnabledListener(@Nullable final OnItemEnabledListener listener) {
409+
this.itemEnabledListener = listener;
410+
}
411+
339412
/**
340413
* Returns the choice mode, which is used by the adapter.
341414
*
@@ -380,12 +453,55 @@ public final void setItemChecked(final int position, final boolean checked) {
380453
if (choiceMode.setItemChecked(position, checked)) {
381454
notifyDataSetChanged();
382455

383-
if (checked && itemSelectedListener != null) {
384-
itemSelectedListener.onItemSelected(position);
456+
if (itemSelectedListener != null) {
457+
itemSelectedListener.onItemSelectionStateChanged(position, checked);
458+
}
459+
}
460+
}
461+
462+
/**
463+
* Returns, whether the list item at a specific position is currently enabled, or not.
464+
*
465+
* @param position The position of the list item, whose enable state should be returned, as an {@link
466+
* Integer} value
467+
* @return True, if the list item is enabled, false otherwise
468+
*/
469+
public final boolean isItemEnabled(final int position) {
470+
return disabledItems == null || !disabledItems.contains(position);
471+
}
472+
473+
/**
474+
* Sets, whether the list item at a specific position should be enabled, or not.
475+
*
476+
* @param position The position of the list item, whose enable state should be changed, as an {@link
477+
* Integer} value
478+
* @param enabled True, if the list item should be enabled, false otherwise
479+
*/
480+
public final void setItemEnabled(final int position, final boolean enabled) {
481+
if (setItemEnabledInternally(position, enabled)) {
482+
notifyDataSetChanged();
483+
484+
if (itemEnabledListener != null) {
485+
itemEnabledListener.onItemEnableStateChanged(position, enabled);
385486
}
386487
}
387488
}
388489

490+
@Override
491+
public final int getItemCount() {
492+
return wrappedAdapter.getItemCount();
493+
}
494+
495+
@Override
496+
public final long getItemId(final int position) {
497+
return wrappedAdapter.getItemId(position);
498+
}
499+
500+
@Override
501+
public final int getItemViewType(final int position) {
502+
return wrappedAdapter.getItemViewType(position);
503+
}
504+
389505
@NonNull
390506
@Override
391507
public final ViewHolderWrapper<VH> onCreateViewHolder(@NonNull final ViewGroup parent,
@@ -408,26 +524,12 @@ public final void onBindViewHolder(@NonNull final ViewHolderWrapper<VH> holder,
408524
wrappedAdapter.onBindViewHolder(wrappedViewHolder, position);
409525
View view = holder.itemView;
410526
view.setOnClickListener(createItemClickListener(position));
527+
setViewEnabled(view, isItemEnabled(position));
411528
View wrappedView = wrappedViewHolder.itemView;
412529

413530
if (wrappedView instanceof Checkable) {
414531
handler.post(createCheckableRunnable((Checkable) wrappedView, isItemChecked(position)));
415532
}
416533
}
417534

418-
@Override
419-
public final int getItemCount() {
420-
return wrappedAdapter.getItemCount();
421-
}
422-
423-
@Override
424-
public final long getItemId(final int position) {
425-
return wrappedAdapter.getItemId(position);
426-
}
427-
428-
@Override
429-
public final int getItemViewType(final int position) {
430-
return wrappedAdapter.getItemViewType(position);
431-
}
432-
433535
}

library/src/main/java/de/mrapp/android/dialog/builder/AbstractListDialogBuilder.java

+28
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,34 @@ public final BuilderType setItemTypeface(@NonNull final Typeface typeface) {
133133
return self();
134134
}
135135

136+
/**
137+
* Sets, whether the list item at a specific position of the dialog, which is created by the
138+
* builder, should be checked, or not.
139+
*
140+
* @param position The position of the list item as an {@link Integer} value
141+
* @param checked True, if the list item should be checked, false otherwise
142+
* @return The builder, the method has been called upon, as an instance of the generic type
143+
* BuilderType
144+
*/
145+
public final BuilderType setItemChecked(final int position, final boolean checked) {
146+
getProduct().setItemChecked(position, checked);
147+
return self();
148+
}
149+
150+
/**
151+
* Sets, whether the list item at a specific position of the dialog, which is created by the
152+
* builder, should be enabled, or not.
153+
*
154+
* @param position The position of the list item as an {@link Integer} value
155+
* @param enabled True, if the list item should be enabled, false otherwise
156+
* @return The builder, the method has been called upon, as an instance of the generic type
157+
* BuilderType
158+
*/
159+
public final BuilderType setItemEnabled(final int position, final boolean enabled) {
160+
getProduct().setItemEnabled(position, enabled);
161+
return self();
162+
}
163+
136164
/**
137165
* Sets the items, which should be shown by the dialog, which is created by the builder.
138166
* <p>

library/src/main/java/de/mrapp/android/dialog/decorator/ListDialogDecorator.java

+33-3
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,16 @@ public class ListDialogDecorator extends AbstractDialogDecorator<ButtonBarDialog
144144
private DialogInterface.OnMultiChoiceClickListener multiChoiceListener;
145145

146146
/**
147-
* The listener, which is notified, when a list item of the dialog becomes selected,
148-
* irrespective of the list view's choice mode.
147+
* The listener, which is notified, when a list item of the dialog becomes selected or
148+
* unselected, irrespective of the list view's choice mode.
149149
*/
150150
private ListDialog.OnItemSelectedListener listViewItemSelectedListener;
151151

152+
/**
153+
* The listener, which is notified, when a list item of the dialog becomes enabled or disabled.
154+
*/
155+
private ListDialog.OnItemEnabledListener listViewItemEnabledListener;
156+
152157
/**
153158
* The dialog's items.
154159
*/
@@ -200,6 +205,7 @@ private void attachAdapter() {
200205
listView.setAdapter(adapter);
201206
listView.setVisibility(adapter != null ? View.VISIBLE : View.GONE);
202207
adapter.setOnItemSelectedListener(listViewItemSelectedListener);
208+
adapter.setOnItemEnabledListener(listViewItemEnabledListener);
203209
initializeSelectionListener();
204210
adaptItemColor();
205211
adaptItemTypeface();
@@ -368,6 +374,20 @@ public final void setItemChecked(final int position, final boolean checked) {
368374
adapter.setItemChecked(position, checked);
369375
}
370376

377+
@Override
378+
public final boolean isItemEnabled(final int position) {
379+
Condition.INSTANCE.ensureNotNull(adapter, "No list items are shown by the dialog",
380+
IndexOutOfBoundsException.class);
381+
return adapter.isItemEnabled(position);
382+
}
383+
384+
@Override
385+
public final void setItemEnabled(final int position, final boolean enabled) {
386+
Condition.INSTANCE.ensureNotNull(adapter, "No list items are shown by the dialog",
387+
IndexOutOfBoundsException.class);
388+
adapter.setItemEnabled(position, enabled);
389+
}
390+
371391
@Override
372392
public final void setItems(@Nullable final CharSequence[] items,
373393
@Nullable final DialogInterface.OnClickListener listener) {
@@ -490,7 +510,7 @@ public final <VH extends RecyclerView.ViewHolder> void setMultiChoiceItems(
490510
@Nullable final boolean[] checkedItems,
491511
@Nullable final DialogInterface.OnMultiChoiceClickListener listener) {
492512
Condition.INSTANCE.ensureTrue(checkedItems == null || adapter == null ||
493-
adapter.getItemCount() == checkedItems.length,
513+
adapter.getItemCount() == checkedItems.length,
494514
"Invalid number of checked items given");
495515
this.items = null;
496516
this.singleChoiceItems = null;
@@ -517,6 +537,16 @@ public final void setOnItemSelectedListener(
517537
}
518538
}
519539

540+
@Override
541+
public final void setOnItemEnabledListener(
542+
@Nullable final ListDialog.OnItemEnabledListener listener) {
543+
listViewItemEnabledListener = listener;
544+
545+
if (adapter != null) {
546+
adapter.setOnItemEnabledListener(listViewItemEnabledListener);
547+
}
548+
}
549+
520550
@Override
521551
public final void onSaveInstanceState(@NonNull final Bundle outState) {
522552
outState.putParcelable(ITEM_COLOR_EXTRA, getItemColor());

0 commit comments

Comments
 (0)