From a7df0bde3e119532fe5ffd8ff187137270ed9974 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Wed, 20 Jan 2021 23:36:38 +0100 Subject: [PATCH] Convert core.models.sqlite --- .../isoron/uhabits/core/io/LoopDBImporter.kt | 4 +- .../core/models/sqlite/SQLiteHabitList.java | 296 ------------------ .../core/models/sqlite/SQLiteHabitList.kt | 226 +++++++++++++ .../{EntryRecord.java => EntryRecord.kt} | 50 +-- .../models/sqlite/records/HabitRecord.java | 141 --------- .../core/models/sqlite/records/HabitRecord.kt | 138 ++++++++ 6 files changed, 392 insertions(+), 463 deletions(-) delete mode 100644 uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.java create mode 100644 uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.kt rename uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/{EntryRecord.java => EntryRecord.kt} (51%) delete mode 100644 uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.java create mode 100644 uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt index c8f76e4a5..0969cd849 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt @@ -100,9 +100,9 @@ class LoopDBImporter habit = habitList.getByUUID(habitRecord.uuid) for (r in entryRecords) { - val t = Timestamp(r.timestamp) + val t = Timestamp(r.timestamp!!) val (_, value) = habit!!.originalEntries.get(t) - if (value != r.value) CreateRepetitionCommand(habitList, habit, t, r.value).run() + if (value != r.value) CreateRepetitionCommand(habitList, habit, t, r.value!!).run() } runner.notifyListeners(command) diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.java b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.java deleted file mode 100644 index 4e8426a7d..000000000 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.java +++ /dev/null @@ -1,296 +0,0 @@ -/* - * 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.models.sqlite; - -import androidx.annotation.*; - -import org.isoron.uhabits.core.database.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.models.memory.*; -import org.isoron.uhabits.core.models.sqlite.records.*; -import org.jetbrains.annotations.NotNull; - -import java.util.*; - -import javax.inject.*; - -/** - * Implementation of a {@link HabitList} that is backed by SQLite. - */ -public class SQLiteHabitList extends HabitList -{ - @NonNull - private final Repository repository; - - @NonNull - private final ModelFactory modelFactory; - - @NonNull - private final MemoryHabitList list; - - private boolean loaded = false; - - @Inject - public SQLiteHabitList(@NonNull ModelFactory modelFactory) - { - super(); - this.modelFactory = modelFactory; - this.list = new MemoryHabitList(); - this.repository = modelFactory.buildHabitListRepository(); - } - - private void loadRecords() - { - if (loaded) return; - loaded = true; - - list.removeAll(); - List records = repository.findAll("order by position"); - - int expectedPosition = 0; - boolean shouldRebuildOrder = false; - for (HabitRecord rec : records) - { - if (rec.position != expectedPosition) shouldRebuildOrder = true; - expectedPosition++; - - Habit h = modelFactory.buildHabit(); - rec.copyTo(h); - ((SQLiteEntryList) h.getOriginalEntries()).setHabitId(h.getId()); - list.add(h); - } - - if(shouldRebuildOrder) rebuildOrder(); - } - - @Override - public synchronized void add(@NonNull Habit habit) - { - loadRecords(); - habit.setPosition(size()); - - HabitRecord record = new HabitRecord(); - record.copyFrom(habit); - repository.save(record); - habit.setId(record.id); - ((SQLiteEntryList) habit.getOriginalEntries()).setHabitId(record.id); - - list.add(habit); - getObservable().notifyListeners(); - } - - @Override - @Nullable - public synchronized Habit getById(long id) - { - loadRecords(); - return list.getById(id); - } - - @Override - @Nullable - public synchronized Habit getByUUID(String uuid) - { - loadRecords(); - return list.getByUUID(uuid); - } - - @Override - @NonNull - public synchronized Habit getByPosition(int position) - { - loadRecords(); - return list.getByPosition(position); - } - - @NonNull - @Override - public synchronized HabitList getFiltered(HabitMatcher filter) - { - loadRecords(); - return list.getFiltered(filter); - } - - @Override - @NonNull - public Order getPrimaryOrder() - { - return list.getPrimaryOrder(); - } - - @Override - public Order getSecondaryOrder() - { - return list.getSecondaryOrder(); - } - - @Override - public synchronized void setPrimaryOrder(@NonNull Order order) - { - list.setPrimaryOrder(order); - getObservable().notifyListeners(); - } - - @Override - public synchronized void setSecondaryOrder(@NonNull Order order) - { - list.setSecondaryOrder(order); - getObservable().notifyListeners(); - } - - @Override - public synchronized int indexOf(@NonNull Habit h) - { - loadRecords(); - return list.indexOf(h); - } - - @NotNull - @Override - public synchronized Iterator iterator() - { - loadRecords(); - return list.iterator(); - } - - private synchronized void rebuildOrder() - { - List records = repository.findAll("order by position"); - repository.executeAsTransaction(() -> - { - int pos = 0; - for (HabitRecord r : records) - { - if (r.position != pos) - { - r.position = pos; - repository.save(r); - } - pos++; - } - }); - } - - @Override - public synchronized void remove(@NonNull Habit habit) - { - loadRecords(); - - reorder(habit, list.getByPosition(size() - 1)); - - list.remove(habit); - - HabitRecord record = repository.find(habit.getId()); - if (record == null) throw new RuntimeException("habit not in database"); - repository.executeAsTransaction(() -> - { - habit.getOriginalEntries().clear(); - repository.remove(record); - }); - - getObservable().notifyListeners(); - } - - @Override - public synchronized void removeAll() - { - list.removeAll(); - repository.execSQL("delete from habits"); - repository.execSQL("delete from repetitions"); - getObservable().notifyListeners(); - } - - @Override - public synchronized void reorder(@NonNull Habit from, @NonNull Habit to) - { - loadRecords(); - list.reorder(from, to); - - HabitRecord fromRecord = repository.find(from.getId()); - HabitRecord toRecord = repository.find(to.getId()); - - if (fromRecord == null) - throw new RuntimeException("habit not in database"); - if (toRecord == null) - throw new RuntimeException("habit not in database"); - - if (toRecord.position < fromRecord.position) - { - repository.execSQL("update habits set position = position + 1 " + - "where position >= ? and position < ?", - toRecord.position, fromRecord.position); - } - else - { - repository.execSQL("update habits set position = position - 1 " + - "where position > ? and position <= ?", - fromRecord.position, toRecord.position); - } - - fromRecord.position = toRecord.position; - repository.save(fromRecord); - - getObservable().notifyListeners(); - } - - @Override - public synchronized void repair() - { - loadRecords(); - rebuildOrder(); - getObservable().notifyListeners(); - } - - @Override - public synchronized int size() - { - loadRecords(); - return list.size(); - } - - @Override - public synchronized void update(List habits) - { - loadRecords(); - list.update(habits); - - for (Habit h : habits) - { - HabitRecord record = repository.find(h.getId()); - if (record == null) continue; - record.copyFrom(h); - repository.save(record); - } - - getObservable().notifyListeners(); - } - - @Override - public void resort() - { - list.resort(); - getObservable().notifyListeners(); - } - - public synchronized void reload() - { - loaded = false; - } -} diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.kt new file mode 100644 index 000000000..acb32141b --- /dev/null +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.kt @@ -0,0 +1,226 @@ +/* + * 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.models.sqlite + +import org.isoron.uhabits.core.database.Repository +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.core.models.HabitList +import org.isoron.uhabits.core.models.HabitMatcher +import org.isoron.uhabits.core.models.ModelFactory +import org.isoron.uhabits.core.models.memory.MemoryHabitList +import org.isoron.uhabits.core.models.sqlite.records.HabitRecord +import javax.inject.Inject + +/** + * Implementation of a [HabitList] that is backed by SQLite. + */ +class SQLiteHabitList @Inject constructor(private val modelFactory: ModelFactory) : HabitList() { + private val repository: Repository + private val list: MemoryHabitList = MemoryHabitList() + private var loaded = false + private fun loadRecords() { + if (loaded) return + loaded = true + list.removeAll() + val records = repository.findAll("order by position") + var shouldRebuildOrder = false + for ((expectedPosition, rec) in records.withIndex()) { + if (rec.position != expectedPosition) shouldRebuildOrder = true + val h = modelFactory.buildHabit() + rec.copyTo(h) + (h.originalEntries as SQLiteEntryList).habitId = h.id + list.add(h) + } + if (shouldRebuildOrder) rebuildOrder() + } + + @Synchronized + override fun add(habit: Habit) { + loadRecords() + habit.position = size() + val record = HabitRecord() + record.copyFrom(habit) + repository.save(record) + habit.id = record.id + (habit.originalEntries as SQLiteEntryList).habitId = record.id + list.add(habit) + observable.notifyListeners() + } + + @Synchronized + override fun getById(id: Long): Habit? { + loadRecords() + return list.getById(id) + } + + @Synchronized + override fun getByUUID(uuid: String?): Habit? { + loadRecords() + return list.getByUUID(uuid) + } + + @Synchronized + override fun getByPosition(position: Int): Habit { + loadRecords() + return list.getByPosition(position) + } + + @Synchronized + override fun getFiltered(matcher: HabitMatcher?): HabitList { + loadRecords() + return list.getFiltered(matcher) + } + + @set:Synchronized + override var primaryOrder: Order + get() = list.primaryOrder + set(order) { + list.primaryOrder = order + observable.notifyListeners() + } + + @set:Synchronized + override var secondaryOrder: Order + get() = list.secondaryOrder + set(order) { + list.secondaryOrder = order + observable.notifyListeners() + } + + @Synchronized + override fun indexOf(h: Habit): Int { + loadRecords() + return list.indexOf(h) + } + + @Synchronized + override fun iterator(): Iterator { + loadRecords() + return list.iterator() + } + + @Synchronized + private fun rebuildOrder() { + val records = repository.findAll("order by position") + repository.executeAsTransaction { + for ((pos, r) in records.withIndex()) { + if (r.position != pos) { + r.position = pos + repository.save(r) + } + } + } + } + + @Synchronized + override fun remove(h: Habit) { + loadRecords() + reorder(h, list.getByPosition(size() - 1)) + list.remove(h) + val record = repository.find( + h.id!! + ) ?: throw RuntimeException("habit not in database") + repository.executeAsTransaction { + h.originalEntries.clear() + repository.remove(record) + } + observable.notifyListeners() + } + + @Synchronized + override fun removeAll() { + list.removeAll() + repository.execSQL("delete from habits") + repository.execSQL("delete from repetitions") + observable.notifyListeners() + } + + @Synchronized + override fun reorder(from: Habit, to: Habit) { + loadRecords() + list.reorder(from, to) + val fromRecord = repository.find( + from.id!! + ) + val toRecord = repository.find( + to.id!! + ) + if (fromRecord == null) throw RuntimeException("habit not in database") + if (toRecord == null) throw RuntimeException("habit not in database") + if (toRecord.position!! < fromRecord.position!!) { + repository.execSQL( + "update habits set position = position + 1 " + + "where position >= ? and position < ?", + toRecord.position!!, + fromRecord.position!! + ) + } else { + repository.execSQL( + "update habits set position = position - 1 " + + "where position > ? and position <= ?", + fromRecord.position!!, + toRecord.position!! + ) + } + fromRecord.position = toRecord.position + repository.save(fromRecord) + observable.notifyListeners() + } + + @Synchronized + override fun repair() { + loadRecords() + rebuildOrder() + observable.notifyListeners() + } + + @Synchronized + override fun size(): Int { + loadRecords() + return list.size() + } + + @Synchronized + override fun update(habits: List?) { + loadRecords() + list.update(habits) + for (h in habits!!) { + val record = repository.find( + h!!.id!! + ) ?: continue + record.copyFrom(h) + repository.save(record) + } + observable.notifyListeners() + } + + override fun resort() { + list.resort() + observable.notifyListeners() + } + + @Synchronized + fun reload() { + loaded = false + } + + init { + repository = modelFactory.buildHabitListRepository() + } +} diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecord.java b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecord.kt similarity index 51% rename from uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecord.java rename to uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecord.kt index 7355e6ce7..757c4a8f9 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecord.java +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecord.kt @@ -16,40 +16,42 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ +package org.isoron.uhabits.core.models.sqlite.records -package org.isoron.uhabits.core.models.sqlite.records; - -import org.isoron.uhabits.core.database.*; -import org.isoron.uhabits.core.models.*; +import org.isoron.uhabits.core.database.Column +import org.isoron.uhabits.core.database.Table +import org.isoron.uhabits.core.models.Entry +import org.isoron.uhabits.core.models.Timestamp /** - * The SQLite database record corresponding to a {@link Entry}. + * The SQLite database record corresponding to a [Entry]. */ @Table(name = "Repetitions") -public class EntryRecord -{ - public HabitRecord habit; - - @Column(name = "habit") - public Long habitId; +class EntryRecord { + var habit: HabitRecord? = null - @Column - public Long timestamp; + @field:Column(name = "habit") + var habitId: Long? = null - @Column - public Integer value; + @field:Column + var timestamp: Long? = null - @Column - public Long id; + @field:Column + var value: Int? = null - public void copyFrom(Entry entry) - { - timestamp = entry.getTimestamp().getUnixTime(); - value = entry.getValue(); + @field:Column + var id: Long? = null + fun copyFrom(entry: Entry) { + timestamp = entry.timestamp.unixTime + value = entry.value } - public Entry toEntry() - { - return new Entry(new Timestamp(timestamp), value); + fun toEntry(): Entry { + return Entry( + Timestamp( + timestamp!! + ), + value!! + ) } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.java b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.java deleted file mode 100644 index 8ddaeb183..000000000 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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.models.sqlite.records; - -import org.isoron.uhabits.core.database.*; -import org.isoron.uhabits.core.models.*; - -import java.util.Objects; - -/** - * The SQLite database record corresponding to a {@link Habit}. - */ -@Table(name = "habits") -public class HabitRecord -{ - @Column - public String description; - - @Column - public String question; - - @Column - public String name; - - @Column(name = "freq_num") - public Integer freqNum; - - @Column(name = "freq_den") - public Integer freqDen; - - @Column - public Integer color; - - @Column - public Integer position; - - @Column(name = "reminder_hour") - public Integer reminderHour; - - @Column(name = "reminder_min") - public Integer reminderMin; - - @Column(name = "reminder_days") - public Integer reminderDays; - - @Column - public Integer highlight; - - @Column - public Integer archived; - - @Column - public Integer type; - - @Column(name = "target_value") - public Double targetValue; - - @Column(name = "target_type") - public Integer targetType; - - @Column - public String unit; - - @Column - public Long id; - - @Column - public String uuid; - - public void copyFrom(Habit model) - { - this.id = model.getId(); - this.name = model.getName(); - this.description = model.getDescription(); - this.highlight = 0; - this.color = model.getColor().getPaletteIndex(); - this.archived = model.isArchived() ? 1 : 0; - this.type = model.getType(); - this.targetType = model.getTargetType(); - this.targetValue = model.getTargetValue(); - this.unit = model.getUnit(); - this.position = model.getPosition(); - this.question = model.getQuestion(); - this.uuid = model.getUuid(); - - Frequency freq = model.getFrequency(); - this.freqNum = freq.getNumerator(); - this.freqDen = freq.getDenominator(); - this.reminderDays = 0; - this.reminderMin = null; - this.reminderHour = null; - - if (model.hasReminder()) - { - Reminder reminder = model.getReminder(); - this.reminderHour = Objects.requireNonNull(reminder).getHour(); - this.reminderMin = reminder.getMinute(); - this.reminderDays = reminder.getDays().toInteger(); - } - } - - public void copyTo(Habit habit) - { - habit.setId(this.id); - habit.setName(this.name); - habit.setDescription(this.description); - habit.setQuestion(this.question); - habit.setFrequency(new Frequency(this.freqNum, this.freqDen)); - habit.setColor(new PaletteColor(this.color)); - habit.setArchived(this.archived != 0); - habit.setType(this.type); - habit.setTargetType(this.targetType); - habit.setTargetValue(this.targetValue); - habit.setUnit(this.unit); - habit.setPosition(this.position); - habit.setUuid(this.uuid); - - if (reminderHour != null && reminderMin != null) - { - habit.setReminder(new Reminder(reminderHour, reminderMin, - new WeekdayList(reminderDays))); - } - } -} diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt new file mode 100644 index 000000000..942a407a4 --- /dev/null +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt @@ -0,0 +1,138 @@ +/* + * 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.models.sqlite.records + +import org.isoron.uhabits.core.database.Column +import org.isoron.uhabits.core.database.Table +import org.isoron.uhabits.core.models.Frequency +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.core.models.PaletteColor +import org.isoron.uhabits.core.models.Reminder +import org.isoron.uhabits.core.models.WeekdayList +import java.util.Objects + +/** + * The SQLite database record corresponding to a [Habit]. + */ +@Table(name = "habits") +class HabitRecord { + @field:Column + var description: String? = null + + @field:Column + var question: String? = null + + @field:Column + var name: String? = null + + @field:Column(name = "freq_num") + var freqNum: Int? = null + + @field:Column(name = "freq_den") + var freqDen: Int? = null + + @field:Column + var color: Int? = null + + @field:Column + var position: Int? = null + + @field:Column(name = "reminder_hour") + var reminderHour: Int? = null + + @field:Column(name = "reminder_min") + var reminderMin: Int? = null + + @field:Column(name = "reminder_days") + var reminderDays: Int? = null + + @field:Column + var highlight: Int? = null + + @field:Column + var archived: Int? = null + + @field:Column + var type: Int? = null + + @field:Column(name = "target_value") + var targetValue: Double? = null + + @field:Column(name = "target_type") + var targetType: Int? = null + + @field:Column + var unit: String? = null + + @field:Column + var id: Long? = null + + @field:Column + var uuid: String? = null + fun copyFrom(model: Habit?) { + id = model!!.id + name = model.name + description = model.description + highlight = 0 + color = model.color.paletteIndex + archived = if (model.isArchived) 1 else 0 + type = model.type + targetType = model.targetType + targetValue = model.targetValue + unit = model.unit + position = model.position + question = model.question + uuid = model.uuid + val (numerator, denominator) = model.frequency + freqNum = numerator + freqDen = denominator + reminderDays = 0 + reminderMin = null + reminderHour = null + if (model.hasReminder()) { + val reminder = model.reminder + reminderHour = Objects.requireNonNull(reminder)!!.hour + reminderMin = reminder!!.minute + reminderDays = reminder.days.toInteger() + } + } + + fun copyTo(habit: Habit) { + habit.id = id + habit.name = name!! + habit.description = description!! + habit.question = question!! + habit.frequency = Frequency(freqNum!!, freqDen!!) + habit.color = PaletteColor(color!!) + habit.isArchived = archived != 0 + habit.type = type!! + habit.targetType = targetType!! + habit.targetValue = targetValue!! + habit.unit = unit!! + habit.position = position!! + habit.uuid = uuid + if (reminderHour != null && reminderMin != null) { + habit.reminder = Reminder( + reminderHour!!, + reminderMin!!, + WeekdayList(reminderDays!!) + ) + } + } +}