mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-15 05:28:51 -06:00
Can create habit groups now
This commit is contained in:
@@ -42,6 +42,14 @@
|
|||||||
android:value=".activities.habits.list.ListHabitsActivity" />
|
android:value=".activities.habits.list.ListHabitsActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".activities.habits.edit.EditHabitGroupActivity"
|
||||||
|
android:exported="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value=".activities.habits.list.ListHabitsActivity" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.backup.api_key"
|
android:name="com.google.android.backup.api_key"
|
||||||
android:value="AEdPqrEAAAAI6aeWncbnMNo8E5GWeZ44dlc5cQ7tCROwFhOtiw" />
|
android:value="AEdPqrEAAAAI6aeWncbnMNo8E5GWeZ44dlc5cQ7tCROwFhOtiw" />
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import javax.inject.Inject
|
|||||||
* Provides data that backs a [HabitCardListView].
|
* Provides data that backs a [HabitCardListView].
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* The data if fetched and cached by a [HabitCardListCache]. This adapter
|
* The data is fetched and cached by a [HabitCardListCache]. This adapter
|
||||||
* also holds a list of items that have been selected.
|
* also holds a list of items that have been selected.
|
||||||
*/
|
*/
|
||||||
@ActivityScope
|
@ActivityScope
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package org.isoron.uhabits.activities.habits.list.views
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.text.LineBreaker.BREAK_STRATEGY_BALANCED
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Build.VERSION.SDK_INT
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import org.isoron.platform.gui.toInt
|
||||||
|
import org.isoron.uhabits.R
|
||||||
|
import org.isoron.uhabits.activities.common.views.RingView
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroup
|
||||||
|
import org.isoron.uhabits.core.models.ModelObservable
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
|
||||||
|
import org.isoron.uhabits.inject.ActivityContext
|
||||||
|
import org.isoron.uhabits.utils.currentTheme
|
||||||
|
import org.isoron.uhabits.utils.dp
|
||||||
|
import org.isoron.uhabits.utils.sres
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class HabitGroupCardViewFactory
|
||||||
|
@Inject constructor(
|
||||||
|
@ActivityContext val context: Context,
|
||||||
|
private val behavior: ListHabitsBehavior
|
||||||
|
) {
|
||||||
|
fun create() = HabitGroupCardView(context, behavior)
|
||||||
|
}
|
||||||
|
|
||||||
|
class HabitGroupCardView(
|
||||||
|
@ActivityContext context: Context,
|
||||||
|
private val behavior: ListHabitsBehavior
|
||||||
|
) : FrameLayout(context),
|
||||||
|
ModelObservable.Listener {
|
||||||
|
|
||||||
|
var habitGroup: HabitGroup? = null
|
||||||
|
set(newHabitGroup) {
|
||||||
|
if (isAttachedToWindow) {
|
||||||
|
field?.observable?.removeListener(this)
|
||||||
|
newHabitGroup?.observable?.addListener(this)
|
||||||
|
}
|
||||||
|
field = newHabitGroup
|
||||||
|
if (newHabitGroup != null) copyAttributesFrom(newHabitGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
var score
|
||||||
|
get() = scoreRing.getPercentage().toDouble()
|
||||||
|
set(value) {
|
||||||
|
scoreRing.setPercentage(value.toFloat())
|
||||||
|
scoreRing.setPrecision(1.0f / 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var innerFrame: LinearLayout
|
||||||
|
private var label: TextView
|
||||||
|
private var scoreRing: RingView
|
||||||
|
|
||||||
|
private var currentToggleTaskId = 0
|
||||||
|
|
||||||
|
init {
|
||||||
|
scoreRing = RingView(context).apply {
|
||||||
|
val thickness = dp(3f)
|
||||||
|
val margin = dp(8f).toInt()
|
||||||
|
val ringSize = dp(15f).toInt()
|
||||||
|
layoutParams = LinearLayout.LayoutParams(ringSize, ringSize).apply {
|
||||||
|
setMargins(margin, 0, margin, 0)
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
}
|
||||||
|
setThickness(thickness)
|
||||||
|
}
|
||||||
|
|
||||||
|
label = TextView(context).apply {
|
||||||
|
maxLines = 2
|
||||||
|
ellipsize = TextUtils.TruncateAt.END
|
||||||
|
layoutParams = LinearLayout.LayoutParams(0, WRAP_CONTENT, 1f)
|
||||||
|
if (SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
breakStrategy = BREAK_STRATEGY_BALANCED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
innerFrame = LinearLayout(context).apply {
|
||||||
|
gravity = Gravity.CENTER_VERTICAL
|
||||||
|
orientation = LinearLayout.HORIZONTAL
|
||||||
|
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
|
||||||
|
elevation = dp(1f)
|
||||||
|
|
||||||
|
addView(scoreRing)
|
||||||
|
addView(label)
|
||||||
|
|
||||||
|
setOnTouchListener { v, event ->
|
||||||
|
v.background.setHotspot(event.x, event.y)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clipToPadding = false
|
||||||
|
layoutParams = LayoutParams(MATCH_PARENT, WRAP_CONTENT)
|
||||||
|
val margin = dp(3f).toInt()
|
||||||
|
setPadding(margin, 0, margin, margin)
|
||||||
|
addView(innerFrame)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onModelChange() {
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
habitGroup?.let { copyAttributesFrom(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setSelected(isSelected: Boolean) {
|
||||||
|
super.setSelected(isSelected)
|
||||||
|
updateBackground(isSelected)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow()
|
||||||
|
habitGroup?.observable?.addListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
habitGroup?.observable?.removeListener(this)
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun copyAttributesFrom(hgr: HabitGroup) {
|
||||||
|
fun getActiveColor(hgr: HabitGroup): Int {
|
||||||
|
return when (hgr.isArchived) {
|
||||||
|
true -> sres.getColor(R.attr.contrast60)
|
||||||
|
false -> currentTheme().color(hgr.color).toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val c = getActiveColor(hgr)
|
||||||
|
label.apply {
|
||||||
|
text = hgr.name
|
||||||
|
setTextColor(c)
|
||||||
|
}
|
||||||
|
scoreRing.apply {
|
||||||
|
setColor(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateBackground(isSelected: Boolean) {
|
||||||
|
val background = when (isSelected) {
|
||||||
|
true -> R.drawable.selected_box
|
||||||
|
false -> R.drawable.ripple
|
||||||
|
}
|
||||||
|
innerFrame.setBackgroundResource(background)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun (() -> Unit).delay(delayInMillis: Long) {
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed(this, delayInMillis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.isoron.uhabits.activities.habits.list.views
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
||||||
|
class HabitGroupCardViewHolder(itemView: HabitGroupCardView) : RecyclerView.ViewHolder(itemView)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.isoron.uhabits.core.commands
|
||||||
|
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroup
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroupList
|
||||||
|
|
||||||
|
data class ArchiveHabitGroupsCommand(
|
||||||
|
val habitGroupList: HabitGroupList,
|
||||||
|
val selected: List<HabitGroup>
|
||||||
|
) : Command {
|
||||||
|
override fun run() {
|
||||||
|
for (hgr in selected) {
|
||||||
|
hgr.isArchived = true
|
||||||
|
for (h in hgr.habitList) {
|
||||||
|
h.isArchived = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
habitGroupList.update(selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.isoron.uhabits.core.commands
|
||||||
|
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroup
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroupList
|
||||||
|
import org.isoron.uhabits.core.models.PaletteColor
|
||||||
|
|
||||||
|
data class ChangeHabitGroupColorCommand(
|
||||||
|
val habitGroupList: HabitGroupList,
|
||||||
|
val selected: List<HabitGroup>,
|
||||||
|
val newColor: PaletteColor
|
||||||
|
) : Command {
|
||||||
|
override fun run() {
|
||||||
|
for (hgr in selected) hgr.color = newColor
|
||||||
|
habitGroupList.update(selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package org.isoron.uhabits.core.commands
|
||||||
|
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroup
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroupList
|
||||||
|
|
||||||
|
data class DeleteHabitGroupsCommand(
|
||||||
|
val habitGroupList: HabitGroupList,
|
||||||
|
val selected: List<HabitGroup>
|
||||||
|
) : Command {
|
||||||
|
override fun run() {
|
||||||
|
for (hgr in selected) habitGroupList.remove(hgr)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.isoron.uhabits.core.commands
|
||||||
|
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroup
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroupList
|
||||||
|
|
||||||
|
data class UnarchiveHabitGroupsCommand(
|
||||||
|
val habitGroupList: HabitGroupList,
|
||||||
|
val selected: List<HabitGroup>
|
||||||
|
) : Command {
|
||||||
|
override fun run() {
|
||||||
|
for (hgr in selected) {
|
||||||
|
hgr.isArchived = false
|
||||||
|
for (h in hgr.habitList) {
|
||||||
|
h.isArchived = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
habitGroupList.update(selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -111,12 +111,8 @@ data class Habit(
|
|||||||
return computedEntries.getKnown().lastOrNull()?.timestamp ?: DateUtils.getTodayWithOffset()
|
return computedEntries.getKnown().lastOrNull()?.timestamp ?: DateUtils.getTodayWithOffset()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hierarchyLevel(): Int {
|
fun isInGroup(): Boolean {
|
||||||
return if (parentID == null) {
|
return (parentID != null)
|
||||||
0
|
|
||||||
} else {
|
|
||||||
1 + parent!!.hierarchyLevel()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copyFrom(other: Habit) {
|
fun copyFrom(other: Habit) {
|
||||||
|
|||||||
@@ -15,15 +15,12 @@ data class HabitGroup(
|
|||||||
var uuid: String? = null,
|
var uuid: String? = null,
|
||||||
var habitList: HabitList,
|
var habitList: HabitList,
|
||||||
val scores: ScoreList,
|
val scores: ScoreList,
|
||||||
val streaks: StreakList,
|
val streaks: StreakList
|
||||||
var parentID: Long? = null,
|
|
||||||
var parentUUID: String? = null
|
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
if (uuid == null) this.uuid = UUID.randomUUID().toString().replace("-", "")
|
if (uuid == null) this.uuid = UUID.randomUUID().toString().replace("-", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
var parent: HabitGroup? = null
|
|
||||||
var observable = ModelObservable()
|
var observable = ModelObservable()
|
||||||
|
|
||||||
val uriString: String
|
val uriString: String
|
||||||
@@ -80,8 +77,6 @@ data class HabitGroup(
|
|||||||
this.question = other.question
|
this.question = other.question
|
||||||
this.reminder = other.reminder
|
this.reminder = other.reminder
|
||||||
this.uuid = other.uuid
|
this.uuid = other.uuid
|
||||||
this.parentID = other.parentID
|
|
||||||
this.parentUUID = other.parentUUID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
@@ -97,8 +92,6 @@ data class HabitGroup(
|
|||||||
if (question != other.question) return false
|
if (question != other.question) return false
|
||||||
if (reminder != other.reminder) return false
|
if (reminder != other.reminder) return false
|
||||||
if (uuid != other.uuid) return false
|
if (uuid != other.uuid) return false
|
||||||
if (parentID != other.parentID) return false
|
|
||||||
if (parentUUID != other.parentUUID) return false
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -113,19 +106,9 @@ data class HabitGroup(
|
|||||||
result = 31 * result + question.hashCode()
|
result = 31 * result + question.hashCode()
|
||||||
result = 31 * result + (reminder?.hashCode() ?: 0)
|
result = 31 * result + (reminder?.hashCode() ?: 0)
|
||||||
result = 31 * result + (uuid?.hashCode() ?: 0)
|
result = 31 * result + (uuid?.hashCode() ?: 0)
|
||||||
result = 31 * result + (parentID?.hashCode() ?: 0)
|
|
||||||
result = 31 * result + (parentUUID?.hashCode() ?: 0)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hierarchyLevel(): Int {
|
fun getHabitByUUID(uuid: String?): Habit? =
|
||||||
return if (parentID == null) {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
1 + parent!!.hierarchyLevel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getHabitByUUIDDeep(uuid: String?): Habit? =
|
|
||||||
habitList.getByUUID(uuid)
|
habitList.getByUUID(uuid)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ abstract class HabitGroupList : Iterable<HabitGroup> {
|
|||||||
protected val filter: HabitMatcher
|
protected val filter: HabitMatcher
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new HabitList.
|
* Creates a new HabitGroupList.
|
||||||
*
|
*
|
||||||
* Depending on the implementation, this list can either be empty or be
|
* Depending on the implementation, this list can either be empty or be
|
||||||
* populated by some pre-existing habits, for example, from a certain
|
* populated by some pre-existing habitgroups, for example, from a certain
|
||||||
* database.
|
* database.
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -35,12 +35,12 @@ abstract class HabitGroupList : Iterable<HabitGroup> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a new habit in the list.
|
* Inserts a new habit group in the list.
|
||||||
*
|
*
|
||||||
* If the id of the habit is null, the list will assign it a new id, which
|
* If the id of the habit group is null, the list will assign it a new id, which
|
||||||
* is guaranteed to be unique in the scope of the list. If id is not null,
|
* is guaranteed to be unique in the scope of the list. If id is not null,
|
||||||
* the caller should make sure that the list does not already contain
|
* the caller should make sure that the list does not already contain
|
||||||
* another habit with same id, otherwise a RuntimeException will be thrown.
|
* another habit group with same id, otherwise a RuntimeException will be thrown.
|
||||||
*
|
*
|
||||||
* @param habitGroup the habit to be inserted
|
* @param habitGroup the habit to be inserted
|
||||||
* @throws IllegalArgumentException if the habit is already on the list.
|
* @throws IllegalArgumentException if the habit is already on the list.
|
||||||
@@ -49,28 +49,28 @@ abstract class HabitGroupList : Iterable<HabitGroup> {
|
|||||||
abstract fun add(habitGroup: HabitGroup)
|
abstract fun add(habitGroup: HabitGroup)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the habit with specified id.
|
* Returns the habit group with specified id.
|
||||||
*
|
*
|
||||||
* @param id the id of the habit
|
* @param id the id of the habit group
|
||||||
* @return the habit, or null if none exist
|
* @return the habit group, or null if none exist
|
||||||
*/
|
*/
|
||||||
abstract fun getById(id: Long): HabitGroup?
|
abstract fun getById(id: Long): HabitGroup?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the habit with specified UUID.
|
* Returns the habit group with specified UUID.
|
||||||
*
|
*
|
||||||
* @param uuid the UUID of the habit
|
* @param uuid the UUID of the habit group
|
||||||
* @return the habit, or null if none exist
|
* @return the habit group, or null if none exist
|
||||||
*/
|
*/
|
||||||
abstract fun getByUUID(uuid: String?): HabitGroup?
|
abstract fun getByUUID(uuid: String?): HabitGroup?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the habit with the specified UUID which is
|
* Returns the habit with the specified UUID which is
|
||||||
* present at any hierarchy within this list.
|
* present in any of the habit groups within this habit group list.
|
||||||
*/
|
*/
|
||||||
fun getHabitByUUIDDeep(uuid: String?): Habit? {
|
fun getHabitByUUID(uuid: String?): Habit? {
|
||||||
for (hgr in this) {
|
for (hgr in this) {
|
||||||
val habit = hgr.getHabitByUUIDDeep(uuid)
|
val habit = hgr.getHabitByUUID(uuid)
|
||||||
if (habit != null) {
|
if (habit != null) {
|
||||||
return habit
|
return habit
|
||||||
}
|
}
|
||||||
@@ -79,46 +79,46 @@ abstract class HabitGroupList : Iterable<HabitGroup> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the habit that occupies a certain position.
|
* Returns the habit group that occupies a certain position.
|
||||||
*
|
*
|
||||||
* @param position the position of the desired habit
|
* @param position the position of the desired habit group
|
||||||
* @return the habit at that position
|
* @return the habit group at that position
|
||||||
* @throws IndexOutOfBoundsException when the position is invalid
|
* @throws IndexOutOfBoundsException when the position is invalid
|
||||||
*/
|
*/
|
||||||
abstract fun getByPosition(position: Int): HabitGroup
|
abstract fun getByPosition(position: Int): HabitGroup
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of habits that match a given condition.
|
* Returns the list of habit groups that match a given condition.
|
||||||
*
|
*
|
||||||
* @param matcher the matcher that checks the condition
|
* @param matcher the matcher that checks the condition
|
||||||
* @return the list of matching habits
|
* @return the list of matching habit groups
|
||||||
*/
|
*/
|
||||||
abstract fun getFiltered(matcher: HabitMatcher?): HabitGroupList
|
abstract fun getFiltered(matcher: HabitMatcher?): HabitGroupList
|
||||||
abstract var primaryOrder: Order
|
abstract var primaryOrder: Order
|
||||||
abstract var secondaryOrder: Order
|
abstract var secondaryOrder: Order
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the index of the given habit in the list, or -1 if the list does
|
* Returns the index of the given habit group in the list, or -1 if the list does
|
||||||
* not contain the habit.
|
* not contain the habit group.
|
||||||
*
|
*
|
||||||
* @param h the habit
|
* @param h the habit group
|
||||||
* @return the index of the habit, or -1 if not in the list
|
* @return the index of the habit group, or -1 if not in the list
|
||||||
*/
|
*/
|
||||||
abstract fun indexOf(h: HabitGroup): Int
|
abstract fun indexOf(h: HabitGroup): Int
|
||||||
val isEmpty: Boolean
|
val isEmpty: Boolean
|
||||||
get() = size() == 0
|
get() = size() == 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the given habit from the list.
|
* Removes the given habit group from the list.
|
||||||
*
|
*
|
||||||
* If the given habit is not in the list, does nothing.
|
* If the given habit group is not in the list, does nothing.
|
||||||
*
|
*
|
||||||
* @param h the habit to be removed.
|
* @param h the habit group to be removed.
|
||||||
*/
|
*/
|
||||||
abstract fun remove(h: HabitGroup)
|
abstract fun remove(h: HabitGroup)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all the habits from the list.
|
* Removes all the habit groups from the list.
|
||||||
*/
|
*/
|
||||||
open fun removeAll() {
|
open fun removeAll() {
|
||||||
val copy: MutableList<HabitGroup> = LinkedList()
|
val copy: MutableList<HabitGroup> = LinkedList()
|
||||||
@@ -128,43 +128,49 @@ abstract class HabitGroupList : Iterable<HabitGroup> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the position of a habit in the list.
|
* Changes the position of a habit group in the list.
|
||||||
*
|
*
|
||||||
* @param from the habit that should be moved
|
* @param from the habit group that should be moved
|
||||||
* @param to the habit that currently occupies the desired position
|
* @param to the habit group that currently occupies the desired position
|
||||||
*/
|
*/
|
||||||
abstract fun reorder(from: HabitGroup, to: HabitGroup)
|
abstract fun reorder(from: HabitGroup, to: HabitGroup)
|
||||||
open fun repair() {}
|
open fun repair() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of habits in this list.
|
* Returns the number of habit groups in this list.
|
||||||
*
|
*
|
||||||
* @return number of habits
|
* @return number of habit groups
|
||||||
*/
|
*/
|
||||||
abstract fun size(): Int
|
abstract fun size(): Int
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the list that a certain list of habits has been modified.
|
* Notifies the list that a certain list of habit groups has been modified.
|
||||||
*
|
*
|
||||||
* Depending on the implementation, this operation might trigger a write to
|
* Depending on the implementation, this operation might trigger a write to
|
||||||
* disk, or do nothing at all. To make sure that the habits get persisted,
|
* disk, or do nothing at all. To make sure that the habit groups get persisted,
|
||||||
* this operation must be called.
|
* this operation must be called.
|
||||||
*
|
*
|
||||||
* @param habitGroups the list of habits that have been modified.
|
* @param habitGroups the list of habit groups that have been modified.
|
||||||
*/
|
*/
|
||||||
abstract fun update(habitGroups: List<HabitGroup>)
|
abstract fun update(habitGroups: List<HabitGroup>)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the list that a certain habit has been modified.
|
* Notifies the list that a certain habit group has been modified.
|
||||||
*
|
*
|
||||||
* See [.update] for more details.
|
* See [.update] for more details.
|
||||||
*
|
*
|
||||||
* @param habitGroup the habit that has been modified.
|
* @param habitGroup the habit groups that has been modified.
|
||||||
*/
|
*/
|
||||||
fun update(habitGroup: HabitGroup) {
|
fun update(habitGroup: HabitGroup) {
|
||||||
update(listOf(habitGroup))
|
update(listOf(habitGroup))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For an empty Habit group list, and a given list of habits,
|
||||||
|
* populate the habit groups with their appropriate habits
|
||||||
|
*
|
||||||
|
* @param habitList list of habits to add to the groups
|
||||||
|
* */
|
||||||
fun populateGroupsWith(habitList: HabitList) {
|
fun populateGroupsWith(habitList: HabitList) {
|
||||||
val toRemove = mutableListOf<String?>()
|
val toRemove = mutableListOf<String?>()
|
||||||
for (habit in habitList) {
|
for (habit in habitList) {
|
||||||
@@ -187,10 +193,9 @@ abstract class HabitGroupList : Iterable<HabitGroup> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the list of habits to the given writer, in CSV format. There is
|
* Writes the list of habit groups to the given writer, in CSV format. There is
|
||||||
* one line for each habit, containing the fields name, description,
|
* one line for each habit group, containing the fields name, description,
|
||||||
* frequency numerator, frequency denominator and color. The color is
|
* , and color. The color is written in HTML format (#000000).
|
||||||
* written in HTML format (#000000).
|
|
||||||
*
|
*
|
||||||
* @param out the writer that will receive the result
|
* @param out the writer that will receive the result
|
||||||
* @throws IOException if write operations fail
|
* @throws IOException if write operations fail
|
||||||
@@ -208,13 +213,13 @@ abstract class HabitGroupList : Iterable<HabitGroup> {
|
|||||||
)
|
)
|
||||||
val csv = CSVWriter(out)
|
val csv = CSVWriter(out)
|
||||||
csv.writeNext(header, false)
|
csv.writeNext(header, false)
|
||||||
for (habit in this) {
|
for (hgr in this) {
|
||||||
val cols = arrayOf(
|
val cols = arrayOf(
|
||||||
String.format("%03d", indexOf(habit) + 1),
|
String.format("%03d", indexOf(hgr) + 1),
|
||||||
habit.name,
|
hgr.name,
|
||||||
habit.question,
|
hgr.question,
|
||||||
habit.description,
|
hgr.description,
|
||||||
habit.color.toCsvColor()
|
hgr.color.toCsvColor()
|
||||||
)
|
)
|
||||||
csv.writeNext(cols, false)
|
csv.writeNext(cols, false)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user