mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
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.
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user