mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
Refactor Habit
This commit is contained in:
@@ -80,7 +80,7 @@ class IntentSchedulerTest : BaseAndroidTest() {
|
||||
@Test
|
||||
@MediumTest
|
||||
fun testScheduleShowReminder() {
|
||||
for (h in habitList) h.setReminder(null)
|
||||
for (h in habitList) h.reminder = null
|
||||
ReminderReceiver.clearLastReceivedIntent()
|
||||
|
||||
setSystemTime("America/Chicago", 2020, JUNE, 1, 12, 30)
|
||||
|
||||
@@ -60,7 +60,7 @@ public class PerformanceTest extends BaseAndroidTest
|
||||
@Test(timeout = 5000)
|
||||
public void benchmarkCreateHabitCommand()
|
||||
{
|
||||
Database db = ((SQLModelFactory) modelFactory).db;
|
||||
Database db = ((SQLModelFactory) modelFactory).getDatabase();
|
||||
db.beginTransaction();
|
||||
for (int i = 0; i < 1_000; i++)
|
||||
{
|
||||
@@ -75,7 +75,7 @@ public class PerformanceTest extends BaseAndroidTest
|
||||
@Test(timeout = 5000)
|
||||
public void benchmarkCreateRepetitionCommand()
|
||||
{
|
||||
Database db = ((SQLModelFactory) modelFactory).db;
|
||||
Database db = ((SQLModelFactory) modelFactory).getDatabase();
|
||||
db.beginTransaction();
|
||||
Habit habit = fixtures.createEmptyHabit();
|
||||
for (int i = 0; i < 5_000; i++)
|
||||
|
||||
@@ -48,6 +48,8 @@ public class TargetWidgetTest extends BaseViewTest
|
||||
|
||||
habit = fixtures.createLongNumericalHabit();
|
||||
habit.setColor(new PaletteColor(11));
|
||||
habit.setFrequency(Frequency.WEEKLY);
|
||||
habit.invalidateNewerThan(Timestamp.ZERO);
|
||||
TargetWidget widget = new TargetWidget(targetContext, 0, habit);
|
||||
view = convertToView(widget, 400, 400);
|
||||
}
|
||||
|
||||
@@ -73,10 +73,10 @@ class EditHabitActivity : AppCompatActivity() {
|
||||
color = habit.color
|
||||
freqNum = habit.frequency.numerator
|
||||
freqDen = habit.frequency.denominator
|
||||
if (habit.hasReminder()) {
|
||||
reminderHour = habit.reminder.hour
|
||||
reminderMin = habit.reminder.minute
|
||||
reminderDays = habit.reminder.days
|
||||
habit.reminder?.let {
|
||||
reminderHour = it.hour
|
||||
reminderMin = it.minute
|
||||
reminderDays = it.days
|
||||
}
|
||||
binding.nameInput.setText(habit.name)
|
||||
binding.questionInput.setText(habit.question)
|
||||
@@ -210,9 +210,9 @@ class EditHabitActivity : AppCompatActivity() {
|
||||
habit.description = notesInput.text.trim().toString()
|
||||
habit.color = color
|
||||
if (reminderHour >= 0) {
|
||||
habit.setReminder(Reminder(reminderHour, reminderMin, reminderDays))
|
||||
habit.reminder = Reminder(reminderHour, reminderMin, reminderDays)
|
||||
} else {
|
||||
habit.setReminder(null)
|
||||
habit.reminder = null
|
||||
}
|
||||
|
||||
habit.frequency = Frequency(freqNum, freqDen)
|
||||
|
||||
@@ -82,7 +82,7 @@ class SubtitleCardPresenter(
|
||||
|
||||
fun present(): SubtitleCardViewModel {
|
||||
val reminderText = if (habit.hasReminder()) {
|
||||
formatTime(context, habit.reminder.hour, habit.reminder.minute)!!
|
||||
formatTime(context, habit.reminder!!.hour, habit.reminder!!.minute)!!
|
||||
} else {
|
||||
resources.getString(R.string.reminder_off)
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ class TargetCardPresenter(
|
||||
val daysInQuarter = 91
|
||||
val daysInYear = cal.getActualMaximum(Calendar.DAY_OF_YEAR)
|
||||
|
||||
val targetToday = habit.getTargetValue() / habit.frequency.denominator
|
||||
val targetToday = habit.targetValue / habit.frequency.denominator
|
||||
val targetThisWeek = targetToday * 7
|
||||
val targetThisMonth = targetToday * daysInMonth
|
||||
val targetThisQuarter = targetToday * daysInQuarter
|
||||
|
||||
@@ -28,13 +28,13 @@ import org.isoron.uhabits.core.models.*
|
||||
class EditSettingController(private val activity: Activity) {
|
||||
|
||||
fun onSave(habit: Habit, action: Int) {
|
||||
if (habit.getId() == null) return
|
||||
if (habit.id == null) return
|
||||
val actionName = getActionName(action)
|
||||
val blurb = String.format("%s: %s", actionName, habit.name)
|
||||
|
||||
val bundle = Bundle()
|
||||
bundle.putInt("action", action)
|
||||
bundle.putLong("habit", habit.getId()!!)
|
||||
bundle.putLong("habit", habit.id!!)
|
||||
|
||||
activity.setResult(Activity.RESULT_OK, Intent().apply {
|
||||
putExtra(EXTRA_STRING_BLURB, blurb)
|
||||
|
||||
@@ -76,7 +76,7 @@ class PendingIntentFactory
|
||||
timestamp: Long): PendingIntent =
|
||||
PendingIntent.getBroadcast(
|
||||
context,
|
||||
(habit.getId()!! % Integer.MAX_VALUE).toInt() + 1,
|
||||
(habit.id!! % Integer.MAX_VALUE).toInt() + 1,
|
||||
Intent(context, ReminderReceiver::class.java).apply {
|
||||
action = ReminderReceiver.ACTION_SHOW_REMINDER
|
||||
data = Uri.parse(habit.uriString)
|
||||
|
||||
@@ -81,7 +81,7 @@ public class ReminderReceiver extends BroadcastReceiver
|
||||
if (habit == null) return;
|
||||
Log.d("ReminderReceiver", String.format(
|
||||
"onShowReminder habit=%d timestamp=%d reminderTime=%d",
|
||||
habit.id,
|
||||
habit.getId(),
|
||||
timestamp,
|
||||
reminderTime));
|
||||
reminderController.onShowReminder(habit,
|
||||
@@ -90,13 +90,13 @@ public class ReminderReceiver extends BroadcastReceiver
|
||||
|
||||
case ACTION_DISMISS_REMINDER:
|
||||
if (habit == null) return;
|
||||
Log.d("ReminderReceiver", String.format("onDismiss habit=%d", habit.id));
|
||||
Log.d("ReminderReceiver", String.format("onDismiss habit=%d", habit.getId()));
|
||||
reminderController.onDismiss(habit);
|
||||
break;
|
||||
|
||||
case ACTION_SNOOZE_REMINDER:
|
||||
if (habit == null) return;
|
||||
Log.d("ReminderReceiver", String.format("onSnoozePressed habit=%d", habit.id));
|
||||
Log.d("ReminderReceiver", String.format("onSnoozePressed habit=%d", habit.getId()));
|
||||
reminderController.onSnoozePressed(habit, context);
|
||||
break;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ public class ImportDataTask implements Task
|
||||
@Override
|
||||
public void doInBackground()
|
||||
{
|
||||
modelFactory.db.beginTransaction();
|
||||
modelFactory.getDatabase().beginTransaction();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -75,7 +75,7 @@ public class ImportDataTask implements Task
|
||||
{
|
||||
importer.importHabitsFromFile(file);
|
||||
result = SUCCESS;
|
||||
modelFactory.db.setTransactionSuccessful();
|
||||
modelFactory.getDatabase().setTransactionSuccessful();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -88,7 +88,7 @@ public class ImportDataTask implements Task
|
||||
Log.e("ImportDataTask", "Import failed", e);
|
||||
}
|
||||
|
||||
modelFactory.db.endTransaction();
|
||||
modelFactory.getDatabase().endTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -66,7 +66,7 @@ open class CheckmarkWidget(
|
||||
override fun getDefaultWidth() = 125
|
||||
|
||||
private fun getNumericalEntryState(): Int {
|
||||
return if (habit.isCompletedToday) {
|
||||
return if (habit.isCompletedToday()) {
|
||||
Entry.YES_MANUAL
|
||||
} else {
|
||||
Entry.NO
|
||||
|
||||
@@ -119,10 +119,9 @@ public class LoopDBImporter extends AbstractImporter
|
||||
else
|
||||
{
|
||||
Habit modified = modelFactory.buildHabit();
|
||||
habitRecord.id = habit.id;
|
||||
habitRecord.id = habit.getId();
|
||||
habitRecord.copyTo(modified);
|
||||
if (!modified.getData().equals(habit.getData()))
|
||||
new EditHabitCommand(modelFactory, habitList, habit, modified).execute();
|
||||
new EditHabitCommand(modelFactory, habitList, habit, modified).execute();
|
||||
}
|
||||
|
||||
// Reload saved version of the habit
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.*;
|
||||
import javax.annotation.concurrent.*;
|
||||
|
||||
import static org.isoron.uhabits.core.models.Entry.*;
|
||||
import static org.isoron.uhabits.core.models.Habit.*;
|
||||
import static org.isoron.uhabits.core.utils.StringUtils.*;
|
||||
|
||||
/**
|
||||
@@ -39,14 +40,18 @@ import static org.isoron.uhabits.core.utils.StringUtils.*;
|
||||
@ThreadSafe
|
||||
public class EntryList
|
||||
{
|
||||
protected final Habit habit;
|
||||
protected Habit habit = null;
|
||||
|
||||
protected ArrayList<Entry> list;
|
||||
|
||||
public EntryList(Habit habit)
|
||||
public EntryList()
|
||||
{
|
||||
this.list = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void setHabit(Habit habit)
|
||||
{
|
||||
this.habit = habit;
|
||||
this.list = new ArrayList<>();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -425,6 +430,22 @@ public class EntryList
|
||||
return getByInterval(oldest.getTimestamp(), DateUtils.getTodayWithOffset());
|
||||
}
|
||||
|
||||
public boolean isCompletedToday()
|
||||
{
|
||||
int todayCheckmark = getTodayValue();
|
||||
if (habit.isNumerical())
|
||||
{
|
||||
if (habit.getTargetType() == AT_LEAST)
|
||||
return todayCheckmark / 1000.0 >= habit.getTargetValue();
|
||||
else
|
||||
return todayCheckmark / 1000.0 <= habit.getTargetValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
return (todayCheckmark != NO && todayCheckmark != UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
static final class Interval
|
||||
{
|
||||
final Timestamp begin;
|
||||
|
||||
@@ -1,510 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.core.models;
|
||||
|
||||
import androidx.annotation.*;
|
||||
|
||||
import org.apache.commons.lang3.builder.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.annotation.concurrent.*;
|
||||
import javax.inject.*;
|
||||
|
||||
import static org.isoron.uhabits.core.models.Entry.*;
|
||||
import static org.isoron.uhabits.core.utils.StringUtils.defaultToStringStyle;
|
||||
|
||||
/**
|
||||
* The thing that the user wants to track.
|
||||
*/
|
||||
@ThreadSafe
|
||||
public class Habit
|
||||
{
|
||||
public static final int AT_LEAST = 0;
|
||||
|
||||
public static final int AT_MOST = 1;
|
||||
|
||||
public static final String HABIT_URI_FORMAT =
|
||||
"content://org.isoron.uhabits/habit/%d";
|
||||
|
||||
public static final int NUMBER_HABIT = 1;
|
||||
|
||||
public static final int YES_NO_HABIT = 0;
|
||||
|
||||
@Nullable
|
||||
public Long id;
|
||||
|
||||
@NonNull
|
||||
private HabitData data;
|
||||
|
||||
@NonNull
|
||||
private StreakList streaks;
|
||||
|
||||
@NonNull
|
||||
private ScoreList scores;
|
||||
|
||||
@NonNull
|
||||
private RepetitionList repetitions;
|
||||
|
||||
@NonNull
|
||||
private EntryList computedEntries;
|
||||
|
||||
private ModelObservable observable = new ModelObservable();
|
||||
|
||||
/**
|
||||
* Constructs a habit with default data.
|
||||
* <p>
|
||||
* The habit is not archived, not highlighted, has no reminders and is
|
||||
* placed in the last position of the list of habits.
|
||||
*/
|
||||
@Inject
|
||||
Habit(@NonNull ModelFactory factory)
|
||||
{
|
||||
this.data = new HabitData();
|
||||
computedEntries = factory.buildEntryList(this);
|
||||
streaks = factory.buildStreakList(this);
|
||||
scores = factory.buildScoreList(this);
|
||||
repetitions = factory.buildRepetitionList(this);
|
||||
}
|
||||
|
||||
Habit(@NonNull ModelFactory factory, @NonNull HabitData data)
|
||||
{
|
||||
this.data = new HabitData(data);
|
||||
computedEntries = factory.buildEntryList(this);
|
||||
streaks = factory.buildStreakList(this);
|
||||
scores = factory.buildScoreList(this);
|
||||
repetitions = factory.buildRepetitionList(this);
|
||||
observable = new ModelObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the reminder for a habit.
|
||||
*/
|
||||
public synchronized void clearReminder()
|
||||
{
|
||||
data.reminder = null;
|
||||
observable.notifyListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all the attributes of the specified habit into this habit
|
||||
*
|
||||
* @param model the model whose attributes should be copied from
|
||||
*/
|
||||
public synchronized void copyFrom(@NonNull Habit model)
|
||||
{
|
||||
this.data = new HabitData(model.data);
|
||||
observable.notifyListeners();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public synchronized EntryList getComputedEntries()
|
||||
{
|
||||
return computedEntries;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public synchronized PaletteColor getColor()
|
||||
{
|
||||
return data.color;
|
||||
}
|
||||
|
||||
public synchronized void setColor(@NonNull PaletteColor color)
|
||||
{
|
||||
data.color = color;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public synchronized String getDescription()
|
||||
{
|
||||
return data.description;
|
||||
}
|
||||
|
||||
public synchronized void setDescription(@NonNull String description)
|
||||
{
|
||||
data.description = description;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public synchronized Frequency getFrequency()
|
||||
{
|
||||
return data.frequency;
|
||||
}
|
||||
|
||||
public synchronized void setFrequency(@NonNull Frequency frequency)
|
||||
{
|
||||
data.frequency = frequency;
|
||||
invalidateNewerThan(Timestamp.ZERO);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public synchronized Long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public synchronized void setId(@Nullable Long id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public synchronized String getName()
|
||||
{
|
||||
return data.name;
|
||||
}
|
||||
|
||||
public synchronized void setName(@NonNull String name)
|
||||
{
|
||||
data.name = name;
|
||||
}
|
||||
|
||||
public ModelObservable getObservable()
|
||||
{
|
||||
return observable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reminder for this habit.
|
||||
* <p>
|
||||
* Before calling this method, you should call {@link #hasReminder()} to
|
||||
* verify that a reminder does exist, otherwise an exception will be
|
||||
* thrown.
|
||||
*
|
||||
* @return the reminder for this habit
|
||||
* @throws IllegalStateException if habit has no reminder
|
||||
*/
|
||||
@NonNull
|
||||
public synchronized Reminder getReminder()
|
||||
{
|
||||
if (data.reminder == null) throw new IllegalStateException();
|
||||
return data.reminder;
|
||||
}
|
||||
|
||||
public synchronized void setReminder(@Nullable Reminder reminder)
|
||||
{
|
||||
data.reminder = reminder;
|
||||
}
|
||||
|
||||
public RepetitionList getOriginalEntries()
|
||||
{
|
||||
return repetitions;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ScoreList getScores()
|
||||
{
|
||||
return scores;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public StreakList getStreaks()
|
||||
{
|
||||
return streaks;
|
||||
}
|
||||
|
||||
public synchronized int getTargetType()
|
||||
{
|
||||
return data.targetType;
|
||||
}
|
||||
|
||||
public synchronized void setTargetType(int targetType)
|
||||
{
|
||||
if (targetType != AT_LEAST && targetType != AT_MOST)
|
||||
throw new IllegalArgumentException(
|
||||
String.format("invalid targetType: %d", targetType));
|
||||
data.targetType = targetType;
|
||||
}
|
||||
|
||||
public synchronized double getTargetValue()
|
||||
{
|
||||
return data.targetValue;
|
||||
}
|
||||
|
||||
public synchronized void setTargetValue(double targetValue)
|
||||
{
|
||||
if (targetValue < 0) throw new IllegalArgumentException();
|
||||
data.targetValue = targetValue;
|
||||
}
|
||||
|
||||
public synchronized int getType()
|
||||
{
|
||||
return data.type;
|
||||
}
|
||||
|
||||
public synchronized void setType(int type)
|
||||
{
|
||||
if (type != YES_NO_HABIT && type != NUMBER_HABIT)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
data.type = type;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public synchronized String getUnit()
|
||||
{
|
||||
return data.unit;
|
||||
}
|
||||
|
||||
public synchronized void setUnit(@NonNull String unit)
|
||||
{
|
||||
data.unit = unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public URI that identifies this habit
|
||||
*
|
||||
* @return the URI
|
||||
*/
|
||||
public String getUriString()
|
||||
{
|
||||
return String.format(Locale.US, HABIT_URI_FORMAT, getId());
|
||||
}
|
||||
|
||||
public synchronized boolean hasId()
|
||||
{
|
||||
return getId() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the habit has a reminder.
|
||||
*
|
||||
* @return true if habit has reminder, false otherwise
|
||||
*/
|
||||
public synchronized boolean hasReminder()
|
||||
{
|
||||
return data.reminder != null;
|
||||
}
|
||||
|
||||
public void invalidateNewerThan(Timestamp timestamp)
|
||||
{
|
||||
getScores().invalidateNewerThan(timestamp);
|
||||
getComputedEntries().invalidateNewerThan(timestamp);
|
||||
getStreaks().invalidateNewerThan(timestamp);
|
||||
}
|
||||
|
||||
public synchronized boolean isArchived()
|
||||
{
|
||||
return data.archived;
|
||||
}
|
||||
|
||||
public synchronized void setArchived(boolean archived)
|
||||
{
|
||||
data.archived = archived;
|
||||
}
|
||||
|
||||
public synchronized boolean isCompletedToday()
|
||||
{
|
||||
int todayCheckmark = getComputedEntries().getTodayValue();
|
||||
if (isNumerical())
|
||||
{
|
||||
if(getTargetType() == AT_LEAST)
|
||||
return todayCheckmark / 1000.0 >= data.targetValue;
|
||||
else
|
||||
return todayCheckmark / 1000.0 <= data.targetValue;
|
||||
}
|
||||
else return (todayCheckmark != NO && todayCheckmark != UNKNOWN);
|
||||
}
|
||||
|
||||
public synchronized boolean isNumerical()
|
||||
{
|
||||
return data.type == NUMBER_HABIT;
|
||||
}
|
||||
|
||||
public HabitData getData()
|
||||
{
|
||||
return new HabitData(data);
|
||||
}
|
||||
|
||||
public Integer getPosition()
|
||||
{
|
||||
return data.position;
|
||||
}
|
||||
|
||||
public void setPosition(int newPosition)
|
||||
{
|
||||
data.position = newPosition;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getQuestion()
|
||||
{
|
||||
return data.question;
|
||||
}
|
||||
|
||||
public void setQuestion(@NonNull String question)
|
||||
{
|
||||
data.question = question;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getUUID()
|
||||
{
|
||||
return data.uuid;
|
||||
}
|
||||
|
||||
public void setUUID(@NonNull String uuid)
|
||||
{
|
||||
data.uuid = uuid;
|
||||
}
|
||||
|
||||
public static final class HabitData
|
||||
{
|
||||
@NonNull
|
||||
public String name;
|
||||
|
||||
@NonNull
|
||||
public String description;
|
||||
|
||||
@NonNull
|
||||
public String question;
|
||||
|
||||
@NonNull
|
||||
public Frequency frequency;
|
||||
|
||||
public PaletteColor color;
|
||||
|
||||
public boolean archived;
|
||||
|
||||
public int targetType;
|
||||
|
||||
public double targetValue;
|
||||
|
||||
public int type;
|
||||
|
||||
public String uuid;
|
||||
|
||||
@NonNull
|
||||
public String unit;
|
||||
|
||||
@Nullable
|
||||
public Reminder reminder;
|
||||
|
||||
public int position;
|
||||
|
||||
public HabitData()
|
||||
{
|
||||
this.color = new PaletteColor(8);
|
||||
this.archived = false;
|
||||
this.frequency = new Frequency(3, 7);
|
||||
this.type = YES_NO_HABIT;
|
||||
this.name = "";
|
||||
this.description = "";
|
||||
this.question = "";
|
||||
this.targetType = AT_LEAST;
|
||||
this.targetValue = 100;
|
||||
this.unit = "";
|
||||
this.position = 0;
|
||||
this.uuid = UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
|
||||
public HabitData(@NonNull HabitData model)
|
||||
{
|
||||
this.name = model.name;
|
||||
this.description = model.description;
|
||||
this.question = model.question;
|
||||
this.frequency = model.frequency;
|
||||
this.color = model.color;
|
||||
this.archived = model.archived;
|
||||
this.targetType = model.targetType;
|
||||
this.targetValue = model.targetValue;
|
||||
this.type = model.type;
|
||||
this.unit = model.unit;
|
||||
this.reminder = model.reminder;
|
||||
this.position = model.position;
|
||||
this.uuid = model.uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return new ToStringBuilder(this, defaultToStringStyle())
|
||||
.append("name", name)
|
||||
.append("description", description)
|
||||
.append("frequency", frequency)
|
||||
.append("color", color)
|
||||
.append("archived", archived)
|
||||
.append("targetType", targetType)
|
||||
.append("targetValue", targetValue)
|
||||
.append("type", type)
|
||||
.append("unit", unit)
|
||||
.append("reminder", reminder)
|
||||
.append("position", position)
|
||||
.append("question", question)
|
||||
.append("uuid", uuid)
|
||||
.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
HabitData habitData = (HabitData) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(color, habitData.color)
|
||||
.append(archived, habitData.archived)
|
||||
.append(targetType, habitData.targetType)
|
||||
.append(targetValue, habitData.targetValue)
|
||||
.append(type, habitData.type)
|
||||
.append(name, habitData.name)
|
||||
.append(description, habitData.description)
|
||||
.append(frequency, habitData.frequency)
|
||||
.append(unit, habitData.unit)
|
||||
.append(reminder, habitData.reminder)
|
||||
.append(position, habitData.position)
|
||||
.append(question, habitData.question)
|
||||
.append(uuid, habitData.uuid)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(name)
|
||||
.append(description)
|
||||
.append(frequency)
|
||||
.append(color)
|
||||
.append(archived)
|
||||
.append(targetType)
|
||||
.append(targetValue)
|
||||
.append(type)
|
||||
.append(unit)
|
||||
.append(reminder)
|
||||
.append(position)
|
||||
.append(question)
|
||||
.append(uuid)
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return new ToStringBuilder(this, defaultToStringStyle())
|
||||
.append("id", id)
|
||||
.append("data", data)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
package org.isoron.uhabits.core.models
|
||||
|
||||
data class Habit(
|
||||
var color: PaletteColor = PaletteColor(8),
|
||||
var description: String = "",
|
||||
var frequency: Frequency = Frequency.DAILY,
|
||||
var id: Long? = null,
|
||||
var isArchived: Boolean = false,
|
||||
var name: String = "",
|
||||
var position: Int = 0,
|
||||
var question: String = "",
|
||||
var reminder: Reminder? = null,
|
||||
var targetType: Int = AT_LEAST,
|
||||
var targetValue: Double = 0.0,
|
||||
var type: Int = YES_NO_HABIT,
|
||||
var unit: String = "",
|
||||
var uuid: String? = null,
|
||||
val computedEntries: EntryList,
|
||||
val originalEntries: RepetitionList,
|
||||
val scores: ScoreList,
|
||||
val streaks: StreakList,
|
||||
) {
|
||||
var observable = ModelObservable()
|
||||
|
||||
val isNumerical: Boolean
|
||||
get() = type == NUMBER_HABIT
|
||||
|
||||
val uriString: String
|
||||
get() = "content://org.isoron.uhabits/habit/$id"
|
||||
|
||||
fun hasReminder(): Boolean = reminder != null
|
||||
|
||||
fun isCompletedToday(): Boolean = computedEntries.isCompletedToday
|
||||
|
||||
fun invalidateNewerThan(timestamp: Timestamp?) {
|
||||
scores.invalidateNewerThan(timestamp)
|
||||
computedEntries.invalidateNewerThan(timestamp)
|
||||
streaks.invalidateNewerThan(timestamp)
|
||||
}
|
||||
|
||||
fun copyFrom(other: Habit) {
|
||||
this.color = other.color
|
||||
this.description = other.description
|
||||
this.frequency = other.frequency
|
||||
// this.id should not be copied
|
||||
this.isArchived = other.isArchived
|
||||
this.name = other.name
|
||||
this.position = other.position
|
||||
this.question = other.question
|
||||
this.reminder = other.reminder
|
||||
this.targetType = other.targetType
|
||||
this.targetValue = other.targetValue
|
||||
this.type = other.type
|
||||
this.unit = other.unit
|
||||
this.uuid = other.uuid
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Habit) return false
|
||||
|
||||
if (color != other.color) return false
|
||||
if (description != other.description) return false
|
||||
if (frequency != other.frequency) return false
|
||||
if (id != other.id) return false
|
||||
if (isArchived != other.isArchived) return false
|
||||
if (name != other.name) return false
|
||||
if (position != other.position) return false
|
||||
if (question != other.question) return false
|
||||
if (reminder != other.reminder) return false
|
||||
if (targetType != other.targetType) return false
|
||||
if (targetValue != other.targetValue) return false
|
||||
if (type != other.type) return false
|
||||
if (unit != other.unit) return false
|
||||
if (uuid != other.uuid) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = color.hashCode()
|
||||
result = 31 * result + description.hashCode()
|
||||
result = 31 * result + frequency.hashCode()
|
||||
result = 31 * result + (id?.hashCode() ?: 0)
|
||||
result = 31 * result + isArchived.hashCode()
|
||||
result = 31 * result + name.hashCode()
|
||||
result = 31 * result + position
|
||||
result = 31 * result + question.hashCode()
|
||||
result = 31 * result + (reminder?.hashCode() ?: 0)
|
||||
result = 31 * result + targetType
|
||||
result = 31 * result + targetValue.hashCode()
|
||||
result = 31 * result + type
|
||||
result = 31 * result + unit.hashCode()
|
||||
result = 31 * result + (uuid?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val AT_LEAST = 0
|
||||
const val AT_MOST = 1
|
||||
const val NUMBER_HABIT = 1
|
||||
const val YES_NO_HABIT = 0
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.core.models;
|
||||
|
||||
import org.isoron.uhabits.core.database.*;
|
||||
import org.isoron.uhabits.core.models.sqlite.records.*;
|
||||
|
||||
/**
|
||||
* Interface implemented by factories that provide concrete implementations of
|
||||
* the core model classes.
|
||||
*/
|
||||
public interface ModelFactory
|
||||
{
|
||||
EntryList buildEntryList(Habit habit);
|
||||
|
||||
default Habit buildHabit()
|
||||
{
|
||||
return new Habit(this);
|
||||
}
|
||||
|
||||
default Habit buildHabit(Habit.HabitData data)
|
||||
{
|
||||
return new Habit(this, data);
|
||||
}
|
||||
|
||||
HabitList buildHabitList();
|
||||
|
||||
RepetitionList buildRepetitionList(Habit habit);
|
||||
|
||||
ScoreList buildScoreList(Habit habit);
|
||||
|
||||
StreakList buildStreakList(Habit habit);
|
||||
|
||||
Repository<HabitRecord> buildHabitListRepository();
|
||||
|
||||
Repository<RepetitionRecord> buildRepetitionListRepository();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
package org.isoron.uhabits.core.models
|
||||
|
||||
import org.isoron.uhabits.core.database.*
|
||||
import org.isoron.uhabits.core.models.sqlite.records.*
|
||||
|
||||
/**
|
||||
* Interface implemented by factories that provide concrete implementations of
|
||||
* the core model classes.
|
||||
*/
|
||||
interface ModelFactory {
|
||||
|
||||
fun buildHabit(): Habit {
|
||||
val computedEntries = buildEntryList()
|
||||
val originalEntries = buildRepetitionList()
|
||||
val scores = buildScoreList()
|
||||
val streaks = buildStreakList()
|
||||
val habit = Habit(
|
||||
computedEntries = computedEntries,
|
||||
originalEntries = originalEntries,
|
||||
scores = scores,
|
||||
streaks = streaks,
|
||||
)
|
||||
computedEntries.setHabit(habit)
|
||||
originalEntries.setHabit(habit)
|
||||
scores.setHabit(habit)
|
||||
streaks.setHabit(habit)
|
||||
return habit
|
||||
}
|
||||
|
||||
fun buildEntryList(): EntryList
|
||||
fun buildHabitList(): HabitList
|
||||
fun buildRepetitionList(): RepetitionList
|
||||
fun buildScoreList(): ScoreList
|
||||
fun buildStreakList(): StreakList
|
||||
fun buildHabitListRepository(): Repository<HabitRecord>
|
||||
fun buildRepetitionListRepository(): Repository<RepetitionRecord>
|
||||
}
|
||||
@@ -27,12 +27,11 @@ import java.util.*;
|
||||
|
||||
public class RepetitionList
|
||||
{
|
||||
@NonNull
|
||||
protected final Habit habit;
|
||||
protected Habit habit;
|
||||
|
||||
private final ArrayList<Entry> list = new ArrayList<>();
|
||||
|
||||
public RepetitionList(@NonNull Habit habit)
|
||||
public void setHabit(Habit habit)
|
||||
{
|
||||
this.habit = habit;
|
||||
}
|
||||
|
||||
@@ -31,22 +31,13 @@ import static org.isoron.uhabits.core.models.Entry.*;
|
||||
|
||||
public abstract class ScoreList implements Iterable<Score>
|
||||
{
|
||||
protected final Habit habit;
|
||||
protected Habit habit;
|
||||
|
||||
protected ModelObservable observable;
|
||||
protected ModelObservable observable = new ModelObservable();
|
||||
|
||||
/**
|
||||
* Creates a new ScoreList for the given habit.
|
||||
* <p>
|
||||
* The list is populated automatically according to the repetitions that the
|
||||
* habit has.
|
||||
*
|
||||
* @param habit the habit to which the scores belong.
|
||||
*/
|
||||
public ScoreList(Habit habit)
|
||||
public void setHabit(Habit habit)
|
||||
{
|
||||
this.habit = habit;
|
||||
observable = new ModelObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,14 +32,13 @@ import java.util.*;
|
||||
*/
|
||||
public abstract class StreakList
|
||||
{
|
||||
protected final Habit habit;
|
||||
protected Habit habit;
|
||||
|
||||
protected ModelObservable observable;
|
||||
protected ModelObservable observable = new ModelObservable();
|
||||
|
||||
protected StreakList(Habit habit)
|
||||
public void setHabit(Habit habit)
|
||||
{
|
||||
this.habit = habit;
|
||||
observable = new ModelObservable();
|
||||
}
|
||||
|
||||
public abstract List<Streak> getAll();
|
||||
|
||||
@@ -95,7 +95,7 @@ public class MemoryHabitList extends HabitList
|
||||
@Override
|
||||
public synchronized Habit getByUUID(String uuid)
|
||||
{
|
||||
for (Habit h : list) if (h.getUUID().equals(uuid)) return h;
|
||||
for (Habit h : list) if (h.getUuid().equals(uuid)) return h;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ public class MemoryHabitList extends HabitList
|
||||
scoreComparatorDesc.compare(h2, h1);
|
||||
|
||||
Comparator<Habit> positionComparator = (h1, h2) ->
|
||||
h1.getPosition().compareTo(h2.getPosition());
|
||||
Integer.compare(h1.getPosition(), h2.getPosition());
|
||||
|
||||
Comparator<Habit> statusComparatorDesc = (h1, h2) ->
|
||||
{
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.core.models.memory;
|
||||
|
||||
import org.isoron.uhabits.core.database.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.models.sqlite.records.*;
|
||||
|
||||
public class MemoryModelFactory implements ModelFactory
|
||||
{
|
||||
@Override
|
||||
public EntryList buildEntryList(Habit habit)
|
||||
{
|
||||
return new EntryList(habit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HabitList buildHabitList()
|
||||
{
|
||||
return new MemoryHabitList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepetitionList buildRepetitionList(Habit habit)
|
||||
{
|
||||
return new RepetitionList(habit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoreList buildScoreList(Habit habit)
|
||||
{
|
||||
return new MemoryScoreList(habit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreakList buildStreakList(Habit habit)
|
||||
{
|
||||
return new MemoryStreakList(habit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Repository<HabitRecord> buildHabitListRepository()
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Repository<RepetitionRecord> buildRepetitionListRepository()
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
package org.isoron.uhabits.core.models.memory
|
||||
|
||||
import org.isoron.uhabits.core.models.*
|
||||
|
||||
class MemoryModelFactory : ModelFactory {
|
||||
override fun buildEntryList() = EntryList()
|
||||
override fun buildHabitList() = MemoryHabitList()
|
||||
override fun buildRepetitionList() = RepetitionList()
|
||||
override fun buildScoreList() = MemoryScoreList()
|
||||
override fun buildStreakList() = MemoryStreakList()
|
||||
override fun buildHabitListRepository() = throw NotImplementedError()
|
||||
override fun buildRepetitionListRepository() = throw NotImplementedError()
|
||||
}
|
||||
@@ -27,13 +27,7 @@ import java.util.*;
|
||||
|
||||
public class MemoryScoreList extends ScoreList
|
||||
{
|
||||
ArrayList<Score> list;
|
||||
|
||||
public MemoryScoreList(Habit habit)
|
||||
{
|
||||
super(habit);
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
ArrayList<Score> list = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void add(List<Score> scores)
|
||||
|
||||
@@ -27,13 +27,7 @@ import java.util.*;
|
||||
|
||||
public class MemoryStreakList extends StreakList
|
||||
{
|
||||
ArrayList<Streak> list;
|
||||
|
||||
public MemoryStreakList(Habit habit)
|
||||
{
|
||||
super(habit);
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
ArrayList<Streak> list = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public Streak getNewestComputed()
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.core.models.sqlite;
|
||||
|
||||
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 javax.inject.*;
|
||||
|
||||
/**
|
||||
* Factory that provides models backed by an SQLite database.
|
||||
*/
|
||||
public class SQLModelFactory implements ModelFactory
|
||||
{
|
||||
public final Database db;
|
||||
|
||||
@Inject
|
||||
public SQLModelFactory(Database db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntryList buildEntryList(Habit habit)
|
||||
{
|
||||
return new EntryList(habit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HabitList buildHabitList()
|
||||
{
|
||||
return new SQLiteHabitList(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepetitionList buildRepetitionList(Habit habit)
|
||||
{
|
||||
return new SQLiteRepetitionList(habit, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoreList buildScoreList(Habit habit)
|
||||
{
|
||||
return new MemoryScoreList(habit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreakList buildStreakList(Habit habit)
|
||||
{
|
||||
return new MemoryStreakList(habit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Repository<HabitRecord> buildHabitListRepository()
|
||||
{
|
||||
return new Repository<>(HabitRecord.class, db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Repository<RepetitionRecord> buildRepetitionListRepository()
|
||||
{
|
||||
return new Repository<>(RepetitionRecord.class, db);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.isoron.uhabits.core.models.sqlite
|
||||
|
||||
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 javax.inject.*
|
||||
|
||||
/**
|
||||
* Factory that provides models backed by an SQLite database.
|
||||
*/
|
||||
class SQLModelFactory
|
||||
@Inject constructor(
|
||||
val database: Database,
|
||||
) : ModelFactory {
|
||||
|
||||
override fun buildEntryList() = EntryList()
|
||||
override fun buildHabitList() = SQLiteHabitList(this)
|
||||
override fun buildRepetitionList() = SQLiteRepetitionList(this)
|
||||
override fun buildScoreList() = MemoryScoreList()
|
||||
override fun buildStreakList() = MemoryStreakList()
|
||||
|
||||
override fun buildHabitListRepository() =
|
||||
Repository(HabitRecord::class.java, database)
|
||||
|
||||
override fun buildRepetitionListRepository() =
|
||||
Repository(RepetitionRecord::class.java, database)
|
||||
}
|
||||
@@ -91,7 +91,7 @@ public class SQLiteHabitList extends HabitList
|
||||
HabitRecord record = new HabitRecord();
|
||||
record.copyFrom(habit);
|
||||
repository.save(record);
|
||||
habit.id = record.id;
|
||||
habit.setId(record.id);
|
||||
|
||||
list.add(habit);
|
||||
getObservable().notifyListeners();
|
||||
|
||||
@@ -40,10 +40,8 @@ public class SQLiteRepetitionList extends RepetitionList
|
||||
|
||||
private boolean loaded = false;
|
||||
|
||||
public SQLiteRepetitionList(@NonNull Habit habit,
|
||||
@NonNull ModelFactory modelFactory)
|
||||
public SQLiteRepetitionList(@NonNull ModelFactory modelFactory)
|
||||
{
|
||||
super(habit);
|
||||
repository = modelFactory.buildRepetitionListRepository();
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ public class HabitRecord
|
||||
this.unit = model.getUnit();
|
||||
this.position = model.getPosition();
|
||||
this.question = model.getQuestion();
|
||||
this.uuid = model.getUUID();
|
||||
this.uuid = model.getUuid();
|
||||
|
||||
Frequency freq = model.getFrequency();
|
||||
this.freqNum = freq.getNumerator();
|
||||
@@ -130,7 +130,7 @@ public class HabitRecord
|
||||
habit.setTargetValue(this.targetValue);
|
||||
habit.setUnit(this.unit);
|
||||
habit.setPosition(this.position);
|
||||
habit.setUUID(this.uuid);
|
||||
habit.setUuid(this.uuid);
|
||||
|
||||
if (reminderHour != null && reminderMin != null)
|
||||
{
|
||||
|
||||
@@ -74,7 +74,7 @@ public class ReminderScheduler implements CommandRunner.Listener
|
||||
|
||||
if (!habit.hasReminder())
|
||||
{
|
||||
sys.log("ReminderScheduler", "habit=" + habit.id + " has no reminder. Skipping.");
|
||||
sys.log("ReminderScheduler", "habit=" + habit.getId() + " has no reminder. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,17 +107,17 @@ public class ReminderScheduler implements CommandRunner.Listener
|
||||
|
||||
public synchronized void scheduleAtTime(@NonNull Habit habit, long reminderTime)
|
||||
{
|
||||
sys.log("ReminderScheduler", "Scheduling alarm for habit=" + habit.id);
|
||||
sys.log("ReminderScheduler", "Scheduling alarm for habit=" + habit.getId());
|
||||
|
||||
if (!habit.hasReminder())
|
||||
{
|
||||
sys.log("ReminderScheduler", "habit=" + habit.id + " has no reminder. Skipping.");
|
||||
sys.log("ReminderScheduler", "habit=" + habit.getId() + " has no reminder. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (habit.isArchived())
|
||||
{
|
||||
sys.log("ReminderScheduler", "habit=" + habit.id + " is archived. Skipping.");
|
||||
sys.log("ReminderScheduler", "habit=" + habit.getId() + " is archived. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,13 +184,13 @@ public class NotificationTray
|
||||
@Override
|
||||
public void onPostExecute()
|
||||
{
|
||||
systemTray.log("Showing notification for habit=" + habit.id);
|
||||
systemTray.log("Showing notification for habit=" + habit.getId());
|
||||
|
||||
if (todayValue != Entry.UNKNOWN) {
|
||||
systemTray.log(String.format(
|
||||
Locale.US,
|
||||
"Habit %d already checked. Skipping.",
|
||||
habit.id));
|
||||
habit.getId()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ public class NotificationTray
|
||||
systemTray.log(String.format(
|
||||
Locale.US,
|
||||
"Habit %d does not have a reminder. Skipping.",
|
||||
habit.id));
|
||||
habit.getId()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ public class NotificationTray
|
||||
systemTray.log(String.format(
|
||||
Locale.US,
|
||||
"Habit %d is archived. Skipping.",
|
||||
habit.id));
|
||||
habit.getId()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ public class NotificationTray
|
||||
systemTray.log(String.format(
|
||||
Locale.US,
|
||||
"Habit %d not supposed to run today. Skipping.",
|
||||
habit.id));
|
||||
habit.getId()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class ShowHabitBehavior(
|
||||
timestamp,
|
||||
thousands,
|
||||
),
|
||||
habit.getId(),
|
||||
habit.id,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -52,10 +52,9 @@ public class EditHabitCommandTest extends BaseUnitTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteUndoRedo()
|
||||
public void testExecute()
|
||||
{
|
||||
command =
|
||||
new EditHabitCommand(modelFactory, habitList, habit, modified);
|
||||
command = new EditHabitCommand(modelFactory, habitList, habit, modified);
|
||||
|
||||
double originalScore = habit.getScores().getTodayValue();
|
||||
assertThat(habit.getName(), equalTo("original"));
|
||||
@@ -66,7 +65,7 @@ public class EditHabitCommandTest extends BaseUnitTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteUndoRedo_withModifiedInterval()
|
||||
public void testExecute_withModifiedInterval()
|
||||
{
|
||||
modified.setFrequency(Frequency.TWO_TIMES_PER_WEEK);
|
||||
command =
|
||||
|
||||
@@ -72,16 +72,13 @@ public class HabitTest extends BaseUnitTest
|
||||
|
||||
|
||||
@Test
|
||||
public void test_hasReminder_clearReminder()
|
||||
public void test_hasReminder()
|
||||
{
|
||||
Habit h = modelFactory.buildHabit();
|
||||
assertThat(h.hasReminder(), is(false));
|
||||
|
||||
h.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
|
||||
assertThat(h.hasReminder(), is(true));
|
||||
|
||||
h.clearReminder();
|
||||
assertThat(h.hasReminder(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -132,31 +129,9 @@ public class HabitTest extends BaseUnitTest
|
||||
@Test
|
||||
public void testEquals() throws Exception
|
||||
{
|
||||
EqualsVerifier
|
||||
.forClass(Habit.HabitData.class)
|
||||
.suppress(Warning.NONFINAL_FIELDS)
|
||||
.verify();
|
||||
|
||||
EqualsVerifier.forClass(Score.class).verify();
|
||||
EqualsVerifier.forClass(Streak.class).verify();
|
||||
EqualsVerifier.forClass(Reminder.class).verify();
|
||||
EqualsVerifier.forClass(WeekdayList.class).verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() throws Exception
|
||||
{
|
||||
Habit h = modelFactory.buildHabit();
|
||||
h.setUUID("nnnn");
|
||||
h.setReminder(new Reminder(22, 30, WeekdayList.EVERY_DAY));
|
||||
String expected = "{id: <null>, data: {name: , description: ," +
|
||||
" frequency: {numerator: 3, denominator: 7}," +
|
||||
" color: PaletteColor(paletteIndex=8), archived: false, targetType: 0," +
|
||||
" targetValue: 100.0, type: 0, unit: ," +
|
||||
" reminder: {hour: 22, minute: 30," +
|
||||
" days: {weekdays: [true,true,true,true,true,true,true]}}," +
|
||||
" position: 0, question: , uuid: nnnn}}";
|
||||
|
||||
assertThat(h.toString(), equalTo(expected));
|
||||
}
|
||||
}
|
||||
@@ -219,6 +219,7 @@ public class ScoreListTest extends BaseUnitTest
|
||||
|
||||
// Missing 2 repetitions out of 4 per week, the score should converge to 50%
|
||||
habit.setFrequency(new Frequency(4, 7));
|
||||
habit.invalidateNewerThan(Timestamp.ZERO);
|
||||
assertThat(habit.getScores().getTodayValue(), closeTo(0.5, E));
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ public class HabitRecordTest extends BaseUnitTest
|
||||
Habit duplicate = modelFactory.buildHabit();
|
||||
record.copyTo(duplicate);
|
||||
|
||||
assertThat(original.getData(), equalTo(duplicate.getData()));
|
||||
assertThat(original, equalTo(duplicate));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -76,6 +76,6 @@ public class HabitRecordTest extends BaseUnitTest
|
||||
Habit duplicate = modelFactory.buildHabit();
|
||||
record.copyTo(duplicate);
|
||||
|
||||
assertThat(original.getData(), equalTo(duplicate.getData()));
|
||||
assertThat(original, equalTo(duplicate));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class ReminderSchedulerTest extends BaseUnitTest
|
||||
{
|
||||
super.setUp();
|
||||
habit = fixtures.createEmptyHabit();
|
||||
habit.id = habitId;
|
||||
habit.setId(habitId);
|
||||
|
||||
reminderScheduler =
|
||||
new ReminderScheduler(commandRunner, habitList, sys, widgetPreferences);
|
||||
|
||||
@@ -63,7 +63,7 @@ public class WidgetBehaviorTest extends BaseUnitTest
|
||||
behavior.onAddRepetition(habit, timestamp);
|
||||
verify(commandRunner).execute(
|
||||
new CreateRepetitionCommand(habitList, habit, timestamp, YES_MANUAL),
|
||||
habit.id);
|
||||
habit.getId());
|
||||
verify(notificationTray).cancel(habit);
|
||||
verifyZeroInteractions(preferences);
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public class WidgetBehaviorTest extends BaseUnitTest
|
||||
behavior.onRemoveRepetition(habit, timestamp);
|
||||
verify(commandRunner).execute(
|
||||
new CreateRepetitionCommand(habitList, habit, timestamp, NO),
|
||||
habit.id);
|
||||
habit.getId());
|
||||
verify(notificationTray).cancel(habit);
|
||||
verifyZeroInteractions(preferences);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public class WidgetBehaviorTest extends BaseUnitTest
|
||||
verify(preferences).isSkipEnabled();
|
||||
verify(commandRunner).execute(
|
||||
new CreateRepetitionCommand(habitList, habit, timestamp, nextValue),
|
||||
habit.id);
|
||||
habit.getId());
|
||||
verify(notificationTray).cancel(habit);
|
||||
reset(preferences, commandRunner, notificationTray);
|
||||
}
|
||||
@@ -111,7 +111,7 @@ public class WidgetBehaviorTest extends BaseUnitTest
|
||||
behavior.onIncrement(habit, timestamp, 100);
|
||||
verify(commandRunner).execute(
|
||||
new CreateRepetitionCommand(habitList, habit, timestamp, 600),
|
||||
habit.id);
|
||||
habit.getId());
|
||||
verify(notificationTray).cancel(habit);
|
||||
verifyZeroInteractions(preferences);
|
||||
}
|
||||
@@ -125,7 +125,7 @@ public class WidgetBehaviorTest extends BaseUnitTest
|
||||
behavior.onDecrement(habit, timestamp, 100);
|
||||
verify(commandRunner).execute(
|
||||
new CreateRepetitionCommand(habitList, habit, timestamp, 400),
|
||||
habit.id);
|
||||
habit.getId());
|
||||
verify(notificationTray).cancel(habit);
|
||||
verifyZeroInteractions(preferences);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user