mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-15 05:28:51 -06:00
Make HabitGroups simpler
No subgroups
This commit is contained in:
@@ -0,0 +1,232 @@
|
|||||||
|
package org.isoron.uhabits.activities.habits.edit
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.Html
|
||||||
|
import android.text.Spanned
|
||||||
|
import android.text.format.DateFormat
|
||||||
|
import android.view.View
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import com.android.datetimepicker.time.RadialPickerLayout
|
||||||
|
import com.android.datetimepicker.time.TimePickerDialog
|
||||||
|
import org.isoron.platform.gui.toInt
|
||||||
|
import org.isoron.uhabits.HabitsApplication
|
||||||
|
import org.isoron.uhabits.R
|
||||||
|
import org.isoron.uhabits.activities.AndroidThemeSwitcher
|
||||||
|
import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialogFactory
|
||||||
|
import org.isoron.uhabits.activities.common.dialogs.WeekdayPickerDialog
|
||||||
|
import org.isoron.uhabits.core.commands.CommandRunner
|
||||||
|
import org.isoron.uhabits.core.commands.CreateHabitGroupCommand
|
||||||
|
import org.isoron.uhabits.core.commands.EditHabitGroupCommand
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroup
|
||||||
|
import org.isoron.uhabits.core.models.PaletteColor
|
||||||
|
import org.isoron.uhabits.core.models.Reminder
|
||||||
|
import org.isoron.uhabits.core.models.WeekdayList
|
||||||
|
import org.isoron.uhabits.databinding.ActivityEditHabitGroupBinding
|
||||||
|
import org.isoron.uhabits.utils.ColorUtils
|
||||||
|
import org.isoron.uhabits.utils.dismissCurrentAndShow
|
||||||
|
import org.isoron.uhabits.utils.formatTime
|
||||||
|
import org.isoron.uhabits.utils.toFormattedString
|
||||||
|
|
||||||
|
class EditHabitGroupActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var themeSwitcher: AndroidThemeSwitcher
|
||||||
|
private lateinit var binding: ActivityEditHabitGroupBinding
|
||||||
|
private lateinit var commandRunner: CommandRunner
|
||||||
|
|
||||||
|
var habitGroupId = -1L
|
||||||
|
var color = PaletteColor(11)
|
||||||
|
var androidColor = 0
|
||||||
|
var reminderHour = -1
|
||||||
|
var reminderMin = -1
|
||||||
|
var reminderDays: WeekdayList = WeekdayList.EVERY_DAY
|
||||||
|
|
||||||
|
override fun onCreate(state: Bundle?) {
|
||||||
|
super.onCreate(state)
|
||||||
|
|
||||||
|
val component = (application as HabitsApplication).component
|
||||||
|
themeSwitcher = AndroidThemeSwitcher(this, component.preferences)
|
||||||
|
themeSwitcher.apply()
|
||||||
|
|
||||||
|
binding = ActivityEditHabitGroupBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
if (intent.hasExtra("habitGroupId")) {
|
||||||
|
binding.toolbar.title = getString(R.string.edit_habit_group)
|
||||||
|
habitGroupId = intent.getLongExtra("habitId", -1)
|
||||||
|
val hgr = component.habitGroupList.getById(habitGroupId)!!
|
||||||
|
color = hgr.color
|
||||||
|
hgr.reminder?.let {
|
||||||
|
reminderHour = it.hour
|
||||||
|
reminderMin = it.minute
|
||||||
|
reminderDays = it.days
|
||||||
|
}
|
||||||
|
binding.nameInput.setText(hgr.name)
|
||||||
|
binding.questionInput.setText(hgr.question)
|
||||||
|
binding.notesInput.setText(hgr.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state != null) {
|
||||||
|
habitGroupId = state.getLong("habitGroupId")
|
||||||
|
color = PaletteColor(state.getInt("paletteColor"))
|
||||||
|
reminderHour = state.getInt("reminderHour")
|
||||||
|
reminderMin = state.getInt("reminderMin")
|
||||||
|
reminderDays = WeekdayList(state.getInt("reminderDays"))
|
||||||
|
}
|
||||||
|
|
||||||
|
updateColors()
|
||||||
|
|
||||||
|
setSupportActionBar(binding.toolbar)
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
supportActionBar?.elevation = 10.0f
|
||||||
|
|
||||||
|
val colorPickerDialogFactory = ColorPickerDialogFactory(this)
|
||||||
|
binding.colorButton.setOnClickListener {
|
||||||
|
val picker = colorPickerDialogFactory.create(color, themeSwitcher.currentTheme)
|
||||||
|
picker.setListener { paletteColor ->
|
||||||
|
this.color = paletteColor
|
||||||
|
updateColors()
|
||||||
|
}
|
||||||
|
picker.dismissCurrentAndShow(supportFragmentManager, "colorPicker")
|
||||||
|
}
|
||||||
|
|
||||||
|
populateReminder()
|
||||||
|
binding.reminderTimePicker.setOnClickListener {
|
||||||
|
val currentHour = if (reminderHour >= 0) reminderHour else 8
|
||||||
|
val currentMin = if (reminderMin >= 0) reminderMin else 0
|
||||||
|
val is24HourMode = DateFormat.is24HourFormat(this)
|
||||||
|
val dialog = TimePickerDialog.newInstance(
|
||||||
|
object : TimePickerDialog.OnTimeSetListener {
|
||||||
|
override fun onTimeSet(view: RadialPickerLayout?, hourOfDay: Int, minute: Int) {
|
||||||
|
reminderHour = hourOfDay
|
||||||
|
reminderMin = minute
|
||||||
|
populateReminder()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTimeCleared(view: RadialPickerLayout?) {
|
||||||
|
reminderHour = -1
|
||||||
|
reminderMin = -1
|
||||||
|
reminderDays = WeekdayList.EVERY_DAY
|
||||||
|
populateReminder()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentHour,
|
||||||
|
currentMin,
|
||||||
|
is24HourMode,
|
||||||
|
androidColor
|
||||||
|
)
|
||||||
|
dialog.dismissCurrentAndShow(supportFragmentManager, "timePicker")
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.reminderDatePicker.setOnClickListener {
|
||||||
|
val dialog = WeekdayPickerDialog()
|
||||||
|
|
||||||
|
dialog.setListener { days: WeekdayList ->
|
||||||
|
reminderDays = days
|
||||||
|
if (reminderDays.isEmpty) reminderDays = WeekdayList.EVERY_DAY
|
||||||
|
populateReminder()
|
||||||
|
}
|
||||||
|
dialog.setSelectedDays(reminderDays)
|
||||||
|
dialog.dismissCurrentAndShow(supportFragmentManager, "dayPicker")
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.buttonSave.setOnClickListener {
|
||||||
|
if (validate()) save()
|
||||||
|
}
|
||||||
|
|
||||||
|
for (fragment in supportFragmentManager.fragments) {
|
||||||
|
(fragment as DialogFragment).dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun save() {
|
||||||
|
val component = (application as HabitsApplication).component
|
||||||
|
val hgr = component.modelFactory.buildHabitGroup()
|
||||||
|
|
||||||
|
var original: HabitGroup? = null
|
||||||
|
if (habitGroupId >= 0) {
|
||||||
|
original = component.habitGroupList.getById(habitGroupId)!!
|
||||||
|
hgr.copyFrom(original)
|
||||||
|
}
|
||||||
|
|
||||||
|
hgr.name = binding.nameInput.text.trim().toString()
|
||||||
|
hgr.question = binding.questionInput.text.trim().toString()
|
||||||
|
hgr.description = binding.notesInput.text.trim().toString()
|
||||||
|
hgr.color = color
|
||||||
|
if (reminderHour >= 0) {
|
||||||
|
hgr.reminder = Reminder(reminderHour, reminderMin, reminderDays)
|
||||||
|
} else {
|
||||||
|
hgr.reminder = null
|
||||||
|
}
|
||||||
|
|
||||||
|
val command = if (habitGroupId >= 0) {
|
||||||
|
EditHabitGroupCommand(
|
||||||
|
component.habitGroupList,
|
||||||
|
habitGroupId,
|
||||||
|
hgr
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
CreateHabitGroupCommand(
|
||||||
|
component.modelFactory,
|
||||||
|
component.habitGroupList,
|
||||||
|
hgr
|
||||||
|
)
|
||||||
|
}
|
||||||
|
component.commandRunner.run(command)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validate(): Boolean {
|
||||||
|
var isValid = true
|
||||||
|
if (binding.nameInput.text.isEmpty()) {
|
||||||
|
binding.nameInput.error = getFormattedValidationError(R.string.validation_cannot_be_blank)
|
||||||
|
isValid = false
|
||||||
|
}
|
||||||
|
return isValid
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun populateReminder() {
|
||||||
|
if (reminderHour < 0) {
|
||||||
|
binding.reminderTimePicker.text = getString(R.string.reminder_off)
|
||||||
|
binding.reminderDatePicker.visibility = View.GONE
|
||||||
|
binding.reminderDivider.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
val time = formatTime(this, reminderHour, reminderMin)
|
||||||
|
binding.reminderTimePicker.text = time
|
||||||
|
binding.reminderDatePicker.visibility = View.VISIBLE
|
||||||
|
binding.reminderDivider.visibility = View.VISIBLE
|
||||||
|
binding.reminderDatePicker.text = reminderDays.toFormattedString(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateColors() {
|
||||||
|
androidColor = themeSwitcher.currentTheme.color(color).toInt()
|
||||||
|
binding.colorButton.backgroundTintList = ColorStateList.valueOf(androidColor)
|
||||||
|
if (!themeSwitcher.isNightMode) {
|
||||||
|
val darkerAndroidColor = ColorUtils.mixColors(Color.BLACK, androidColor, 0.15f)
|
||||||
|
window.statusBarColor = darkerAndroidColor
|
||||||
|
binding.toolbar.setBackgroundColor(androidColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFormattedValidationError(@StringRes resId: Int): Spanned {
|
||||||
|
val html = "<font color=#FFFFFF>${getString(resId)}</font>"
|
||||||
|
return Html.fromHtml(html)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(state: Bundle) {
|
||||||
|
super.onSaveInstanceState(state)
|
||||||
|
with(state) {
|
||||||
|
putLong("habitGroupId", habitGroupId)
|
||||||
|
putInt("paletteColor", color.paletteIndex)
|
||||||
|
putInt("androidColor", androidColor)
|
||||||
|
putInt("reminderHour", reminderHour)
|
||||||
|
putInt("reminderMin", reminderMin)
|
||||||
|
putInt("reminderDays", reminderDays.toInteger())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,10 +25,12 @@ import android.net.Uri
|
|||||||
import org.isoron.uhabits.R
|
import org.isoron.uhabits.R
|
||||||
import org.isoron.uhabits.activities.about.AboutActivity
|
import org.isoron.uhabits.activities.about.AboutActivity
|
||||||
import org.isoron.uhabits.activities.habits.edit.EditHabitActivity
|
import org.isoron.uhabits.activities.habits.edit.EditHabitActivity
|
||||||
|
import org.isoron.uhabits.activities.habits.edit.EditHabitGroupActivity
|
||||||
import org.isoron.uhabits.activities.habits.show.ShowHabitActivity
|
import org.isoron.uhabits.activities.habits.show.ShowHabitActivity
|
||||||
import org.isoron.uhabits.activities.intro.IntroActivity
|
import org.isoron.uhabits.activities.intro.IntroActivity
|
||||||
import org.isoron.uhabits.activities.settings.SettingsActivity
|
import org.isoron.uhabits.activities.settings.SettingsActivity
|
||||||
import org.isoron.uhabits.core.models.Habit
|
import org.isoron.uhabits.core.models.Habit
|
||||||
|
import org.isoron.uhabits.core.models.HabitGroup
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class IntentFactory
|
class IntentFactory
|
||||||
@@ -100,4 +102,14 @@ class IntentFactory
|
|||||||
intent.putExtra("habitType", habitType)
|
intent.putExtra("habitType", habitType)
|
||||||
return intent
|
return intent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startEditGroupActivity(context: Context): Intent {
|
||||||
|
return Intent(context, EditHabitGroupActivity::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startEditGroupActivity(context: Context, habitGroup: HabitGroup): Intent {
|
||||||
|
val intent = startEditGroupActivity(context)
|
||||||
|
intent.putExtra("habitGroupId", habitGroup.id)
|
||||||
|
return intent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
72
uhabits-android/src/main/res/layout/show_habit_group.xml
Normal file
72
uhabits-android/src/main/res/layout/show_habit_group.xml
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
|
||||||
|
~
|
||||||
|
~ 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 <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/container"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
style="@style/Toolbar"
|
||||||
|
app:popupTheme="?toolbarPopupTheme"
|
||||||
|
android:layout_alignParentTop="true"/>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/scrollView"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/toolbar"
|
||||||
|
android:background="?windowBackgroundColor"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/CardList"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
|
<org.isoron.uhabits.activities.habits.show.views.SubtitleCardView
|
||||||
|
android:id="@+id/subtitleCard"
|
||||||
|
style="@style/ShowHabit.Subtitle"/>
|
||||||
|
|
||||||
|
<org.isoron.uhabits.activities.habits.show.views.NotesCardView
|
||||||
|
android:id="@+id/notesCard"
|
||||||
|
style="@style/Card"
|
||||||
|
android:gravity="center" />
|
||||||
|
|
||||||
|
<org.isoron.uhabits.activities.habits.show.views.OverviewCardView
|
||||||
|
android:id="@+id/overviewCard"
|
||||||
|
style="@style/Card"
|
||||||
|
android:paddingTop="12dp"/>
|
||||||
|
|
||||||
|
<org.isoron.uhabits.activities.habits.show.views.ScoreCardView
|
||||||
|
android:id="@+id/scoreCard"
|
||||||
|
style="@style/Card"
|
||||||
|
android:gravity="center"/>
|
||||||
|
|
||||||
|
<org.isoron.uhabits.activities.habits.show.views.StreakCardView
|
||||||
|
android:id="@+id/streakCard"
|
||||||
|
style="@style/Card"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
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.ModelFactory
|
||||||
|
|
||||||
|
data class CreateHabitGroupCommand(
|
||||||
|
val modelFactory: ModelFactory,
|
||||||
|
val habitGroupList: HabitGroupList,
|
||||||
|
val model: HabitGroup
|
||||||
|
) : Command {
|
||||||
|
override fun run() {
|
||||||
|
val habitGroup = modelFactory.buildHabitGroup()
|
||||||
|
habitGroup.copyFrom(model)
|
||||||
|
habitGroupList.add(habitGroup)
|
||||||
|
habitGroup.recompute()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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.HabitNotFoundException
|
||||||
|
|
||||||
|
data class EditHabitGroupCommand(
|
||||||
|
val habitGroupList: HabitGroupList,
|
||||||
|
val habitGroupId: Long,
|
||||||
|
val modified: HabitGroup
|
||||||
|
) : Command {
|
||||||
|
override fun run() {
|
||||||
|
val habitGroup = habitGroupList.getById(habitGroupId) ?: throw HabitNotFoundException()
|
||||||
|
habitGroup.copyFrom(modified)
|
||||||
|
habitGroupList.update(habitGroup)
|
||||||
|
habitGroup.observable.notifyListeners()
|
||||||
|
habitGroup.recompute()
|
||||||
|
habitGroupList.resort()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,6 @@ data class HabitGroup(
|
|||||||
var reminder: Reminder? = null,
|
var reminder: Reminder? = null,
|
||||||
var uuid: String? = null,
|
var uuid: String? = null,
|
||||||
var habitList: HabitList,
|
var habitList: HabitList,
|
||||||
var habitGroupList: HabitGroupList,
|
|
||||||
val scores: ScoreList,
|
val scores: ScoreList,
|
||||||
val streaks: StreakList,
|
val streaks: StreakList,
|
||||||
var parentID: Long? = null,
|
var parentID: Long? = null,
|
||||||
@@ -33,11 +32,11 @@ data class HabitGroup(
|
|||||||
fun hasReminder(): Boolean = reminder != null
|
fun hasReminder(): Boolean = reminder != null
|
||||||
|
|
||||||
fun isCompletedToday(): Boolean {
|
fun isCompletedToday(): Boolean {
|
||||||
return habitList.all { it.isCompletedToday() } && habitGroupList.all { it.isCompletedToday() }
|
return habitList.all { it.isCompletedToday() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isEnteredToday(): Boolean {
|
fun isEnteredToday(): Boolean {
|
||||||
return habitList.all { it.isEnteredToday() } && habitGroupList.all { it.isEnteredToday() }
|
return habitList.all { it.isEnteredToday() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun firstEntryDate(): Timestamp {
|
fun firstEntryDate(): Timestamp {
|
||||||
@@ -47,16 +46,11 @@ data class HabitGroup(
|
|||||||
val first = h.firstEntryDate()
|
val first = h.firstEntryDate()
|
||||||
if (earliest.isNewerThan(first)) earliest = first
|
if (earliest.isNewerThan(first)) earliest = first
|
||||||
}
|
}
|
||||||
for (hgr in habitGroupList) {
|
|
||||||
val first = hgr.firstEntryDate()
|
|
||||||
if (earliest.isNewerThan(first)) earliest = first
|
|
||||||
}
|
|
||||||
return earliest
|
return earliest
|
||||||
}
|
}
|
||||||
|
|
||||||
fun recompute() {
|
fun recompute() {
|
||||||
for (h in habitList) h.recompute()
|
for (h in habitList) h.recompute()
|
||||||
for (hgr in habitGroupList) hgr.recompute()
|
|
||||||
|
|
||||||
val today = DateUtils.getTodayWithOffset()
|
val today = DateUtils.getTodayWithOffset()
|
||||||
val to = today.plus(30)
|
val to = today.plus(30)
|
||||||
@@ -65,14 +59,12 @@ data class HabitGroup(
|
|||||||
|
|
||||||
scores.combineFrom(
|
scores.combineFrom(
|
||||||
habitList = habitList,
|
habitList = habitList,
|
||||||
habitGroupList = habitGroupList,
|
|
||||||
from = from,
|
from = from,
|
||||||
to = to
|
to = to
|
||||||
)
|
)
|
||||||
|
|
||||||
streaks.combineFrom(
|
streaks.combineFrom(
|
||||||
habitList = habitList,
|
habitList = habitList,
|
||||||
habitGroupList = habitGroupList,
|
|
||||||
from = from,
|
from = from,
|
||||||
to = to
|
to = to
|
||||||
)
|
)
|
||||||
@@ -134,23 +126,6 @@ data class HabitGroup(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getHabitByUUIDDeep(uuid: String?): Habit? {
|
fun getHabitByUUIDDeep(uuid: String?): Habit? =
|
||||||
val habit = habitList.getByUUID(uuid)
|
habitList.getByUUID(uuid)
|
||||||
if (habit != null) return habit
|
|
||||||
for (hgr in habitGroupList) {
|
|
||||||
val found = hgr.getHabitByUUIDDeep(uuid)
|
|
||||||
if (found != null) return found
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getHabitGroupByUUIDDeep(uuid: String?): HabitGroup? {
|
|
||||||
val habitGroup = habitGroupList.getByUUID(uuid)
|
|
||||||
if (habitGroup != null) return habitGroup
|
|
||||||
for (hgr in habitGroupList) {
|
|
||||||
val found = hgr.getHabitGroupByUUIDDeep(uuid)
|
|
||||||
if (found != null) return found
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,16 +78,6 @@ abstract class HabitGroupList : Iterable<HabitGroup> {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getHabitGroupByUUIDDeep(uuid: String?): HabitGroup? {
|
|
||||||
for (hgr in this) {
|
|
||||||
val habit = hgr.getHabitGroupByUUIDDeep(uuid)
|
|
||||||
if (habit != null) {
|
|
||||||
return habit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the habit that occupies a certain position.
|
* Returns the habit that occupies a certain position.
|
||||||
*
|
*
|
||||||
@@ -191,21 +181,6 @@ abstract class HabitGroupList : Iterable<HabitGroup> {
|
|||||||
habitList.remove(h)
|
habitList.remove(h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toRemove.clear()
|
|
||||||
for (hgr1 in this) {
|
|
||||||
val hgr2 = getByUUID(hgr1.parentUUID)
|
|
||||||
if (hgr2 != null) {
|
|
||||||
hgr2.habitGroupList.add(hgr1)
|
|
||||||
toRemove.add(hgr1.uuid)
|
|
||||||
hgr1.parent = hgr2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (uuid in toRemove) {
|
|
||||||
val h = getByUUID(uuid)
|
|
||||||
if (h != null) {
|
|
||||||
remove(h)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (hgr in this) {
|
for (hgr in this) {
|
||||||
hgr.recompute()
|
hgr.recompute()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,12 +41,10 @@ interface ModelFactory {
|
|||||||
}
|
}
|
||||||
fun buildHabitGroup(): HabitGroup {
|
fun buildHabitGroup(): HabitGroup {
|
||||||
val habits = buildHabitList()
|
val habits = buildHabitList()
|
||||||
val groups = buildHabitGroupList()
|
|
||||||
val scores = buildScoreList()
|
val scores = buildScoreList()
|
||||||
val streaks = buildStreakList()
|
val streaks = buildStreakList()
|
||||||
return HabitGroup(
|
return HabitGroup(
|
||||||
habitList = habits,
|
habitList = habits,
|
||||||
habitGroupList = groups,
|
|
||||||
scores = scores,
|
scores = scores,
|
||||||
streaks = streaks
|
streaks = streaks
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -141,15 +141,13 @@ class ScoreList {
|
|||||||
@Synchronized
|
@Synchronized
|
||||||
fun combineFrom(
|
fun combineFrom(
|
||||||
habitList: HabitList,
|
habitList: HabitList,
|
||||||
habitGroupList: HabitGroupList,
|
|
||||||
from: Timestamp,
|
from: Timestamp,
|
||||||
to: Timestamp
|
to: Timestamp
|
||||||
) {
|
) {
|
||||||
var current = to
|
var current = to
|
||||||
while (current >= from) {
|
while (current >= from) {
|
||||||
val habitScores = habitList.map { it.scores[current].value }
|
val habitScores = habitList.map { it.scores[current].value }
|
||||||
val groupScores = habitGroupList.map { it.scores[current].value }
|
val averageScore = habitScores.average()
|
||||||
val averageScore = (habitScores + groupScores).average()
|
|
||||||
map[current] = Score(current, averageScore)
|
map[current] = Score(current, averageScore)
|
||||||
current = current.minus(1)
|
current = current.minus(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ class StreakList {
|
|||||||
@Synchronized
|
@Synchronized
|
||||||
fun combineFrom(
|
fun combineFrom(
|
||||||
habitList: HabitList,
|
habitList: HabitList,
|
||||||
habitGroupList: HabitGroupList,
|
|
||||||
from: Timestamp,
|
from: Timestamp,
|
||||||
to: Timestamp
|
to: Timestamp
|
||||||
) {
|
) {
|
||||||
@@ -79,9 +78,7 @@ class StreakList {
|
|||||||
var streakRunning = false
|
var streakRunning = false
|
||||||
var streakStart = from
|
var streakStart = from
|
||||||
while (current <= to) {
|
while (current <= to) {
|
||||||
if (habitList.all { it.streaks.isInStreaks(current) } &&
|
if (habitList.all { it.streaks.isInStreaks(current) } && !streakRunning
|
||||||
habitGroupList.all { it.streaks.isInStreaks(current) } &&
|
|
||||||
!streakRunning
|
|
||||||
) {
|
) {
|
||||||
streakStart = current
|
streakStart = current
|
||||||
streakRunning = true
|
streakRunning = true
|
||||||
|
|||||||
@@ -205,10 +205,6 @@ class MemoryHabitGroupList : HabitGroupList {
|
|||||||
hgr.habitList.primaryOrder = primaryOrder
|
hgr.habitList.primaryOrder = primaryOrder
|
||||||
hgr.habitList.secondaryOrder = secondaryOrder
|
hgr.habitList.secondaryOrder = secondaryOrder
|
||||||
hgr.habitList.resort()
|
hgr.habitList.resort()
|
||||||
|
|
||||||
hgr.habitGroupList.primaryOrder = primaryOrder
|
|
||||||
hgr.habitGroupList.secondaryOrder = secondaryOrder
|
|
||||||
hgr.habitGroupList.resort()
|
|
||||||
}
|
}
|
||||||
if (comparator != null) list.sortWith(comparator!!)
|
if (comparator != null) list.sortWith(comparator!!)
|
||||||
observable.notifyListeners()
|
observable.notifyListeners()
|
||||||
|
|||||||
@@ -49,12 +49,6 @@ class HabitGroupRecord {
|
|||||||
@field:Column
|
@field:Column
|
||||||
var uuid: String? = null
|
var uuid: String? = null
|
||||||
|
|
||||||
@field:Column(name = "parent_id")
|
|
||||||
var parentID: Long? = null
|
|
||||||
|
|
||||||
@field:Column(name = "parent_uuid")
|
|
||||||
var parentUUID: String? = null
|
|
||||||
|
|
||||||
fun copyFrom(model: HabitGroup) {
|
fun copyFrom(model: HabitGroup) {
|
||||||
id = model.id
|
id = model.id
|
||||||
name = model.name
|
name = model.name
|
||||||
@@ -68,8 +62,6 @@ class HabitGroupRecord {
|
|||||||
reminderDays = 0
|
reminderDays = 0
|
||||||
reminderMin = null
|
reminderMin = null
|
||||||
reminderHour = null
|
reminderHour = null
|
||||||
parentID = model.parentID
|
|
||||||
parentUUID = model.parentUUID
|
|
||||||
if (model.hasReminder()) {
|
if (model.hasReminder()) {
|
||||||
val reminder = model.reminder
|
val reminder = model.reminder
|
||||||
reminderHour = requireNonNull(reminder)!!.hour
|
reminderHour = requireNonNull(reminder)!!.hour
|
||||||
@@ -87,8 +79,6 @@ class HabitGroupRecord {
|
|||||||
habitGroup.isArchived = archived != 0
|
habitGroup.isArchived = archived != 0
|
||||||
habitGroup.position = position!!
|
habitGroup.position = position!!
|
||||||
habitGroup.uuid = uuid
|
habitGroup.uuid = uuid
|
||||||
habitGroup.parentID = parentID
|
|
||||||
habitGroup.parentUUID = parentUUID
|
|
||||||
if (reminderHour != null && reminderMin != null) {
|
if (reminderHour != null && reminderMin != null) {
|
||||||
habitGroup.reminder = Reminder(
|
habitGroup.reminder = Reminder(
|
||||||
reminderHour!!,
|
reminderHour!!,
|
||||||
|
|||||||
@@ -15,7 +15,5 @@ create table HabitGroups (
|
|||||||
reminder_hour integer,
|
reminder_hour integer,
|
||||||
reminder_min integer,
|
reminder_min integer,
|
||||||
question text not null default "",
|
question text not null default "",
|
||||||
uuid text,
|
uuid text
|
||||||
parent_id integer,
|
|
||||||
parent_uuid integer
|
|
||||||
);
|
);
|
||||||
Reference in New Issue
Block a user