diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/AddButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/AddButtonView.kt
index fb7885fea..0034d2b94 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/AddButtonView.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/AddButtonView.kt
@@ -47,7 +47,7 @@ class AddButtonView(
private inner class Drawer {
private val rect = RectF()
- private val highContrastColor = sres.getColor(R.attr.contrast100)
+ private val highContrastColor = sres.getColor(R.attr.contrast80)
private val paint = TextPaint().apply {
typeface = getFontAwesome()
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CollapseButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CollapseButtonView.kt
new file mode 100644
index 000000000..12c54cf55
--- /dev/null
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CollapseButtonView.kt
@@ -0,0 +1,101 @@
+package org.isoron.uhabits.activities.habits.list.views
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.RectF
+import android.text.TextPaint
+import android.view.View
+import org.isoron.uhabits.R
+import org.isoron.uhabits.activities.habits.list.ListHabitsActivity
+import org.isoron.uhabits.core.models.HabitGroup
+import org.isoron.uhabits.core.models.ModelObservable
+import org.isoron.uhabits.utils.getFontAwesome
+import org.isoron.uhabits.utils.sp
+import org.isoron.uhabits.utils.sres
+import org.isoron.uhabits.utils.toMeasureSpec
+
+class CollapseButtonView(
+ context: Context,
+ var habitGroup: HabitGroup?
+) : View(context),
+ View.OnClickListener,
+ ModelObservable.Listener {
+
+ private var drawer = Drawer()
+
+ var collapsed = false
+
+ init {
+ setOnClickListener(this)
+ }
+
+ override fun onClick(v: View) {
+ collapsed = !collapsed
+ habitGroup!!.collapsed = collapsed
+ drawer.rotate()
+ invalidate()
+ (context as ListHabitsActivity).component.listHabitsMenu.behavior.onPreferencesChanged()
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ drawer.draw(canvas)
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ val height = resources.getDimensionPixelSize(R.dimen.checkmarkHeight)
+ val width = resources.getDimensionPixelSize(R.dimen.checkmarkWidth)
+ super.onMeasure(
+ width.toMeasureSpec(MeasureSpec.EXACTLY),
+ height.toMeasureSpec(MeasureSpec.EXACTLY)
+ )
+ }
+
+ private inner class Drawer {
+ private val rect = RectF()
+ private val highContrastColor = sres.getColor(R.attr.contrast100)
+
+ private var rotationAngle = 0f
+ private var offset_y = 0.4f
+ private var offset_x = 0f
+ private val paint = TextPaint().apply {
+ typeface = getFontAwesome()
+ isAntiAlias = true
+ textAlign = Paint.Align.CENTER
+ }
+
+ fun rotate() {
+ if (rotationAngle == 0f) {
+ rotationAngle = 90f
+ offset_y = 0f
+ offset_x = -0.4f
+ } else {
+ rotationAngle = 0f
+ offset_y = 0.4f
+ offset_x = 0f
+ }
+ }
+
+ fun draw(canvas: Canvas) {
+ paint.color = highContrastColor
+ val id = R.string.fa_angle_down
+ paint.textSize = sp(12.0f)
+ paint.strokeWidth = 0f
+ paint.style = Paint.Style.FILL
+
+ val label = resources.getString(id)
+ val em = paint.measureText("m")
+
+ rect.set(0f, 0f, width.toFloat(), height.toFloat())
+ rect.offset(offset_x * em, offset_y * em)
+
+ canvas.save() // Save the current state of the canvas
+ canvas.rotate(rotationAngle, rect.centerX(), rect.centerY()) // Rotate the canvas
+ canvas.drawText(label, rect.centerX(), rect.centerY(), paint)
+ canvas.restore()
+ }
+ }
+
+ override fun onModelChange() {}
+}
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitGroupCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitGroupCardView.kt
index 4bbffa7e2..bcac0dafa 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitGroupCardView.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitGroupCardView.kt
@@ -42,6 +42,7 @@ class HabitGroupCardView(
field = newHabitGroup
if (newHabitGroup != null) copyAttributesFrom(newHabitGroup)
addButtonView.habitGroup = newHabitGroup
+ collapseButtonView.habitGroup = newHabitGroup
}
var score
@@ -52,6 +53,7 @@ class HabitGroupCardView(
}
var addButtonView: AddButtonView
+ var collapseButtonView: CollapseButtonView
private var innerFrame: LinearLayout
private var label: TextView
private var scoreRing: RingView
@@ -81,6 +83,7 @@ class HabitGroupCardView(
}
addButtonView = AddButtonView(context, habitGroup)
+ collapseButtonView = CollapseButtonView(context, habitGroup)
innerFrame = LinearLayout(context).apply {
gravity = Gravity.CENTER_VERTICAL
@@ -91,6 +94,7 @@ class HabitGroupCardView(
addView(scoreRing)
addView(label)
addView(addButtonView)
+ addView(collapseButtonView)
setOnTouchListener { v, event ->
v.background.setHotspot(event.x, event.y)
@@ -142,6 +146,12 @@ class HabitGroupCardView(
scoreRing.apply {
setColor(c)
}
+
+ if (collapseButtonView.collapsed) {
+ addButtonView.visibility = GONE
+ } else {
+ addButtonView.visibility = VISIBLE
+ }
}
private fun updateBackground(isSelected: Boolean) {
diff --git a/uhabits-android/src/main/res/values/fontawesome.xml b/uhabits-android/src/main/res/values/fontawesome.xml
index 53e20cc46..6586f31c9 100644
--- a/uhabits-android/src/main/res/values/fontawesome.xml
+++ b/uhabits-android/src/main/res/values/fontawesome.xml
@@ -25,6 +25,8 @@
+
+
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 8a0c1a17c..332466625 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
@@ -56,6 +56,8 @@ data class Habit(
val uriString: String
get() = "content://org.isoron.uhabits/habit/$id"
+ var collapsed = false
+
fun isSubHabit(): Boolean = groupUUID != null
fun hasReminder(): Boolean = reminder != null
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/HabitGroup.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/HabitGroup.kt
index d08ea3e3a..be2ef7365 100644
--- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/HabitGroup.kt
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/HabitGroup.kt
@@ -45,6 +45,14 @@ data class HabitGroup(
val uriString: String
get() = "content://org.isoron.uhabits/habitgroup/$id"
+ var collapsed = false
+ set(value) {
+ if (value != field) {
+ field = value
+ habitList.forEach { it.collapsed = value }
+ }
+ }
+
fun hasReminder(): Boolean = reminder != null
fun isCompletedToday(): Boolean {
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/HabitMatcher.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/HabitMatcher.kt
index fbfedb3e0..4ef35087d 100644
--- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/HabitMatcher.kt
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/HabitMatcher.kt
@@ -29,6 +29,7 @@ data class HabitMatcher(
if (isReminderRequired && !habit.hasReminder()) return false
if (!isCompletedAllowed && habit.isCompletedToday()) return false
if (!isEnteredAllowed && habit.isEnteredToday()) return false
+ if (habit.collapsed) return false
return true
}
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/memory/MemoryHabitGroupList.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/memory/MemoryHabitGroupList.kt
index b9aa7a71e..4fef8519c 100644
--- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/memory/MemoryHabitGroupList.kt
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/memory/MemoryHabitGroupList.kt
@@ -47,6 +47,7 @@ class MemoryHabitGroupList : HabitGroupList {
parent.observable.addListener { loadFromParent() }
for (hgr in parent.list) {
hgr.habitList.observable.addListener { loadFromParent() }
+ hgr.observable.notifyListeners()
}
loadFromParent()
}