HabitCardListAdapter: Return copy of list of selected items

Previously, HabitCardListAdapter returned a pointer to the list, instead of a
copy. By the time other parts of the application were reading the list, its
contents had already changed. This prevented the user from deleting or
archiving habits.
pull/760/head
Alinson S. Xavier 5 years ago
parent 89bde4c9ae
commit 48c1adb3bb

@ -53,7 +53,7 @@ class HabitCardListAdapter @Inject constructor(
ListHabitsSelectionMenuBehavior.Adapter { ListHabitsSelectionMenuBehavior.Adapter {
val observable: ModelObservable = ModelObservable() val observable: ModelObservable = ModelObservable()
private var listView: HabitCardListView? = null private var listView: HabitCardListView? = null
override val selected: LinkedList<Habit> = LinkedList() val selected: LinkedList<Habit> = LinkedList()
override fun atMidnight() { override fun atMidnight() {
cache.refreshAllHabits() cache.refreshAllHabits()
} }
@ -71,6 +71,10 @@ class HabitCardListAdapter @Inject constructor(
observable.notifyListeners() observable.notifyListeners()
} }
override fun getSelected(): List<Habit> {
return ArrayList(selected)
}
/** /**
* Returns the item that occupies a certain position on the list * Returns the item that occupies a certain position on the list
* *

@ -37,28 +37,28 @@ class ListHabitsSelectionMenuBehavior @Inject constructor(
var commandRunner: CommandRunner var commandRunner: CommandRunner
) { ) {
fun canArchive(): Boolean { fun canArchive(): Boolean {
for (habit in adapter.selected) if (habit.isArchived) return false for (habit in adapter.getSelected()) if (habit.isArchived) return false
return true return true
} }
fun canEdit(): Boolean { fun canEdit(): Boolean {
return adapter.selected.size == 1 return adapter.getSelected().size == 1
} }
fun canUnarchive(): Boolean { fun canUnarchive(): Boolean {
for (habit in adapter.selected) if (!habit.isArchived) return false for (habit in adapter.getSelected()) if (!habit.isArchived) return false
return true return true
} }
fun onArchiveHabits() { fun onArchiveHabits() {
commandRunner.run(ArchiveHabitsCommand(habitList, adapter.selected)) commandRunner.run(ArchiveHabitsCommand(habitList, adapter.getSelected()))
adapter.clearSelection() adapter.clearSelection()
} }
fun onChangeColor() { fun onChangeColor() {
val (color) = adapter.selected[0] val (color) = adapter.getSelected()[0]
screen.showColorPicker(color) { selectedColor: PaletteColor -> screen.showColorPicker(color) { selectedColor: PaletteColor ->
commandRunner.run(ChangeHabitColorCommand(habitList, adapter.selected, selectedColor)) commandRunner.run(ChangeHabitColorCommand(habitList, adapter.getSelected(), selectedColor))
adapter.clearSelection() adapter.clearSelection()
} }
} }
@ -66,27 +66,27 @@ class ListHabitsSelectionMenuBehavior @Inject constructor(
fun onDeleteHabits() { fun onDeleteHabits() {
screen.showDeleteConfirmationScreen( screen.showDeleteConfirmationScreen(
{ {
adapter.performRemove(adapter.selected) adapter.performRemove(adapter.getSelected())
commandRunner.run(DeleteHabitsCommand(habitList, adapter.selected)) commandRunner.run(DeleteHabitsCommand(habitList, adapter.getSelected()))
adapter.clearSelection() adapter.clearSelection()
}, },
adapter.selected.size adapter.getSelected().size
) )
} }
fun onEditHabits() { fun onEditHabits() {
screen.showEditHabitsScreen(adapter.selected) screen.showEditHabitsScreen(adapter.getSelected())
adapter.clearSelection() adapter.clearSelection()
} }
fun onUnarchiveHabits() { fun onUnarchiveHabits() {
commandRunner.run(UnarchiveHabitsCommand(habitList, adapter.selected)) commandRunner.run(UnarchiveHabitsCommand(habitList, adapter.getSelected()))
adapter.clearSelection() adapter.clearSelection()
} }
interface Adapter { interface Adapter {
fun clearSelection() fun clearSelection()
val selected: List<Habit> fun getSelected(): List<Habit>
fun performRemove(selected: List<Habit>) fun performRemove(selected: List<Habit>)
} }

@ -52,27 +52,27 @@ class ListHabitsSelectionMenuBehaviorTest : BaseUnitTest() {
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun canArchive() { fun canArchive() {
whenever(adapter.selected).thenReturn(listOf(habit1, habit2)) whenever(adapter.getSelected()).thenReturn(listOf(habit1, habit2))
assertFalse(behavior.canArchive()) assertFalse(behavior.canArchive())
whenever(adapter.selected).thenReturn(listOf(habit2, habit3)) whenever(adapter.getSelected()).thenReturn(listOf(habit2, habit3))
assertTrue(behavior.canArchive()) assertTrue(behavior.canArchive())
} }
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun canEdit() { fun canEdit() {
whenever(adapter.selected).thenReturn(listOf(habit1)) whenever(adapter.getSelected()).thenReturn(listOf(habit1))
assertTrue(behavior.canEdit()) assertTrue(behavior.canEdit())
whenever(adapter.selected).thenReturn(listOf(habit1, habit2)) whenever(adapter.getSelected()).thenReturn(listOf(habit1, habit2))
assertFalse(behavior.canEdit()) assertFalse(behavior.canEdit())
} }
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun canUnarchive() { fun canUnarchive() {
whenever(adapter.selected).thenReturn(listOf(habit1, habit2)) whenever(adapter.getSelected()).thenReturn(listOf(habit1, habit2))
assertFalse(behavior.canUnarchive()) assertFalse(behavior.canUnarchive())
whenever(adapter.selected).thenReturn(listOf(habit1)) whenever(adapter.getSelected()).thenReturn(listOf(habit1))
assertTrue(behavior.canUnarchive()) assertTrue(behavior.canUnarchive())
} }
@ -80,7 +80,7 @@ class ListHabitsSelectionMenuBehaviorTest : BaseUnitTest() {
@Throws(Exception::class) @Throws(Exception::class)
fun onArchiveHabits() { fun onArchiveHabits() {
assertFalse(habit2.isArchived) assertFalse(habit2.isArchived)
whenever(adapter.selected).thenReturn(listOf(habit2)) whenever(adapter.getSelected()).thenReturn(listOf(habit2))
behavior.onArchiveHabits() behavior.onArchiveHabits()
assertTrue(habit2.isArchived) assertTrue(habit2.isArchived)
} }
@ -90,7 +90,7 @@ class ListHabitsSelectionMenuBehaviorTest : BaseUnitTest() {
fun onChangeColor() { fun onChangeColor() {
assertThat(habit1.color, equalTo(PaletteColor(8))) assertThat(habit1.color, equalTo(PaletteColor(8)))
assertThat(habit2.color, equalTo(PaletteColor(8))) assertThat(habit2.color, equalTo(PaletteColor(8)))
whenever(adapter.selected).thenReturn(listOf(habit1, habit2)) whenever(adapter.getSelected()).thenReturn(listOf(habit1, habit2))
behavior.onChangeColor() behavior.onChangeColor()
verify(screen) verify(screen)
.showColorPicker(eq(PaletteColor(8)), colorPickerCallback.capture()) .showColorPicker(eq(PaletteColor(8)), colorPickerCallback.capture())
@ -103,7 +103,7 @@ class ListHabitsSelectionMenuBehaviorTest : BaseUnitTest() {
fun onDeleteHabits() { fun onDeleteHabits() {
val id = habit1.id!! val id = habit1.id!!
habitList.getById(id)!! habitList.getById(id)!!
whenever(adapter.selected).thenReturn(listOf(habit1)) whenever(adapter.getSelected()).thenReturn(listOf(habit1))
behavior.onDeleteHabits() behavior.onDeleteHabits()
verify(screen).showDeleteConfirmationScreen(deleteCallback.capture(), eq(1)) verify(screen).showDeleteConfirmationScreen(deleteCallback.capture(), eq(1))
deleteCallback.lastValue.onConfirmed() deleteCallback.lastValue.onConfirmed()
@ -114,7 +114,7 @@ class ListHabitsSelectionMenuBehaviorTest : BaseUnitTest() {
@Throws(Exception::class) @Throws(Exception::class)
fun onEditHabits() { fun onEditHabits() {
val selected: List<Habit> = listOf(habit1, habit2) val selected: List<Habit> = listOf(habit1, habit2)
whenever(adapter.selected).thenReturn(selected) whenever(adapter.getSelected()).thenReturn(selected)
behavior.onEditHabits() behavior.onEditHabits()
verify(screen).showEditHabitsScreen(selected) verify(screen).showEditHabitsScreen(selected)
} }
@ -123,7 +123,7 @@ class ListHabitsSelectionMenuBehaviorTest : BaseUnitTest() {
@Throws(Exception::class) @Throws(Exception::class)
fun onUnarchiveHabits() { fun onUnarchiveHabits() {
assertTrue(habit1.isArchived) assertTrue(habit1.isArchived)
whenever(adapter.selected).thenReturn(listOf(habit1)) whenever(adapter.getSelected()).thenReturn(listOf(habit1))
behavior.onUnarchiveHabits() behavior.onUnarchiveHabits()
assertFalse(habit1.isArchived) assertFalse(habit1.isArchived)
} }

Loading…
Cancel
Save