From c1f0dae683e01f674c654040187ffa24135b5ca2 Mon Sep 17 00:00:00 2001 From: Dharanish Date: Sat, 6 Jul 2024 09:00:25 +0200 Subject: [PATCH] Implement habit group score ring, sorting sub habits (except with score) --- .../habits/list/views/HabitCardView.kt | 1 + .../core/commands/DeleteHabitsCommand.kt | 9 ++- .../commands/RefreshParentGroupCommand.kt | 34 +++++++++++ .../org/isoron/uhabits/core/models/Habit.kt | 4 -- .../screens/habits/list/HabitCardListCache.kt | 57 ++++++++++--------- .../screens/habits/list/ListHabitsBehavior.kt | 9 +++ .../list/ListHabitsSelectionMenuBehavior.kt | 2 +- 7 files changed, 83 insertions(+), 33 deletions(-) create mode 100644 uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/RefreshParentGroupCommand.kt diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt index e047549b9..c973c19be 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt @@ -97,6 +97,7 @@ class HabitCardView( set(value) { scoreRing.setPercentage(value.toFloat()) scoreRing.setPrecision(1.0f / 16) + behavior.onChangeScore(habit!!) } var unit diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/DeleteHabitsCommand.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/DeleteHabitsCommand.kt index e61ba1626..fbbfafcd4 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/DeleteHabitsCommand.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/DeleteHabitsCommand.kt @@ -26,6 +26,13 @@ data class DeleteHabitsCommand( val selected: List ) : Command { override fun run() { - for (h in selected) habitList.remove(h) + for (h in selected) { + if (!h.isSubHabit()) { + habitList.remove(h) + } else { + val list = h.parent!!.habitList + list.remove(h) + } + } } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/RefreshParentGroupCommand.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/RefreshParentGroupCommand.kt new file mode 100644 index 000000000..70322c3c0 --- /dev/null +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/RefreshParentGroupCommand.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker 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 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker 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, see . + */ +package org.isoron.uhabits.core.commands + +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.core.models.HabitGroupList + +data class RefreshParentGroupCommand( + val habit: Habit, + val habitGroupList: HabitGroupList +) : Command { + override fun run() { + if (!habit.isSubHabit()) return + val hgr = habit.parent + hgr!!.recompute() + habitGroupList.resort() + } +} diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt index 2d41d0384..25b5320bb 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt @@ -113,10 +113,6 @@ data class Habit( return computedEntries.getKnown().lastOrNull()?.timestamp ?: DateUtils.getTodayWithOffset() } - fun isInGroup(): Boolean { - return (parentID != null) - } - fun copyFrom(other: Habit) { this.color = other.color this.description = other.description diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.kt index 0bab9a99c..be2612b0c 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.kt @@ -214,49 +214,46 @@ class HabitCardListCache @Inject constructor( @Synchronized fun remove(uuid: String) { - val type = data.positionTypes[data.uuidToPosition[uuid]!!] + val position = data.uuidToPosition[uuid] ?: return + val type = data.positionTypes[position] if (type == STANDALONE_HABIT) { val h = data.uuidToHabit[uuid] if (h != null) { - val position = data.habits.indexOf(h) - data.habits.removeAt(position) - data.checkmarks.remove(uuid) - data.notes.remove(uuid) - data.scores.remove(uuid) - data.decrementPositions(position + 1, data.positionTypes.size) - listener.onItemRemoved(position) + val pos = data.habits.indexOf(h) + data.habits.removeAt(pos) + data.removeWithUUID(uuid) + data.positionTypes.removeAt(pos) + data.decrementPositions(pos + 1, data.positionTypes.size) + listener.onItemRemoved(pos) } } else if (type == SUB_HABIT) { val h = data.uuidToHabit[uuid] if (h != null) { - val position = data.uuidToPosition[uuid]!! + val pos = data.uuidToPosition[uuid]!! val hgrUUID = h.parentUUID val hgr = data.uuidToHabitGroup[hgrUUID] val hgrIdx = data.habitGroups.indexOf(hgr) data.subHabits[hgrIdx].remove(h) - data.checkmarks.remove(uuid) - data.notes.remove(uuid) - data.scores.remove(uuid) - data.decrementPositions(position + 1, data.positionTypes.size) - listener.onItemRemoved(position) + data.removeWithUUID(uuid) + data.positionTypes.removeAt(pos) + data.decrementPositions(pos + 1, data.positionTypes.size) + listener.onItemRemoved(pos) } } else if (type == HABIT_GROUP) { val hgr = data.uuidToHabitGroup[uuid] if (hgr != null) { - val position = data.uuidToPosition[uuid]!! + val pos = data.uuidToPosition[uuid]!! val hgrIdx = data.habitGroups.indexOf(hgr) for (habit in data.subHabits[hgrIdx].reversed()) { - data.checkmarks.remove(habit.uuid) - data.notes.remove(habit.uuid) - data.scores.remove(habit.uuid) + data.removeWithUUID(habit.uuid) listener.onItemRemoved(data.uuidToPosition[habit.uuid]!!) } data.subHabits.removeAt(hgrIdx) data.habitGroups.removeAt(hgrIdx) - data.scores.remove(hgr.uuid) + data.removeWithUUID(hgr.uuid) data.rebuildPositions() - listener.onItemRemoved(position) + listener.onItemRemoved(pos) } } } @@ -466,7 +463,6 @@ class HabitCardListCache @Inject constructor( @Synchronized fun decrementPositions(fromPosition: Int, toPosition: Int) { - positionTypes.removeAt(fromPosition) for (pos in positionToHabit.keys.sortedBy { it }) { if (pos in fromPosition..toPosition) { positionToHabit[pos - 1] = positionToHabit[pos]!! @@ -508,10 +504,11 @@ class HabitCardListCache @Inject constructor( if (type == STANDALONE_HABIT) { habits.removeAt(fromPosition) + positionTypes.removeAt(fromPosition) if (fromPosition < checkedToPosition) { decrementPositions(fromPosition + 1, checkedToPosition) } else { - incrementPositions(toPosition, fromPosition - 1) + incrementPositions(checkedToPosition, fromPosition - 1) } habits.add(checkedToPosition, habit) positionTypes.add(checkedToPosition, STANDALONE_HABIT) @@ -520,10 +517,11 @@ class HabitCardListCache @Inject constructor( val hgrIdx = habitGroups.indexOf(hgr) val h = positionToHabit[fromPosition]!! subHabits[hgrIdx].remove(h) + positionTypes.removeAt(fromPosition) if (fromPosition < checkedToPosition) { decrementPositions(fromPosition + 1, checkedToPosition) } else { - incrementPositions(toPosition, fromPosition - 1) + incrementPositions(checkedToPosition, fromPosition - 1) } subHabits[hgrIdx].add(checkedToPosition - uuidToPosition[hgr!!.uuid]!! - 1, habit) positionTypes.add(checkedToPosition, SUB_HABIT) @@ -556,6 +554,15 @@ class HabitCardListCache @Inject constructor( listener.onItemMoved(fromPosition, toPosition) } + fun removeWithUUID(uuid: String?) { + uuidToPosition.remove(uuid) + uuidToHabit.remove(uuid) + uuidToHabitGroup.remove(uuid) + scores.remove(uuid) + notes.remove(uuid) + checkmarks.remove(uuid) + } + /** * Creates a new CacheData without any content. */ @@ -654,10 +661,6 @@ class HabitCardListCache @Inject constructor( data.habits.add(position, habit) data.positionTypes.add(position, STANDALONE_HABIT) } else { -// val parent = data.uuidToHabitGroup[habit.parentUUID] -// val parentIdx = data.habitGroups.indexOf(parent) -// val parentPosition = data.uuidToPosition[habit.parentUUID]!! -// data.subHabits[parentIdx].add(position - parentPosition - 1, habit) data.positionTypes.add(position, SUB_HABIT) } data.incrementPositions(position, data.positionTypes.size - 1) diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt index 73ac30d23..4e35841e9 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt @@ -20,9 +20,11 @@ package org.isoron.uhabits.core.ui.screens.habits.list import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.commands.CreateRepetitionCommand +import org.isoron.uhabits.core.commands.RefreshParentGroupCommand import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.HabitGroup +import org.isoron.uhabits.core.models.HabitGroupList import org.isoron.uhabits.core.models.HabitList import org.isoron.uhabits.core.models.HabitType import org.isoron.uhabits.core.models.NumericalHabitType.AT_LEAST @@ -41,6 +43,7 @@ import kotlin.math.roundToInt open class ListHabitsBehavior @Inject constructor( private val habitList: HabitList, + private val habitGroupList: HabitGroupList, private val dirFinder: DirFinder, private val taskRunner: TaskRunner, private val screen: Screen, @@ -141,6 +144,12 @@ open class ListHabitsBehavior @Inject constructor( if (value == YES_MANUAL) screen.showConfetti(habit.color, x, y) } + fun onChangeScore(habit: Habit) { + commandRunner.run( + RefreshParentGroupCommand(habit, habitGroupList) + ) + } + enum class Message { COULD_NOT_EXPORT, IMPORT_SUCCESSFUL, diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehavior.kt index 231fa4c45..1608b757f 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehavior.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehavior.kt @@ -95,8 +95,8 @@ class ListHabitsSelectionMenuBehavior @Inject constructor( { adapter.performRemove(adapter.getSelectedHabits()) adapter.performRemoveHabitGroup(adapter.getSelectedHabitGroups()) - commandRunner.run(DeleteHabitsCommand(habitList, adapter.getSelectedHabits())) commandRunner.run(DeleteHabitGroupsCommand(habitGroupList, adapter.getSelectedHabitGroups())) + commandRunner.run(DeleteHabitsCommand(habitList, adapter.getSelectedHabits())) adapter.clearSelection() }, adapter.getSelectedHabits().size + adapter.getSelectedHabitGroups().size