mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
Persist repetition values
This commit is contained in:
@@ -12,7 +12,7 @@ android {
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 25
|
||||
|
||||
buildConfigField "Integer", "databaseVersion", "15"
|
||||
buildConfigField "Integer", "databaseVersion", "16"
|
||||
buildConfigField "String", "databaseFilename", "\"uhabits.db\""
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -37,6 +37,7 @@ import java.util.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.core.IsNot.not;
|
||||
import static org.isoron.uhabits.models.Checkmark.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
@@ -67,7 +68,7 @@ public class SQLiteRepetitionListTest extends BaseAndroidTest
|
||||
RepetitionRecord record = getByTimestamp(today + day);
|
||||
assertThat(record, is(nullValue()));
|
||||
|
||||
Repetition rep = new Repetition(today + day);
|
||||
Repetition rep = new Repetition(today + day, CHECKED_EXPLICITLY);
|
||||
habit.getRepetitions().add(rep);
|
||||
|
||||
record = getByTimestamp(today + day);
|
||||
|
||||
2
app/src/main/assets/migrations/16.sql
Normal file
2
app/src/main/assets/migrations/16.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
alter table Habits add column type integer not null default 0;
|
||||
alter table Repetitions add column value integer not null default 2;
|
||||
@@ -323,7 +323,11 @@ public class HistoryChart extends ScrollableChart
|
||||
int checkmarkOffset)
|
||||
{
|
||||
if (checkmarkOffset >= checkmarks.length) pSquareBg.setColor(colors[0]);
|
||||
else pSquareBg.setColor(colors[checkmarks[checkmarkOffset]]);
|
||||
else
|
||||
{
|
||||
int checkmark = checkmarks[checkmarkOffset];
|
||||
pSquareBg.setColor(colors[Integer.min(2, checkmark)]);
|
||||
}
|
||||
|
||||
pSquareFg.setColor(reverseTextColor);
|
||||
canvas.drawRect(location, pSquareBg);
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package org.isoron.uhabits.activities.habits.list;
|
||||
|
||||
import android.support.annotation.*;
|
||||
import android.util.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.activities.*;
|
||||
@@ -169,9 +168,9 @@ public class ListHabitsController
|
||||
{
|
||||
int oldValue = habit.getCheckmarks().getTodayValue();
|
||||
screen.showNumberPicker(oldValue, newValue -> {
|
||||
Log.d("ListHabitsController",
|
||||
String.format("%s %d %d", habit.getName(), timestamp,
|
||||
newValue));
|
||||
commandRunner.execute(
|
||||
new CreateRepetitionCommand(habit, timestamp, newValue),
|
||||
habit.getId());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -104,11 +104,13 @@ public class HabitCardView extends FrameLayout
|
||||
public void setValues(int values[])
|
||||
{
|
||||
checkmarkPanel.setValues(values);
|
||||
numberPanel.setValues(values);
|
||||
numberPanel.setThreshold(10);
|
||||
|
||||
int[] magnitudes = new int[]{10, 100, 1000, 10000};
|
||||
int threshold = magnitudes[new Random().nextInt(4)];
|
||||
numberPanel.setThreshold(threshold);
|
||||
numberPanel.initEditMode();
|
||||
// int[] magnitudes = new int[]{10, 100, 1000, 10000};
|
||||
// int threshold = magnitudes[new Random().nextInt(4)];
|
||||
// numberPanel.setThreshold(threshold);
|
||||
// numberPanel.initEditMode();
|
||||
|
||||
postInvalidate();
|
||||
}
|
||||
@@ -237,7 +239,7 @@ public class HabitCardView extends FrameLayout
|
||||
checkmarkPanel.setColor(color);
|
||||
numberPanel.setColor(color);
|
||||
|
||||
boolean isNumberHabit = false; //(new Random().nextInt(3) == 0);
|
||||
boolean isNumberHabit = true; //(new Random().nextInt(3) == 0);
|
||||
checkmarkPanel.setVisibility(isNumberHabit ? GONE : VISIBLE);
|
||||
numberPanel.setVisibility(isNumberHabit ? VISIBLE : GONE);
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.commands;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.models.*;
|
||||
|
||||
/**
|
||||
* Command to toggle a repetition.
|
||||
*/
|
||||
public class CreateRepetitionCommand extends Command
|
||||
{
|
||||
@NonNull
|
||||
private final Habit habit;
|
||||
|
||||
private final long timestamp;
|
||||
|
||||
private final int value;
|
||||
|
||||
private Repetition previousRep;
|
||||
|
||||
private Repetition newRep;
|
||||
|
||||
public CreateRepetitionCommand(@NonNull Habit habit,
|
||||
long timestamp,
|
||||
int value)
|
||||
{
|
||||
this.timestamp = timestamp;
|
||||
this.habit = habit;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute()
|
||||
{
|
||||
RepetitionList reps = habit.getRepetitions();
|
||||
|
||||
previousRep = reps.getByTimestamp(timestamp);
|
||||
if (previousRep != null) reps.remove(previousRep);
|
||||
|
||||
newRep = new Repetition(timestamp, value);
|
||||
reps.add(newRep);
|
||||
|
||||
habit.invalidateNewerThan(timestamp);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Habit getHabit()
|
||||
{
|
||||
return habit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo()
|
||||
{
|
||||
habit.getRepetitions().remove(newRep);
|
||||
if (previousRep != null) habit.getRepetitions().add(previousRep);
|
||||
habit.invalidateNewerThan(timestamp);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,9 @@ import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
import static org.isoron.uhabits.models.Checkmark.CHECKED_EXPLICITLY;
|
||||
import static org.isoron.uhabits.models.Checkmark.CHECKED_IMPLICITLY;
|
||||
|
||||
/**
|
||||
* The collection of {@link Checkmark}s belonging to a habit.
|
||||
*/
|
||||
@@ -239,7 +242,7 @@ public abstract class CheckmarkList
|
||||
for (Repetition rep : reps)
|
||||
{
|
||||
int offset = (int) ((rep.getTimestamp() - fromExtended) / day);
|
||||
checks[nDaysExtended - offset - 1] = Checkmark.CHECKED_EXPLICITLY;
|
||||
checks[nDaysExtended - offset - 1] = rep.getValue();
|
||||
}
|
||||
|
||||
for (int i = 0; i < nDays; i++)
|
||||
@@ -247,11 +250,11 @@ public abstract class CheckmarkList
|
||||
int counter = 0;
|
||||
|
||||
for (int j = 0; j < freq.getDenominator(); j++)
|
||||
if (checks[i + j] == 2) counter++;
|
||||
if (checks[i + j] == CHECKED_EXPLICITLY) counter++;
|
||||
|
||||
if (counter >= freq.getNumerator())
|
||||
if (checks[i] != Checkmark.CHECKED_EXPLICITLY)
|
||||
checks[i] = Checkmark.CHECKED_IMPLICITLY;
|
||||
if (checks[i] != CHECKED_EXPLICITLY)
|
||||
checks[i] = CHECKED_IMPLICITLY;
|
||||
}
|
||||
|
||||
List<Checkmark> checkmarks = new LinkedList<>();
|
||||
|
||||
@@ -274,4 +274,11 @@ public class Habit
|
||||
.append("archived", archived)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public void invalidateNewerThan(long timestamp)
|
||||
{
|
||||
getScores().invalidateNewerThan(timestamp);
|
||||
getCheckmarks().invalidateNewerThan(timestamp);
|
||||
getStreaks().invalidateNewerThan(timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ public final class Repetition
|
||||
|
||||
private final long timestamp;
|
||||
|
||||
private final int value;
|
||||
|
||||
/**
|
||||
* Creates a new repetition with given parameters.
|
||||
* <p>
|
||||
@@ -38,9 +40,24 @@ public final class Repetition
|
||||
*
|
||||
* @param timestamp the time this repetition occurred.
|
||||
*/
|
||||
public Repetition(long timestamp)
|
||||
public Repetition(long timestamp, int value)
|
||||
{
|
||||
this.timestamp = timestamp;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Repetition that = (Repetition) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(timestamp, that.timestamp)
|
||||
.append(value, that.value)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
public long getTimestamp()
|
||||
@@ -48,11 +65,26 @@ public final class Repetition
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public int getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(timestamp)
|
||||
.append(value)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return new ToStringBuilder(this)
|
||||
.append("timestamp", timestamp)
|
||||
.append("value", value)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,13 +192,11 @@ public abstract class RepetitionList
|
||||
if (rep != null) remove(rep);
|
||||
else
|
||||
{
|
||||
rep = new Repetition(timestamp);
|
||||
rep = new Repetition(timestamp, Checkmark.CHECKED_EXPLICITLY);
|
||||
add(rep);
|
||||
}
|
||||
|
||||
habit.getScores().invalidateNewerThan(timestamp);
|
||||
habit.getCheckmarks().invalidateNewerThan(timestamp);
|
||||
habit.getStreaks().invalidateNewerThan(timestamp);
|
||||
habit.invalidateNewerThan(timestamp);
|
||||
return rep;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ public class MemoryRepetitionList extends RepetitionList
|
||||
oldestRep = rep;
|
||||
oldestTime = rep.getTimestamp();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return oldestRep;
|
||||
@@ -106,7 +105,6 @@ public class MemoryRepetitionList extends RepetitionList
|
||||
newestRep = rep;
|
||||
newestTime = rep.getTimestamp();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return newestRep;
|
||||
@@ -119,7 +117,6 @@ public class MemoryRepetitionList extends RepetitionList
|
||||
observable.notifyListeners();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public long getTotalCount()
|
||||
{
|
||||
|
||||
@@ -73,7 +73,7 @@ public class SQLiteRepetitionList extends RepetitionList
|
||||
public List<Repetition> getByInterval(long timeFrom, long timeTo)
|
||||
{
|
||||
check(habit.getId());
|
||||
String query = "select habit, timestamp " +
|
||||
String query = "select habit, timestamp, value " +
|
||||
"from Repetitions " +
|
||||
"where habit = ? and timestamp >= ? and timestamp <= ? " +
|
||||
"order by timestamp";
|
||||
@@ -93,7 +93,7 @@ public class SQLiteRepetitionList extends RepetitionList
|
||||
public Repetition getByTimestamp(long timestamp)
|
||||
{
|
||||
check(habit.getId());
|
||||
String query = "select habit, timestamp " +
|
||||
String query = "select habit, timestamp, value " +
|
||||
"from Repetitions " +
|
||||
"where habit = ? and timestamp = ? " +
|
||||
"limit 1";
|
||||
@@ -111,7 +111,7 @@ public class SQLiteRepetitionList extends RepetitionList
|
||||
public Repetition getOldest()
|
||||
{
|
||||
check(habit.getId());
|
||||
String query = "select habit, timestamp " +
|
||||
String query = "select habit, timestamp, value " +
|
||||
"from Repetitions " +
|
||||
"where habit = ? " +
|
||||
"order by timestamp asc " +
|
||||
@@ -129,7 +129,7 @@ public class SQLiteRepetitionList extends RepetitionList
|
||||
public Repetition getNewest()
|
||||
{
|
||||
check(habit.getId());
|
||||
String query = "select habit, timestamp " +
|
||||
String query = "select habit, timestamp, value " +
|
||||
"from Repetitions " +
|
||||
"where habit = ? " +
|
||||
"order by timestamp desc " +
|
||||
@@ -182,7 +182,6 @@ public class SQLiteRepetitionList extends RepetitionList
|
||||
return reps;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public long getTotalCount()
|
||||
{
|
||||
|
||||
@@ -38,6 +38,9 @@ public class RepetitionRecord extends Model implements SQLiteRecord
|
||||
@Column(name = "timestamp")
|
||||
public Long timestamp;
|
||||
|
||||
@Column(name = "value")
|
||||
public int value;
|
||||
|
||||
public static RepetitionRecord get(Long id)
|
||||
{
|
||||
return RepetitionRecord.load(RepetitionRecord.class, id);
|
||||
@@ -46,16 +49,18 @@ public class RepetitionRecord extends Model implements SQLiteRecord
|
||||
public void copyFrom(Repetition repetition)
|
||||
{
|
||||
timestamp = repetition.getTimestamp();
|
||||
value = repetition.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(Cursor c)
|
||||
{
|
||||
timestamp = c.getLong(1);
|
||||
value = c.getInt(2);
|
||||
}
|
||||
|
||||
public Repetition toRepetition()
|
||||
{
|
||||
return new Repetition(timestamp);
|
||||
return new Repetition(timestamp, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.commands;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.junit.*;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
import static org.isoron.uhabits.models.Checkmark.CHECKED_EXPLICITLY;
|
||||
|
||||
public class CreateRepetitionCommandTest extends BaseUnitTest
|
||||
{
|
||||
|
||||
private CreateRepetitionCommand command;
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private long today;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
habit = fixtures.createShortHabit();
|
||||
|
||||
today = DateUtils.getStartOfToday();
|
||||
command = new CreateRepetitionCommand(habit, today, 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteUndoRedo()
|
||||
{
|
||||
RepetitionList reps = habit.getRepetitions();
|
||||
|
||||
Repetition rep = reps.getByTimestamp(today);
|
||||
assertNotNull(rep);
|
||||
assertEquals(CHECKED_EXPLICITLY, rep.getValue());
|
||||
|
||||
command.execute();
|
||||
rep = reps.getByTimestamp(today);
|
||||
assertNotNull(rep);
|
||||
assertEquals(100, rep.getValue());
|
||||
|
||||
command.undo();
|
||||
rep = reps.getByTimestamp(today);
|
||||
assertNotNull(rep);
|
||||
assertEquals(CHECKED_EXPLICITLY, rep.getValue());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user