mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
Refactor Habit class
This commit is contained in:
@@ -19,8 +19,7 @@
|
||||
|
||||
package org.isoron.uhabits;
|
||||
|
||||
import org.isoron.uhabits.models.Habit;
|
||||
import org.isoron.uhabits.models.HabitList;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.utils.DateUtils;
|
||||
|
||||
public class HabitFixtures
|
||||
@@ -42,8 +41,7 @@ public class HabitFixtures
|
||||
habit.setName("Meditate");
|
||||
habit.setDescription("Did you meditate this morning?");
|
||||
habit.setColor(3);
|
||||
habit.setFreqNum(1);
|
||||
habit.setFreqDen(1);
|
||||
habit.setFrequency(Frequency.DAILY);
|
||||
habitList.add(habit);
|
||||
return habit;
|
||||
}
|
||||
@@ -51,8 +49,7 @@ public class HabitFixtures
|
||||
public Habit createLongHabit()
|
||||
{
|
||||
Habit habit = createEmptyHabit();
|
||||
habit.setFreqNum(3);
|
||||
habit.setFreqDen(7);
|
||||
habit.setFrequency(new Frequency(3, 7));
|
||||
habit.setColor(4);
|
||||
|
||||
long day = DateUtils.millisecondsInOneDay;
|
||||
@@ -72,8 +69,7 @@ public class HabitFixtures
|
||||
Habit habit = new Habit();
|
||||
habit.setName("Wake up early");
|
||||
habit.setDescription("Did you wake up before 6am?");
|
||||
habit.setFreqNum(2);
|
||||
habit.setFreqDen(3);
|
||||
habit.setFrequency(new Frequency(2, 3));
|
||||
habitList.add(habit);
|
||||
|
||||
long timestamp = DateUtils.getStartOfToday();
|
||||
|
||||
@@ -41,6 +41,7 @@ import static org.junit.Assert.*;
|
||||
public class ImportTest extends BaseAndroidTest
|
||||
{
|
||||
private File baseDir;
|
||||
|
||||
private Context context;
|
||||
|
||||
@Before
|
||||
@@ -52,33 +53,72 @@ public class ImportTest extends BaseAndroidTest
|
||||
fixtures.purgeHabits(habitList);
|
||||
context = InstrumentationRegistry.getInstrumentation().getContext();
|
||||
baseDir = FileUtils.getFilesDir("Backups");
|
||||
if(baseDir == null) fail("baseDir should not be null");
|
||||
if (baseDir == null) fail("baseDir should not be null");
|
||||
}
|
||||
|
||||
private void copyAssetToFile(String assetPath, File dst) throws IOException
|
||||
@Test
|
||||
public void testHabitBullCSV() throws IOException
|
||||
{
|
||||
InputStream in = context.getAssets().open(assetPath);
|
||||
FileUtils.copy(in, dst);
|
||||
importFromFile("habitbull.csv");
|
||||
|
||||
List<Habit> habits = habitList.getAll(true);
|
||||
assertThat(habits.size(), equalTo(4));
|
||||
|
||||
Habit habit = habits.get(0);
|
||||
assertThat(habit.getName(), equalTo("Breed dragons"));
|
||||
assertThat(habit.getDescription(), equalTo("with love and fire"));
|
||||
assertThat(habit.getFrequency(), equalTo(Frequency.DAILY));
|
||||
assertTrue(containsRepetition(habit, 2016, 3, 18));
|
||||
assertTrue(containsRepetition(habit, 2016, 3, 19));
|
||||
assertFalse(containsRepetition(habit, 2016, 3, 20));
|
||||
}
|
||||
|
||||
private void importFromFile(String assetFilename) throws IOException
|
||||
@Test
|
||||
public void testLoopDB() throws IOException
|
||||
{
|
||||
File file = new File(String.format("%s/%s", baseDir.getPath(), assetFilename));
|
||||
copyAssetToFile(assetFilename, file);
|
||||
assertTrue(file.exists());
|
||||
assertTrue(file.canRead());
|
||||
importFromFile("loop.db");
|
||||
|
||||
GenericImporter importer = new GenericImporter();
|
||||
assertThat(importer.canHandle(file), is(true));
|
||||
List<Habit> habits = habitList.getAll(true);
|
||||
assertThat(habits.size(), equalTo(9));
|
||||
|
||||
importer.importHabitsFromFile(file);
|
||||
Habit habit = habits.get(0);
|
||||
assertThat(habit.getName(), equalTo("Wake up early"));
|
||||
assertThat(habit.getFrequency(), equalTo(Frequency.THREE_TIMES_PER_WEEK));
|
||||
assertTrue(containsRepetition(habit, 2016, 3, 14));
|
||||
assertTrue(containsRepetition(habit, 2016, 3, 16));
|
||||
assertFalse(containsRepetition(habit, 2016, 3, 17));
|
||||
}
|
||||
|
||||
private boolean containsRepetition(Habit h, int year, int month, int day)
|
||||
@Test
|
||||
public void testRewireDB() throws IOException
|
||||
{
|
||||
GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
|
||||
date.set(year, month - 1, day);
|
||||
return h.getRepetitions().containsTimestamp(date.getTimeInMillis());
|
||||
importFromFile("rewire.db");
|
||||
|
||||
List<Habit> habits = habitList.getAll(true);
|
||||
assertThat(habits.size(), equalTo(3));
|
||||
|
||||
Habit habit = habits.get(0);
|
||||
assertThat(habit.getName(), equalTo("Wake up early"));
|
||||
assertThat(habit.getFrequency(),
|
||||
equalTo(Frequency.THREE_TIMES_PER_WEEK));
|
||||
assertFalse(habit.hasReminder());
|
||||
assertFalse(containsRepetition(habit, 2015, 12, 31));
|
||||
assertTrue(containsRepetition(habit, 2016, 1, 18));
|
||||
assertTrue(containsRepetition(habit, 2016, 1, 28));
|
||||
assertFalse(containsRepetition(habit, 2016, 3, 10));
|
||||
|
||||
habit = habits.get(1);
|
||||
assertThat(habit.getName(), equalTo("brush teeth"));
|
||||
assertThat(habit.getFrequency(),
|
||||
equalTo(Frequency.THREE_TIMES_PER_WEEK));
|
||||
assertThat(habit.hasReminder(), equalTo(true));
|
||||
|
||||
Reminder reminder = habit.getReminder();
|
||||
assertThat(reminder.getHour(), equalTo(8));
|
||||
assertThat(reminder.getMinute(), equalTo(0));
|
||||
boolean[] reminderDays = { false, true, true, true, true, true, false };
|
||||
assertThat(reminder.getDays(),
|
||||
equalTo(DateUtils.packWeekdayList(reminderDays)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -97,69 +137,30 @@ public class ImportTest extends BaseAndroidTest
|
||||
assertFalse(containsRepetition(h, 2016, 3, 14));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRewireDB() throws IOException
|
||||
private boolean containsRepetition(Habit h, int year, int month, int day)
|
||||
{
|
||||
importFromFile("rewire.db");
|
||||
|
||||
List<Habit> habits = habitList.getAll(true);
|
||||
assertThat(habits.size(), equalTo(3));
|
||||
|
||||
Habit habit = habits.get(0);
|
||||
assertThat(habit.getName(), equalTo("Wake up early"));
|
||||
assertThat(habit.getFreqNum(), equalTo(3));
|
||||
assertThat(habit.getFreqDen(), equalTo(7));
|
||||
assertFalse(habit.hasReminder());
|
||||
assertFalse(containsRepetition(habit, 2015, 12, 31));
|
||||
assertTrue(containsRepetition(habit, 2016, 1, 18));
|
||||
assertTrue(containsRepetition(habit, 2016, 1, 28));
|
||||
assertFalse(containsRepetition(habit, 2016, 3, 10));
|
||||
|
||||
habit = habits.get(1);
|
||||
assertThat(habit.getName(), equalTo("brush teeth"));
|
||||
assertThat(habit.getFreqNum(), equalTo(3));
|
||||
assertThat(habit.getFreqDen(), equalTo(7));
|
||||
assertThat(habit.hasReminder(), equalTo(true));
|
||||
|
||||
Reminder reminder = habit.getReminder();
|
||||
assertThat(reminder.getHour(), equalTo(8));
|
||||
assertThat(reminder.getMinute(), equalTo(0));
|
||||
boolean[] reminderDays = {false, true, true, true, true, true, false};
|
||||
assertThat(reminder.getDays(), equalTo(DateUtils.packWeekdayList(reminderDays)));
|
||||
GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
|
||||
date.set(year, month - 1, day);
|
||||
return h.getRepetitions().containsTimestamp(date.getTimeInMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHabitBullCSV() throws IOException
|
||||
private void copyAssetToFile(String assetPath, File dst) throws IOException
|
||||
{
|
||||
importFromFile("habitbull.csv");
|
||||
|
||||
List<Habit> habits = habitList.getAll(true);
|
||||
assertThat(habits.size(), equalTo(4));
|
||||
|
||||
Habit habit = habits.get(0);
|
||||
assertThat(habit.getName(), equalTo("Breed dragons"));
|
||||
assertThat(habit.getDescription(), equalTo("with love and fire"));
|
||||
assertThat(habit.getFreqNum(), equalTo(1));
|
||||
assertThat(habit.getFreqDen(), equalTo(1));
|
||||
assertTrue(containsRepetition(habit, 2016, 3, 18));
|
||||
assertTrue(containsRepetition(habit, 2016, 3, 19));
|
||||
assertFalse(containsRepetition(habit, 2016, 3, 20));
|
||||
InputStream in = context.getAssets().open(assetPath);
|
||||
FileUtils.copy(in, dst);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopDB() throws IOException
|
||||
private void importFromFile(String assetFilename) throws IOException
|
||||
{
|
||||
importFromFile("loop.db");
|
||||
File file =
|
||||
new File(String.format("%s/%s", baseDir.getPath(), assetFilename));
|
||||
copyAssetToFile(assetFilename, file);
|
||||
assertTrue(file.exists());
|
||||
assertTrue(file.canRead());
|
||||
|
||||
List<Habit> habits = habitList.getAll(true);
|
||||
assertThat(habits.size(), equalTo(9));
|
||||
GenericImporter importer = new GenericImporter();
|
||||
assertThat(importer.canHandle(file), is(true));
|
||||
|
||||
Habit habit = habits.get(0);
|
||||
assertThat(habit.getName(), equalTo("Wake up early"));
|
||||
assertThat(habit.getFreqNum(), equalTo(3));
|
||||
assertThat(habit.getFreqDen(), equalTo(7));
|
||||
assertTrue(containsRepetition(habit, 2016, 3, 14));
|
||||
assertTrue(containsRepetition(habit, 2016, 3, 16));
|
||||
assertFalse(containsRepetition(habit, 2016, 3, 17));
|
||||
importer.importHabitsFromFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class SQLiteHabitListTest extends BaseAndroidTest
|
||||
Habit h = new Habit();
|
||||
h.setName("habit " + i);
|
||||
h.setId((long) i);
|
||||
if (i % 2 == 0) h.setArchived(1);
|
||||
if (i % 2 == 0) h.setArchived(true);
|
||||
|
||||
HabitRecord record = new HabitRecord();
|
||||
record.copyFrom(h);
|
||||
|
||||
@@ -67,7 +67,7 @@ public class SQLiteRepetitionListTest extends BaseAndroidTest
|
||||
RepetitionRecord record = getByTimestamp(today + day);
|
||||
assertThat(record, is(nullValue()));
|
||||
|
||||
Repetition rep = new Repetition(habit, today + day);
|
||||
Repetition rep = new Repetition(today + day);
|
||||
habit.getRepetitions().add(rep);
|
||||
|
||||
record = getByTimestamp(today + day);
|
||||
@@ -91,7 +91,6 @@ public class SQLiteRepetitionListTest extends BaseAndroidTest
|
||||
{
|
||||
Repetition rep = repetitions.getByTimestamp(today);
|
||||
assertThat(rep, is(not(nullValue())));
|
||||
assertThat(rep.getHabit(), equalTo(habit));
|
||||
assertThat(rep.getTimestamp(), equalTo(today));
|
||||
|
||||
rep = repetitions.getByTimestamp(today - 2 * day);
|
||||
@@ -103,7 +102,6 @@ public class SQLiteRepetitionListTest extends BaseAndroidTest
|
||||
{
|
||||
Repetition rep = repetitions.getOldest();
|
||||
assertThat(rep, is(not(nullValue())));
|
||||
assertThat(rep.getHabit(), equalTo(habit));
|
||||
assertThat(rep.getTimestamp(), equalTo(today - 120 * day));
|
||||
}
|
||||
|
||||
|
||||
@@ -92,9 +92,9 @@ public class SQLiteScoreListTest extends BaseAndroidTest
|
||||
new Delete().from(ScoreRecord.class).execute();
|
||||
|
||||
List<Score> list = new LinkedList<>();
|
||||
list.add(new Score(habit, today, 0));
|
||||
list.add(new Score(habit, today - day, 0));
|
||||
list.add(new Score(habit, today - 2 * day, 0));
|
||||
list.add(new Score(today, 0));
|
||||
list.add(new Score(today - day, 0));
|
||||
list.add(new Score(today - 2 * day, 0));
|
||||
|
||||
scores.add(list);
|
||||
|
||||
|
||||
@@ -47,14 +47,14 @@ public class ArchiveHabitsCommand extends Command
|
||||
@Override
|
||||
public void execute()
|
||||
{
|
||||
for(Habit h : habits) h.setArchived(1);
|
||||
for(Habit h : habits) h.setArchived(true);
|
||||
habitList.update(habits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo()
|
||||
{
|
||||
for(Habit h : habits) h.setArchived(0);
|
||||
for(Habit h : habits) h.setArchived(false);
|
||||
habitList.update(habits);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,10 @@
|
||||
|
||||
package org.isoron.uhabits.commands;
|
||||
|
||||
import org.isoron.uhabits.HabitsApplication;
|
||||
import org.isoron.uhabits.R;
|
||||
import org.isoron.uhabits.models.Habit;
|
||||
import org.isoron.uhabits.models.HabitList;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.*;
|
||||
|
||||
/**
|
||||
* Command to modify a habit.
|
||||
@@ -40,7 +38,7 @@ public class EditHabitCommand extends Command
|
||||
|
||||
private long savedId;
|
||||
|
||||
private boolean hasIntervalChanged;
|
||||
private boolean hasFrequencyChanged;
|
||||
|
||||
public EditHabitCommand(Habit original, Habit modified)
|
||||
{
|
||||
@@ -53,9 +51,9 @@ public class EditHabitCommand extends Command
|
||||
this.modified.copyFrom(modified);
|
||||
this.original.copyFrom(original);
|
||||
|
||||
hasIntervalChanged =
|
||||
(!this.original.getFreqDen().equals(this.modified.getFreqDen()) ||
|
||||
!this.original.getFreqNum().equals(this.modified.getFreqNum()));
|
||||
Frequency originalFreq = this.original.getFrequency();
|
||||
Frequency modifiedFreq = this.modified.getFrequency();
|
||||
hasFrequencyChanged = (!originalFreq.equals(modifiedFreq));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,7 +93,7 @@ public class EditHabitCommand extends Command
|
||||
|
||||
private void invalidateIfNeeded(Habit habit)
|
||||
{
|
||||
if (hasIntervalChanged)
|
||||
if (hasFrequencyChanged)
|
||||
{
|
||||
habit.getCheckmarks().invalidateNewerThan(0);
|
||||
habit.getStreaks().invalidateNewerThan(0);
|
||||
|
||||
@@ -47,14 +47,14 @@ public class UnarchiveHabitsCommand extends Command
|
||||
@Override
|
||||
public void execute()
|
||||
{
|
||||
for(Habit h : habits) h.setArchived(0);
|
||||
for(Habit h : habits) h.setArchived(false);
|
||||
habitList.update(habits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo()
|
||||
{
|
||||
for(Habit h : habits) h.setArchived(1);
|
||||
for(Habit h : habits) h.setArchived(true);
|
||||
habitList.update(habits);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import android.support.annotation.NonNull;
|
||||
import com.activeandroid.ActiveAndroid;
|
||||
import com.opencsv.CSVReader;
|
||||
|
||||
import org.isoron.uhabits.models.Habit;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.utils.DateUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@@ -94,8 +94,7 @@ public class HabitBullCSVImporter extends AbstractImporter
|
||||
h = new Habit();
|
||||
h.setName(name);
|
||||
h.setDescription(description);
|
||||
h.setFreqDen(1);
|
||||
h.setFreqNum(1);
|
||||
h.setFrequency(Frequency.DAILY);
|
||||
habitList.add(h);
|
||||
habits.put(name, h);
|
||||
}
|
||||
|
||||
@@ -133,25 +133,30 @@ public class RewireDBImporter extends AbstractImporter
|
||||
habit.setDescription(description);
|
||||
|
||||
int periods[] = { 7, 31, 365 };
|
||||
int numerator, denominator;
|
||||
|
||||
switch (schedule)
|
||||
{
|
||||
case 0:
|
||||
habit.setFreqNum(activeDays.split(",").length);
|
||||
habit.setFreqDen(7);
|
||||
numerator = activeDays.split(",").length;
|
||||
denominator = 7;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
habit.setFreqNum(days);
|
||||
habit.setFreqDen(periods[periodIndex]);
|
||||
numerator = days;
|
||||
denominator = (periods[periodIndex]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
habit.setFreqNum(1);
|
||||
habit.setFreqDen(repeatingCount);
|
||||
numerator = 1;
|
||||
denominator = repeatingCount;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
habit.setFrequency(new Frequency(numerator, denominator));
|
||||
habitList.add(habit);
|
||||
|
||||
createReminder(db, habit, id);
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.isoron.uhabits.models.Habit;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.utils.DatabaseUtils;
|
||||
import org.isoron.uhabits.utils.DateUtils;
|
||||
|
||||
@@ -117,8 +117,7 @@ public class TickmateDBImporter extends AbstractImporter
|
||||
Habit habit = new Habit();
|
||||
habit.setName(name);
|
||||
habit.setDescription(description);
|
||||
habit.setFreqNum(1);
|
||||
habit.setFreqDen(1);
|
||||
habit.setFrequency(Frequency.DAILY);
|
||||
habitList.add(habit);
|
||||
|
||||
createCheckmarks(db, habit, id);
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.apache.commons.lang3.builder.*;
|
||||
* <p>
|
||||
* Checkmarks are computed automatically from the list of repetitions.
|
||||
*/
|
||||
public class Checkmark
|
||||
public final class Checkmark
|
||||
{
|
||||
/**
|
||||
* Indicates that there was a repetition at the timestamp.
|
||||
|
||||
@@ -189,7 +189,9 @@ public abstract class CheckmarkList
|
||||
|
||||
if (from > to) return;
|
||||
|
||||
long fromExtended = from - (long) (habit.getFreqDen()) * day;
|
||||
Frequency freq = habit.getFrequency();
|
||||
|
||||
long fromExtended = from - (long) (freq.getDenominator()) * day;
|
||||
List<Repetition> reps =
|
||||
habit.getRepetitions().getByInterval(fromExtended, to);
|
||||
|
||||
@@ -207,10 +209,10 @@ public abstract class CheckmarkList
|
||||
{
|
||||
int counter = 0;
|
||||
|
||||
for (int j = 0; j < habit.getFreqDen(); j++)
|
||||
for (int j = 0; j < freq.getDenominator(); j++)
|
||||
if (checks[i + j] == 2) counter++;
|
||||
|
||||
if (counter >= habit.getFreqNum())
|
||||
if (counter >= freq.getNumerator())
|
||||
if (checks[i] != Checkmark.CHECKED_EXPLICITLY)
|
||||
checks[i] = Checkmark.CHECKED_IMPLICITLY;
|
||||
}
|
||||
|
||||
97
app/src/main/java/org/isoron/uhabits/models/Frequency.java
Normal file
97
app/src/main/java/org/isoron/uhabits/models/Frequency.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.models;
|
||||
|
||||
import org.apache.commons.lang3.builder.*;
|
||||
|
||||
/**
|
||||
* Represents how often is the habit repeated.
|
||||
*/
|
||||
public class Frequency
|
||||
{
|
||||
public static final Frequency DAILY = new Frequency(1, 1);
|
||||
|
||||
public static final Frequency FIVE_TIMES_PER_WEEK = new Frequency(5, 7);
|
||||
|
||||
public static final Frequency THREE_TIMES_PER_WEEK = new Frequency(3, 7);
|
||||
|
||||
public static final Frequency TWO_TIMES_PER_WEEK = new Frequency(2, 7);
|
||||
|
||||
public static final Frequency WEEKLY = new Frequency(1, 7);
|
||||
|
||||
private final int numerator;
|
||||
|
||||
private final int denominator;
|
||||
|
||||
public Frequency(int numerator, int denominator)
|
||||
{
|
||||
if (numerator == denominator) numerator = denominator = 1;
|
||||
|
||||
this.numerator = numerator;
|
||||
this.denominator = denominator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Frequency frequency = (Frequency) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(numerator, frequency.numerator)
|
||||
.append(denominator, frequency.denominator)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
public int getDenominator()
|
||||
{
|
||||
return denominator;
|
||||
}
|
||||
|
||||
public int getNumerator()
|
||||
{
|
||||
return numerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(numerator)
|
||||
.append(denominator)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
public double toDouble()
|
||||
{
|
||||
return (double) numerator / denominator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return new ToStringBuilder(this)
|
||||
.append("numerator", numerator)
|
||||
.append("denominator", denominator)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -47,19 +47,13 @@ public class Habit
|
||||
private String description;
|
||||
|
||||
@NonNull
|
||||
private Integer freqNum;
|
||||
|
||||
@NonNull
|
||||
private Integer freqDen;
|
||||
private Frequency frequency;
|
||||
|
||||
@NonNull
|
||||
private Integer color;
|
||||
|
||||
@NonNull
|
||||
private Integer highlight;
|
||||
|
||||
@NonNull
|
||||
private Integer archived;
|
||||
private boolean archived;
|
||||
|
||||
@NonNull
|
||||
private StreakList streaks;
|
||||
@@ -109,10 +103,8 @@ public class Habit
|
||||
HabitsApplication.getComponent().inject(this);
|
||||
|
||||
this.color = 5;
|
||||
this.highlight = 0;
|
||||
this.archived = 0;
|
||||
this.freqDen = 7;
|
||||
this.freqNum = 3;
|
||||
this.archived = false;
|
||||
this.frequency = new Frequency(3, 7);
|
||||
|
||||
checkmarks = factory.buildCheckmarkList(this);
|
||||
streaks = factory.buildStreakList(this);
|
||||
@@ -139,24 +131,13 @@ public class Habit
|
||||
{
|
||||
this.name = model.getName();
|
||||
this.description = model.getDescription();
|
||||
this.freqNum = model.getFreqNum();
|
||||
this.freqDen = model.getFreqDen();
|
||||
this.color = model.getColor();
|
||||
this.archived = model.isArchived();
|
||||
this.frequency = model.frequency;
|
||||
this.reminder = model.reminder;
|
||||
this.highlight = model.getHighlight();
|
||||
this.archived = model.getArchived();
|
||||
observable.notifyListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag that indicates whether the habit is archived. Archived habits are
|
||||
* usually omitted from listings, unless explicitly included.
|
||||
*/
|
||||
public Integer getArchived()
|
||||
{
|
||||
return archived;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of checkmarks belonging to this habit.
|
||||
*/
|
||||
@@ -179,21 +160,11 @@ public class Habit
|
||||
return color;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Reminder getReminder()
|
||||
{
|
||||
if(reminder == null) throw new IllegalStateException();
|
||||
return reminder;
|
||||
}
|
||||
|
||||
public void setColor(Integer color)
|
||||
{
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of the habit
|
||||
*/
|
||||
public String getDescription()
|
||||
{
|
||||
return description;
|
||||
@@ -204,46 +175,15 @@ public class Habit
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency denominator. If a habit is performed 3 times in 7 days, this
|
||||
* field equals 7.
|
||||
*/
|
||||
public Integer getFreqDen()
|
||||
{
|
||||
return freqDen;
|
||||
}
|
||||
|
||||
public void setFreqDen(Integer freqDen)
|
||||
{
|
||||
this.freqDen = freqDen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency numerator. If a habit is performed 3 times in 7 days, this
|
||||
* field equals 3.
|
||||
*/
|
||||
public Integer getFreqNum()
|
||||
{
|
||||
return freqNum;
|
||||
}
|
||||
|
||||
public void setFreqNum(@NonNull Integer freqNum)
|
||||
{
|
||||
this.freqNum = freqNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not currently used.
|
||||
*/
|
||||
@NonNull
|
||||
public Integer getHighlight()
|
||||
public Frequency getFrequency()
|
||||
{
|
||||
return highlight;
|
||||
return frequency;
|
||||
}
|
||||
|
||||
public void setHighlight(@NonNull Integer highlight)
|
||||
public void setFrequency(@NonNull Frequency frequency)
|
||||
{
|
||||
this.highlight = highlight;
|
||||
this.frequency = frequency;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -257,9 +197,6 @@ public class Habit
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the habit
|
||||
*/
|
||||
@NonNull
|
||||
public String getName()
|
||||
{
|
||||
@@ -277,26 +214,39 @@ public class Habit
|
||||
}
|
||||
|
||||
/**
|
||||
* List of repetitions belonging to this habit.
|
||||
* 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 Reminder getReminder()
|
||||
{
|
||||
if (reminder == null) throw new IllegalStateException();
|
||||
return reminder;
|
||||
}
|
||||
|
||||
public void setReminder(@Nullable Reminder reminder)
|
||||
{
|
||||
this.reminder = reminder;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public RepetitionList getRepetitions()
|
||||
{
|
||||
return repetitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of scores belonging to this habit.
|
||||
*/
|
||||
@NonNull
|
||||
public ScoreList getScores()
|
||||
{
|
||||
return scores;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of streaks belonging to this habit.
|
||||
*/
|
||||
@NonNull
|
||||
public StreakList getStreaks()
|
||||
{
|
||||
@@ -315,7 +265,7 @@ public class Habit
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the habit has a reminder set.
|
||||
* Returns whether the habit has a reminder.
|
||||
*
|
||||
* @return true if habit has reminder, false otherwise
|
||||
*/
|
||||
@@ -324,26 +274,16 @@ public class Habit
|
||||
return reminder != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the habit is archived or not.
|
||||
*
|
||||
* @return true if archived
|
||||
*/
|
||||
public boolean isArchived()
|
||||
{
|
||||
return archived != 0;
|
||||
return archived;
|
||||
}
|
||||
|
||||
public void setArchived(@NonNull Integer archived)
|
||||
public void setArchived(boolean archived)
|
||||
{
|
||||
this.archived = archived;
|
||||
}
|
||||
|
||||
public void setReminder(@Nullable Reminder reminder)
|
||||
{
|
||||
this.reminder = reminder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
@@ -351,10 +291,7 @@ public class Habit
|
||||
.append("id", id)
|
||||
.append("name", name)
|
||||
.append("description", description)
|
||||
.append("freqNum", freqNum)
|
||||
.append("freqDen", freqDen)
|
||||
.append("color", color)
|
||||
.append("highlight", highlight)
|
||||
.append("archived", archived)
|
||||
.toString();
|
||||
}
|
||||
|
||||
@@ -208,12 +208,14 @@ public abstract class HabitList
|
||||
|
||||
for (Habit habit : getAll(true))
|
||||
{
|
||||
Frequency freq = habit.getFrequency();
|
||||
|
||||
String[] cols = {
|
||||
String.format("%03d", indexOf(habit) + 1),
|
||||
habit.getName(),
|
||||
habit.getDescription(),
|
||||
Integer.toString(habit.getFreqNum()),
|
||||
Integer.toString(habit.getFreqDen()),
|
||||
Integer.toString(freq.getNumerator()),
|
||||
Integer.toString(freq.getDenominator()),
|
||||
ColorUtils.CSV_PALETTE[habit.getColor()]
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.*;
|
||||
*/
|
||||
public class ModelObservable
|
||||
{
|
||||
List<Listener> listeners;
|
||||
private List<Listener> listeners;
|
||||
|
||||
/**
|
||||
* Creates a new ModelObservable with no listeners.
|
||||
@@ -62,7 +62,7 @@ public class ModelObservable
|
||||
* Removes the given listener.
|
||||
* <p>
|
||||
* The listener will no longer be notified when the model changes. If the
|
||||
* given listener is not subscrined to this observable, does nothing.
|
||||
* given listener is not subscribed to this observable, does nothing.
|
||||
*
|
||||
* @param l the listener to be removed
|
||||
*/
|
||||
@@ -77,6 +77,10 @@ public class ModelObservable
|
||||
*/
|
||||
public interface Listener
|
||||
{
|
||||
/**
|
||||
* Called whenever the model associated to this observable has been
|
||||
* modified.
|
||||
*/
|
||||
void onModelChange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package org.isoron.uhabits.models;
|
||||
|
||||
public class Reminder
|
||||
public final class Reminder
|
||||
{
|
||||
private final int hour;
|
||||
|
||||
|
||||
@@ -19,18 +19,14 @@
|
||||
|
||||
package org.isoron.uhabits.models;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import org.apache.commons.lang3.builder.*;
|
||||
|
||||
/**
|
||||
* Represents a record that the user has performed a certain habit at a certain
|
||||
* date.
|
||||
*/
|
||||
public class Repetition
|
||||
public final class Repetition
|
||||
{
|
||||
@NonNull
|
||||
private final Habit habit;
|
||||
|
||||
private final long timestamp;
|
||||
|
||||
@@ -40,20 +36,13 @@ public class Repetition
|
||||
* The timestamp corresponds to the days this repetition occurred. Time of
|
||||
* day must be midnight (UTC).
|
||||
*
|
||||
* @param habit the habit to which this repetition belongs.
|
||||
* @param timestamp the time this repetition occurred.
|
||||
*/
|
||||
public Repetition(Habit habit, long timestamp)
|
||||
public Repetition(long timestamp)
|
||||
{
|
||||
this.habit = habit;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public Habit getHabit()
|
||||
{
|
||||
return habit;
|
||||
}
|
||||
|
||||
public long getTimestamp()
|
||||
{
|
||||
return timestamp;
|
||||
|
||||
@@ -21,7 +21,6 @@ package org.isoron.uhabits.models;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
import java.util.*;
|
||||
@@ -183,7 +182,7 @@ public abstract class RepetitionList
|
||||
if (rep != null) remove(rep);
|
||||
else
|
||||
{
|
||||
rep = new Repetition(habit, timestamp);
|
||||
rep = new Repetition(timestamp);
|
||||
add(rep);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,18 +24,13 @@ import org.apache.commons.lang3.builder.*;
|
||||
/**
|
||||
* Represents how strong a habit is at a certain date.
|
||||
*/
|
||||
public class Score
|
||||
public final class Score
|
||||
{
|
||||
/**
|
||||
* Maximum score value attainable by any habit.
|
||||
*/
|
||||
public static final int MAX_VALUE = 19259478;
|
||||
|
||||
/**
|
||||
* Habit to which this score belongs to.
|
||||
*/
|
||||
private Habit habit;
|
||||
|
||||
/**
|
||||
* Timestamp of the day to which this score applies. Time of day should be
|
||||
* midnight (UTC).
|
||||
@@ -47,9 +42,8 @@ public class Score
|
||||
*/
|
||||
private final Integer value;
|
||||
|
||||
public Score(Habit habit, Long timestamp, Integer value)
|
||||
public Score(Long timestamp, Integer value)
|
||||
{
|
||||
this.habit = habit;
|
||||
this.timestamp = timestamp;
|
||||
this.value = value;
|
||||
}
|
||||
@@ -91,11 +85,6 @@ public class Score
|
||||
return Long.signum(this.getTimestamp() - other.getTimestamp());
|
||||
}
|
||||
|
||||
public Habit getHabit()
|
||||
{
|
||||
return habit;
|
||||
}
|
||||
|
||||
public Long getTimestamp()
|
||||
{
|
||||
return timestamp;
|
||||
|
||||
@@ -157,7 +157,7 @@ public abstract class ScoreList implements Iterable<Score>
|
||||
protected void compute(long from, long to)
|
||||
{
|
||||
final long day = DateUtils.millisecondsInOneDay;
|
||||
final double freq = ((double) habit.getFreqNum()) / habit.getFreqDen();
|
||||
final double freq = habit.getFrequency().toDouble();
|
||||
|
||||
int newestValue = 0;
|
||||
long newestTimestamp = 0;
|
||||
@@ -181,7 +181,7 @@ public abstract class ScoreList implements Iterable<Score>
|
||||
{
|
||||
int value = checkmarkValues[checkmarkValues.length - i - 1];
|
||||
lastScore = Score.compute(freq, lastScore, value);
|
||||
scores.add(new Score(habit, beginning + day * i, lastScore));
|
||||
scores.add(new Score(beginning + day * i, lastScore));
|
||||
}
|
||||
|
||||
add(scores);
|
||||
@@ -241,7 +241,7 @@ public abstract class ScoreList implements Iterable<Score>
|
||||
for (Long v : groupValues) meanValue += v;
|
||||
meanValue /= groupValues.size();
|
||||
|
||||
scores.add(new Score(habit, timestamp, (int) meanValue));
|
||||
scores.add(new Score(timestamp, (int) meanValue));
|
||||
}
|
||||
|
||||
return scores;
|
||||
|
||||
@@ -22,17 +22,14 @@ package org.isoron.uhabits.models;
|
||||
import org.apache.commons.lang3.builder.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
public class Streak
|
||||
public final class Streak
|
||||
{
|
||||
private Habit habit;
|
||||
private final long start;
|
||||
|
||||
private long start;
|
||||
private final long end;
|
||||
|
||||
private long end;
|
||||
|
||||
public Streak(Habit habit, long start, long end)
|
||||
public Streak(long start, long end)
|
||||
{
|
||||
this.habit = habit;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
@@ -55,11 +52,6 @@ public class Streak
|
||||
return end;
|
||||
}
|
||||
|
||||
public Habit getHabit()
|
||||
{
|
||||
return habit;
|
||||
}
|
||||
|
||||
public long getLength()
|
||||
{
|
||||
return (end - start) / DateUtils.millisecondsInOneDay + 1;
|
||||
|
||||
@@ -97,7 +97,7 @@ public abstract class StreakList
|
||||
{
|
||||
long start = transitions.get(i);
|
||||
long end = transitions.get(i + 1);
|
||||
streaks.add(new Streak(habit, start, end));
|
||||
streaks.add(new Streak(start, end));
|
||||
}
|
||||
|
||||
return streaks;
|
||||
|
||||
@@ -57,8 +57,11 @@ public class SQLiteRepetitionList extends RepetitionList
|
||||
@Override
|
||||
public void add(Repetition rep)
|
||||
{
|
||||
check(habit.getId());
|
||||
|
||||
RepetitionRecord record = new RepetitionRecord();
|
||||
record.copyFrom(rep);
|
||||
record.habit = habitRecord;
|
||||
record.save();
|
||||
observable.notifyListeners();
|
||||
}
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
package org.isoron.uhabits.models.sqlite;
|
||||
|
||||
import android.support.annotation.*;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.activeandroid.query.*;
|
||||
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.models.sqlite.records.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -34,21 +36,29 @@ import java.util.*;
|
||||
*/
|
||||
public class SQLiteStreakList extends StreakList
|
||||
{
|
||||
private HabitRecord habitRecord;
|
||||
|
||||
@NonNull
|
||||
private final SQLiteUtils<StreakRecord> sqlite;
|
||||
|
||||
public SQLiteStreakList(Habit habit)
|
||||
{
|
||||
super(habit);
|
||||
sqlite = new SQLiteUtils<>(StreakRecord.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Streak> getAll()
|
||||
{
|
||||
check(habit.getId());
|
||||
rebuild();
|
||||
List<StreakRecord> records = new Select()
|
||||
.from(StreakRecord.class)
|
||||
.where("habit = ?", habit.getId())
|
||||
.orderBy("end desc")
|
||||
.execute();
|
||||
|
||||
String query = StreakRecord.SELECT + "where habit = ? " +
|
||||
"order by end desc";
|
||||
|
||||
String params[] = { Long.toString(habit.getId())};
|
||||
|
||||
List<StreakRecord> records = sqlite.query(query, params);
|
||||
return recordsToStreaks(records);
|
||||
}
|
||||
|
||||
@@ -75,11 +85,14 @@ public class SQLiteStreakList extends StreakList
|
||||
@Override
|
||||
protected void add(@NonNull List<Streak> streaks)
|
||||
{
|
||||
check(habit.getId());
|
||||
|
||||
DatabaseUtils.executeAsTransaction(() -> {
|
||||
for (Streak streak : streaks)
|
||||
{
|
||||
StreakRecord record = new StreakRecord();
|
||||
record.copyFrom(streak);
|
||||
record.habit = habitRecord;
|
||||
record.save();
|
||||
}
|
||||
});
|
||||
@@ -95,12 +108,15 @@ public class SQLiteStreakList extends StreakList
|
||||
@Nullable
|
||||
private StreakRecord getNewestRecord()
|
||||
{
|
||||
return new Select()
|
||||
.from(StreakRecord.class)
|
||||
.where("habit = ?", habit.getId())
|
||||
.orderBy("end desc")
|
||||
.limit(1)
|
||||
.executeSingle();
|
||||
check(habit.getId());
|
||||
String query = StreakRecord.SELECT + "where habit = ? " +
|
||||
"order by end desc " +
|
||||
"limit 1 ";
|
||||
String params[] = { habit.getId().toString() };
|
||||
StreakRecord record = sqlite.querySingle(query, params);
|
||||
if (record != null) record.habit = habitRecord;
|
||||
return record;
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -109,8 +125,22 @@ public class SQLiteStreakList extends StreakList
|
||||
LinkedList<Streak> streaks = new LinkedList<>();
|
||||
|
||||
for (StreakRecord record : records)
|
||||
{
|
||||
record.habit = habitRecord;
|
||||
streaks.add(record.toStreak());
|
||||
}
|
||||
|
||||
return streaks;
|
||||
}
|
||||
|
||||
@Contract("null -> fail")
|
||||
private void check(Long id)
|
||||
{
|
||||
if (id == null) throw new RuntimeException("habit is not saved");
|
||||
|
||||
if(habitRecord != null) return;
|
||||
|
||||
habitRecord = HabitRecord.get(id);
|
||||
if (habitRecord == null) throw new RuntimeException("habit not found");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,9 +142,13 @@ public class HabitRecord extends Model implements SQLiteRecord
|
||||
{
|
||||
this.name = model.getName();
|
||||
this.description = model.getDescription();
|
||||
this.freqNum = model.getFreqNum();
|
||||
this.freqDen = model.getFreqDen();
|
||||
this.highlight = 0;
|
||||
this.color = model.getColor();
|
||||
this.archived = model.isArchived() ? 1 : 0;
|
||||
Frequency freq = model.getFrequency();
|
||||
this.freqNum = freq.getNumerator();
|
||||
this.freqDen = freq.getDenominator();
|
||||
|
||||
if(model.hasReminder())
|
||||
{
|
||||
Reminder reminder = model.getReminder();
|
||||
@@ -152,8 +156,6 @@ public class HabitRecord extends Model implements SQLiteRecord
|
||||
this.reminderMin = reminder.getMinute();
|
||||
this.reminderDays = reminder.getDays();
|
||||
}
|
||||
this.highlight = model.getHighlight();
|
||||
this.archived = model.getArchived();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,11 +179,9 @@ public class HabitRecord extends Model implements SQLiteRecord
|
||||
{
|
||||
habit.setName(this.name);
|
||||
habit.setDescription(this.description);
|
||||
habit.setFreqNum(this.freqNum);
|
||||
habit.setFreqDen(this.freqDen);
|
||||
habit.setFrequency(new Frequency(this.freqNum, this.freqDen));
|
||||
habit.setColor(this.color);
|
||||
habit.setHighlight(this.highlight);
|
||||
habit.setArchived(this.archived);
|
||||
habit.setArchived(this.archived != 0);
|
||||
habit.setId(this.getId());
|
||||
|
||||
if (reminderHour != null && reminderMin != null)
|
||||
@@ -204,8 +204,6 @@ public class HabitRecord extends Model implements SQLiteRecord
|
||||
|
||||
private void setId(Long id)
|
||||
{
|
||||
// HACK: The id field is declared private by ActiveAndroid and
|
||||
// there are no setters. (WTF?)
|
||||
try
|
||||
{
|
||||
Field f = (Model.class).getDeclaredField("mId");
|
||||
|
||||
@@ -46,7 +46,6 @@ public class RepetitionRecord extends Model implements SQLiteRecord
|
||||
|
||||
public void copyFrom(Repetition repetition)
|
||||
{
|
||||
habit = HabitRecord.get(repetition.getHabit().getId());
|
||||
timestamp = repetition.getTimestamp();
|
||||
}
|
||||
|
||||
@@ -60,6 +59,6 @@ public class RepetitionRecord extends Model implements SQLiteRecord
|
||||
{
|
||||
SQLiteHabitList habitList = SQLiteHabitList.getInstance();
|
||||
Habit h = habitList.getById(habit.getId());
|
||||
return new Repetition(h, timestamp);
|
||||
return new Repetition(timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,6 @@ public class ScoreRecord extends Model implements SQLiteRecord
|
||||
{
|
||||
SQLiteHabitList habitList = SQLiteHabitList.getInstance();
|
||||
Habit h = habitList.getById(habit.getId());
|
||||
return new Score(h, timestamp, score);
|
||||
return new Score(timestamp, score);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,18 +19,24 @@
|
||||
|
||||
package org.isoron.uhabits.models.sqlite.records;
|
||||
|
||||
import android.database.*;
|
||||
|
||||
import com.activeandroid.*;
|
||||
import com.activeandroid.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.models.sqlite.*;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
|
||||
/**
|
||||
* The SQLite database record corresponding to a Streak.
|
||||
*/
|
||||
@Table(name = "Streak")
|
||||
public class StreakRecord extends Model
|
||||
public class StreakRecord extends Model implements SQLiteRecord
|
||||
{
|
||||
public static final String SELECT = "select id, start, end, length from Streak ";
|
||||
|
||||
@Column(name = "habit")
|
||||
public HabitRecord habit;
|
||||
|
||||
@@ -50,16 +56,38 @@ public class StreakRecord extends Model
|
||||
|
||||
public void copyFrom(Streak streak)
|
||||
{
|
||||
habit = HabitRecord.get(streak.getHabit().getId());
|
||||
start = streak.getStart();
|
||||
end = streak.getEnd();
|
||||
length = streak.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(Cursor c)
|
||||
{
|
||||
setId(c.getLong(0));
|
||||
start = c.getLong(1);
|
||||
end = c.getLong(2);
|
||||
length = c.getLong(3);
|
||||
}
|
||||
|
||||
private void setId(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field f = (Model.class).getDeclaredField("mId");
|
||||
f.setAccessible(true);
|
||||
f.set(this, id);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Streak toStreak()
|
||||
{
|
||||
SQLiteHabitList habitList = SQLiteHabitList.getInstance();
|
||||
Habit h = habitList.getById(habit.getId());
|
||||
return new Streak(h, start, end);
|
||||
return new Streak(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +83,7 @@ public abstract class BaseDialogFragment extends AppCompatDialogFragment
|
||||
if (position < 0 || position > 4) throw new IllegalArgumentException();
|
||||
int freqNums[] = { 1, 1, 2, 5, 3 };
|
||||
int freqDens[] = { 1, 7, 7, 7, 7 };
|
||||
modifiedHabit.setFreqNum(freqNums[position]);
|
||||
modifiedHabit.setFreqDen(freqDens[position]);
|
||||
modifiedHabit.setFrequency(new Frequency(freqNums[position], freqDens[position]));
|
||||
helper.populateFrequencyFields(modifiedHabit);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,8 +84,12 @@ public class BaseDialogHelper
|
||||
habit.setDescription(tvDescription.getText().toString().trim());
|
||||
String freqNum = tvFreqNum.getText().toString();
|
||||
String freqDen = tvFreqDen.getText().toString();
|
||||
if (!freqNum.isEmpty()) habit.setFreqNum(Integer.parseInt(freqNum));
|
||||
if (!freqDen.isEmpty()) habit.setFreqDen(Integer.parseInt(freqDen));
|
||||
if (!freqNum.isEmpty() && !freqDen.isEmpty())
|
||||
{
|
||||
int numerator = Integer.parseInt(freqNum);
|
||||
int denominator = Integer.parseInt(freqDen);
|
||||
habit.setFrequency(new Frequency(numerator, denominator));
|
||||
}
|
||||
}
|
||||
|
||||
void populateColor(int paletteColor)
|
||||
@@ -99,16 +103,18 @@ public class BaseDialogHelper
|
||||
{
|
||||
int quickSelectPosition = -1;
|
||||
|
||||
if (habit.getFreqNum().equals(habit.getFreqDen()))
|
||||
Frequency freq = habit.getFrequency();
|
||||
|
||||
if (freq.equals(Frequency.DAILY))
|
||||
quickSelectPosition = 0;
|
||||
|
||||
else if (habit.getFreqNum() == 1 && habit.getFreqDen() == 7)
|
||||
else if (freq.equals(Frequency.WEEKLY))
|
||||
quickSelectPosition = 1;
|
||||
|
||||
else if (habit.getFreqNum() == 2 && habit.getFreqDen() == 7)
|
||||
else if (freq.equals(Frequency.TWO_TIMES_PER_WEEK))
|
||||
quickSelectPosition = 2;
|
||||
|
||||
else if (habit.getFreqNum() == 5 && habit.getFreqDen() == 7)
|
||||
else if (freq.equals(Frequency.FIVE_TIMES_PER_WEEK))
|
||||
quickSelectPosition = 3;
|
||||
|
||||
if (quickSelectPosition >= 0)
|
||||
@@ -116,8 +122,8 @@ public class BaseDialogHelper
|
||||
|
||||
else showCustomFrequency();
|
||||
|
||||
tvFreqNum.setText(habit.getFreqNum().toString());
|
||||
tvFreqDen.setText(habit.getFreqDen().toString());
|
||||
tvFreqNum.setText(Integer.toString(freq.getNumerator()));
|
||||
tvFreqDen.setText(Integer.toString(freq.getDenominator()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@@ -138,8 +144,7 @@ public class BaseDialogHelper
|
||||
tvReminderTime.setText(time);
|
||||
llReminderDays.setVisibility(View.VISIBLE);
|
||||
|
||||
boolean weekdays[] =
|
||||
DateUtils.unpackWeekdayList(reminder.getDays());
|
||||
boolean weekdays[] = DateUtils.unpackWeekdayList(reminder.getDays());
|
||||
tvReminderDays.setText(
|
||||
DateUtils.formatWeekdayList(frag.getContext(), weekdays));
|
||||
}
|
||||
@@ -169,14 +174,16 @@ public class BaseDialogHelper
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (habit.getFreqNum() <= 0)
|
||||
Frequency freq = habit.getFrequency();
|
||||
|
||||
if (freq.getNumerator() <= 0)
|
||||
{
|
||||
tvFreqNum.setError(
|
||||
frag.getString(R.string.validation_number_should_be_positive));
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (habit.getFreqNum() > habit.getFreqDen())
|
||||
if (freq.getNumerator() > freq.getDenominator())
|
||||
{
|
||||
tvFreqNum.setError(
|
||||
frag.getString(R.string.validation_at_most_one_rep_per_day));
|
||||
|
||||
@@ -19,11 +19,9 @@
|
||||
|
||||
package org.isoron.uhabits.ui.habits.edit;
|
||||
|
||||
import org.isoron.uhabits.HabitsApplication;
|
||||
import org.isoron.uhabits.R;
|
||||
import org.isoron.uhabits.commands.Command;
|
||||
import org.isoron.uhabits.commands.CreateHabitCommand;
|
||||
import org.isoron.uhabits.models.Habit;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.commands.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
|
||||
public class CreateHabitDialogFragment extends BaseDialogFragment
|
||||
{
|
||||
@@ -37,8 +35,7 @@ public class CreateHabitDialogFragment extends BaseDialogFragment
|
||||
protected void initializeHabits()
|
||||
{
|
||||
modifiedHabit = new Habit();
|
||||
modifiedHabit.setFreqNum(1);
|
||||
modifiedHabit.setFreqDen(1);
|
||||
modifiedHabit.setFrequency(Frequency.DAILY);
|
||||
modifiedHabit.setColor(
|
||||
prefs.getDefaultHabitColor(modifiedHabit.getColor()));
|
||||
}
|
||||
|
||||
@@ -42,8 +42,9 @@ public class ShowHabitHelper
|
||||
if (fragment.habit == null) return "";
|
||||
|
||||
Resources resources = fragment.getResources();
|
||||
Integer freqNum = fragment.habit.getFreqNum();
|
||||
Integer freqDen = fragment.habit.getFreqDen();
|
||||
Frequency freq = fragment.habit.getFrequency();
|
||||
Integer freqNum = freq.getNumerator();
|
||||
Integer freqDen = freq.getDenominator();
|
||||
|
||||
if (freqNum.equals(freqDen))
|
||||
return resources.getString(R.string.every_day);
|
||||
|
||||
@@ -425,7 +425,7 @@ public class HabitScoreView extends ScrollableDataView
|
||||
int step = Score.MAX_VALUE / 10;
|
||||
int current = previous + random.nextInt(step * 2) - step;
|
||||
current = Math.max(0, Math.min(Score.MAX_VALUE, current));
|
||||
scores.add(new Score(habit, timestamp, current));
|
||||
scores.add(new Score(timestamp, current));
|
||||
previous = current;
|
||||
timestamp -= day;
|
||||
}
|
||||
|
||||
@@ -43,8 +43,7 @@ public class EditHabitCommandTest extends BaseUnitTest
|
||||
|
||||
habit = fixtures.createShortHabit();
|
||||
habit.setName("original");
|
||||
habit.setFreqDen(1);
|
||||
habit.setFreqNum(1);
|
||||
habit.setFrequency(Frequency.DAILY);
|
||||
|
||||
modified = new Habit();
|
||||
modified.copyFrom(habit);
|
||||
@@ -75,8 +74,7 @@ public class EditHabitCommandTest extends BaseUnitTest
|
||||
@Test
|
||||
public void testExecuteUndoRedo_withModifiedInterval()
|
||||
{
|
||||
modified.setFreqNum(1);
|
||||
modified.setFreqDen(7);
|
||||
modified.setFrequency(Frequency.TWO_TIMES_PER_WEEK);
|
||||
command = new EditHabitCommand(habit, modified);
|
||||
|
||||
int originalScore = habit.getScores().getTodayValue();
|
||||
|
||||
@@ -39,7 +39,7 @@ public class UnarchiveHabitsCommandTest extends BaseUnitTest
|
||||
super.setUp();
|
||||
|
||||
habit = fixtures.createShortHabit();
|
||||
habit.setArchived(1);
|
||||
habit.setArchived(true);
|
||||
habitList.update(habit);
|
||||
|
||||
command = new UnarchiveHabitsCommand(Collections.singletonList(habit));
|
||||
|
||||
@@ -40,8 +40,7 @@ public class HabitFixtures
|
||||
habit.setName("Meditate");
|
||||
habit.setDescription("Did you meditate this morning?");
|
||||
habit.setColor(3);
|
||||
habit.setFreqNum(1);
|
||||
habit.setFreqDen(1);
|
||||
habit.setFrequency(Frequency.DAILY);
|
||||
habitList.add(habit);
|
||||
return habit;
|
||||
}
|
||||
@@ -49,8 +48,7 @@ public class HabitFixtures
|
||||
public Habit createLongHabit()
|
||||
{
|
||||
Habit habit = createEmptyHabit();
|
||||
habit.setFreqNum(3);
|
||||
habit.setFreqDen(7);
|
||||
habit.setFrequency(new Frequency(3, 7));
|
||||
habit.setColor(4);
|
||||
|
||||
long day = DateUtils.millisecondsInOneDay;
|
||||
@@ -70,8 +68,7 @@ public class HabitFixtures
|
||||
Habit habit = new Habit();
|
||||
habit.setName("Wake up early");
|
||||
habit.setDescription("Did you wake up before 6am?");
|
||||
habit.setFreqNum(2);
|
||||
habit.setFreqDen(3);
|
||||
habit.setFrequency(new Frequency(2, 3));
|
||||
habitList.add(habit);
|
||||
|
||||
long timestamp = DateUtils.getStartOfToday();
|
||||
|
||||
@@ -57,10 +57,10 @@ public class HabitListTest extends BaseUnitTest
|
||||
habit.setReminder(new Reminder(8, 30, DateUtils.ALL_WEEK_DAYS));
|
||||
}
|
||||
|
||||
habits.get(0).setArchived(1);
|
||||
habits.get(1).setArchived(1);
|
||||
habits.get(4).setArchived(1);
|
||||
habits.get(7).setArchived(1);
|
||||
habits.get(0).setArchived(true);
|
||||
habits.get(1).setArchived(true);
|
||||
habits.get(4).setArchived(true);
|
||||
habits.get(7).setArchived(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -166,15 +166,13 @@ public class HabitListTest extends BaseUnitTest
|
||||
Habit h1 = new Habit();
|
||||
h1.setName("Meditate");
|
||||
h1.setDescription("Did you meditate this morning?");
|
||||
h1.setFreqNum(1);
|
||||
h1.setFreqDen(1);
|
||||
h1.setFrequency(Frequency.DAILY);
|
||||
h1.setColor(3);
|
||||
|
||||
Habit h2 = new Habit();
|
||||
h2.setName("Wake up early");
|
||||
h2.setDescription("Did you wake up before 6am?");
|
||||
h2.setFreqNum(2);
|
||||
h2.setFreqDen(3);
|
||||
h2.setFrequency(new Frequency(2, 3));
|
||||
h2.setColor(5);
|
||||
|
||||
list.add(h1);
|
||||
|
||||
@@ -27,6 +27,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.core.IsNot.not;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class HabitTest extends BaseUnitTest
|
||||
@@ -36,8 +37,7 @@ public class HabitTest extends BaseUnitTest
|
||||
public void testConstructor_default()
|
||||
{
|
||||
Habit habit = new Habit();
|
||||
assertThat(habit.getArchived(), is(0));
|
||||
assertThat(habit.getHighlight(), is(0));
|
||||
assertFalse(habit.isArchived());
|
||||
|
||||
assertThat(habit.hasReminder(), is(false));
|
||||
assertThat(habit.getStreaks(), is(not(nullValue())));
|
||||
@@ -50,20 +50,16 @@ public class HabitTest extends BaseUnitTest
|
||||
public void test_copyAttributes()
|
||||
{
|
||||
Habit model = new Habit();
|
||||
model.setArchived(1);
|
||||
model.setHighlight(1);
|
||||
model.setArchived(true);
|
||||
model.setColor(0);
|
||||
model.setFreqNum(10);
|
||||
model.setFreqDen(20);
|
||||
model.setFrequency(new Frequency(10, 20));
|
||||
model.setReminder(new Reminder(8, 30, 1));
|
||||
|
||||
Habit habit = new Habit();
|
||||
habit.copyFrom(model);
|
||||
assertThat(habit.getArchived(), is(model.getArchived()));
|
||||
assertThat(habit.getHighlight(), is(model.getHighlight()));
|
||||
assertThat(habit.isArchived(), is(model.isArchived()));
|
||||
assertThat(habit.getColor(), is(model.getColor()));
|
||||
assertThat(habit.getFreqNum(), is(model.getFreqNum()));
|
||||
assertThat(habit.getFreqDen(), is(model.getFreqDen()));
|
||||
assertThat(habit.getFrequency(), equalTo(model.getFrequency()));
|
||||
assertThat(habit.getReminder(), equalTo(model.getReminder()));
|
||||
}
|
||||
|
||||
|
||||
@@ -147,8 +147,7 @@ public class ScoreListTest extends BaseUnitTest
|
||||
toggleRepetitions(0, 2);
|
||||
assertThat(habit.getScores().getTodayValue(), equalTo(1948077));
|
||||
|
||||
habit.setFreqNum(1);
|
||||
habit.setFreqDen(2);
|
||||
habit.setFrequency(new Frequency(1, 2));
|
||||
habit.getScores().invalidateNewerThan(0);
|
||||
|
||||
assertThat(habit.getScores().getTodayValue(), equalTo(1974654));
|
||||
|
||||
@@ -46,8 +46,7 @@ public class StreakListTest extends BaseUnitTest
|
||||
{
|
||||
super.setUp();
|
||||
habit = fixtures.createLongHabit();
|
||||
habit.setFreqDen(1);
|
||||
habit.setFreqNum(1);
|
||||
habit.setFrequency(Frequency.DAILY);
|
||||
|
||||
streaks = habit.getStreaks();
|
||||
streaks.rebuild();
|
||||
|
||||
Reference in New Issue
Block a user