mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Replace ActiveAndroid queries with raw SQLite queries
This commit is contained in:
@@ -58,6 +58,7 @@ dependencies {
|
|||||||
compile 'org.apmem.tools:layouts:1.10@aar'
|
compile 'org.apmem.tools:layouts:1.10@aar'
|
||||||
compile 'com.opencsv:opencsv:3.7'
|
compile 'com.opencsv:opencsv:3.7'
|
||||||
compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
|
compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
|
||||||
|
compile 'org.jetbrains:annotations-java5:15.0'
|
||||||
|
|
||||||
compile 'com.jakewharton:butterknife:8.0.1'
|
compile 'com.jakewharton:butterknife:8.0.1'
|
||||||
apt 'com.jakewharton:butterknife-compiler:8.0.1'
|
apt 'com.jakewharton:butterknife-compiler:8.0.1'
|
||||||
|
|||||||
@@ -19,18 +19,18 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits;
|
package org.isoron.uhabits;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.*;
|
||||||
import android.content.Context;
|
import android.content.*;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.*;
|
||||||
|
|
||||||
import com.activeandroid.ActiveAndroid;
|
import com.activeandroid.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.HabitList;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.utils.DatabaseUtils;
|
import org.isoron.uhabits.utils.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Android application for Loop Habit Tracker.
|
* The Android application for Loop Habit Tracker.
|
||||||
@@ -92,7 +92,7 @@ public class HabitsApplication extends Application
|
|||||||
{
|
{
|
||||||
if (context != null) context
|
if (context != null) context
|
||||||
.getClassLoader()
|
.getClassLoader()
|
||||||
.loadClass("org.isoron.uhabits.unit.models.HabitTest");
|
.loadClass("org.isoron.uhabits.BaseAndroidTest");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (final Exception e)
|
catch (final Exception e)
|
||||||
|
|||||||
@@ -21,13 +21,14 @@ package org.isoron.uhabits.models.sqlite;
|
|||||||
|
|
||||||
import android.database.sqlite.*;
|
import android.database.sqlite.*;
|
||||||
import android.support.annotation.*;
|
import android.support.annotation.*;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import com.activeandroid.*;
|
import com.activeandroid.*;
|
||||||
import com.activeandroid.query.*;
|
import com.activeandroid.query.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.*;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.models.sqlite.records.*;
|
import org.isoron.uhabits.models.sqlite.records.*;
|
||||||
import org.isoron.uhabits.utils.*;
|
import org.jetbrains.annotations.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -36,14 +37,23 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class SQLiteCheckmarkList extends CheckmarkList
|
public class SQLiteCheckmarkList extends CheckmarkList
|
||||||
{
|
{
|
||||||
|
@Nullable
|
||||||
|
private HabitRecord habitRecord;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final SQLiteUtils<CheckmarkRecord> sqlite;
|
||||||
|
|
||||||
public SQLiteCheckmarkList(Habit habit)
|
public SQLiteCheckmarkList(Habit habit)
|
||||||
{
|
{
|
||||||
super(habit);
|
super(habit);
|
||||||
|
sqlite = new SQLiteUtils<>(CheckmarkRecord.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(List<Checkmark> checkmarks)
|
public void add(List<Checkmark> checkmarks)
|
||||||
{
|
{
|
||||||
|
check(habit.getId());
|
||||||
|
|
||||||
String query =
|
String query =
|
||||||
"insert into Checkmarks(habit, timestamp, value) values (?,?,?)";
|
"insert into Checkmarks(habit, timestamp, value) values (?,?,?)";
|
||||||
|
|
||||||
@@ -69,16 +79,26 @@ public class SQLiteCheckmarkList extends CheckmarkList
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public List<Checkmark> getByInterval(long fromTimestamp, long toTimestamp)
|
public List<Checkmark> getByInterval(long fromTimestamp, long toTimestamp)
|
||||||
{
|
{
|
||||||
|
check(habit.getId());
|
||||||
computeAll();
|
computeAll();
|
||||||
|
|
||||||
List<CheckmarkRecord> records = select()
|
String query = "select habit, timestamp, value " +
|
||||||
.and("timestamp >= ?", fromTimestamp)
|
"from checkmarks " +
|
||||||
.and("timestamp <= ?", toTimestamp)
|
"where habit = ? and timestamp >= ? and timestamp <= ? " +
|
||||||
.execute();
|
"order by timestamp desc";
|
||||||
|
|
||||||
|
String params[] = {
|
||||||
|
Long.toString(habit.getId()),
|
||||||
|
Long.toString(fromTimestamp),
|
||||||
|
Long.toString(toTimestamp)
|
||||||
|
};
|
||||||
|
|
||||||
|
List<CheckmarkRecord> records = sqlite.query(query, params);
|
||||||
|
for (CheckmarkRecord record : records) record.habit = habitRecord;
|
||||||
return toCheckmarks(records);
|
return toCheckmarks(records);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,19 +118,31 @@ public class SQLiteCheckmarkList extends CheckmarkList
|
|||||||
@Nullable
|
@Nullable
|
||||||
protected Checkmark getNewestComputed()
|
protected Checkmark getNewestComputed()
|
||||||
{
|
{
|
||||||
CheckmarkRecord record = select().limit(1).executeSingle();
|
check(habit.getId());
|
||||||
|
|
||||||
|
String query = "select habit, timestamp, value " +
|
||||||
|
"from checkmarks " +
|
||||||
|
"where habit = ? " +
|
||||||
|
"order by timestamp desc " +
|
||||||
|
"limit 1";
|
||||||
|
|
||||||
|
String params[] = { Long.toString(habit.getId()) };
|
||||||
|
|
||||||
|
CheckmarkRecord record = sqlite.querySingle(query, params);
|
||||||
if (record == null) return null;
|
if (record == null) return null;
|
||||||
|
record.habit = habitRecord;
|
||||||
return record.toCheckmark();
|
return record.toCheckmark();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@Contract("null -> fail")
|
||||||
private From select()
|
private void check(Long id)
|
||||||
{
|
{
|
||||||
return new Select()
|
if (id == null) throw new RuntimeException("habit is not saved");
|
||||||
.from(CheckmarkRecord.class)
|
|
||||||
.where("habit = ?", habit.getId())
|
if (habitRecord != null) return;
|
||||||
.and("timestamp <= ?", DateUtils.getStartOfToday())
|
|
||||||
.orderBy("timestamp desc");
|
habitRecord = HabitRecord.get(id);
|
||||||
|
if (habitRecord == null) throw new RuntimeException("habit not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|||||||
@@ -19,8 +19,10 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.models.sqlite;
|
package org.isoron.uhabits.models.sqlite;
|
||||||
|
|
||||||
|
import android.database.sqlite.*;
|
||||||
import android.support.annotation.*;
|
import android.support.annotation.*;
|
||||||
|
|
||||||
|
import com.activeandroid.*;
|
||||||
import com.activeandroid.query.*;
|
import com.activeandroid.query.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.*;
|
import org.isoron.uhabits.models.*;
|
||||||
@@ -37,9 +39,13 @@ public class SQLiteHabitList extends HabitList
|
|||||||
|
|
||||||
private HashMap<Long, Habit> cache;
|
private HashMap<Long, Habit> cache;
|
||||||
|
|
||||||
|
private final SQLiteUtils<HabitRecord> sqlite;
|
||||||
|
|
||||||
|
|
||||||
private SQLiteHabitList()
|
private SQLiteHabitList()
|
||||||
{
|
{
|
||||||
cache = new HashMap<>();
|
cache = new HashMap<>();
|
||||||
|
sqlite = new SQLiteUtils<>(HabitRecord.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,13 +83,18 @@ public class SQLiteHabitList extends HabitList
|
|||||||
@Override
|
@Override
|
||||||
public int countActive()
|
public int countActive()
|
||||||
{
|
{
|
||||||
return select().count();
|
SQLiteDatabase db = Cache.openDatabase();
|
||||||
|
SQLiteStatement st = db.compileStatement(
|
||||||
|
"select count(*) from habits where archived = 0");
|
||||||
|
return (int) st.simpleQueryForLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int countWithArchived()
|
public int countWithArchived()
|
||||||
{
|
{
|
||||||
return selectWithArchived().count();
|
SQLiteDatabase db = Cache.openDatabase();
|
||||||
|
SQLiteStatement st = db.compileStatement("select count(*) from habits");
|
||||||
|
return (int) st.simpleQueryForLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -91,8 +102,17 @@ public class SQLiteHabitList extends HabitList
|
|||||||
public List<Habit> getAll(boolean includeArchive)
|
public List<Habit> getAll(boolean includeArchive)
|
||||||
{
|
{
|
||||||
List<HabitRecord> recordList;
|
List<HabitRecord> recordList;
|
||||||
if (includeArchive) recordList = selectWithArchived().execute();
|
if (includeArchive)
|
||||||
else recordList = select().execute();
|
{
|
||||||
|
String query = HabitRecord.SELECT + "order by position";
|
||||||
|
recordList = sqlite.query(query, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String query = HabitRecord.SELECT + "where archived = 0 " +
|
||||||
|
"order by position";
|
||||||
|
recordList = sqlite.query(query, null);
|
||||||
|
}
|
||||||
|
|
||||||
List<Habit> habits = new LinkedList<>();
|
List<Habit> habits = new LinkedList<>();
|
||||||
for (HabitRecord record : recordList)
|
for (HabitRecord record : recordList)
|
||||||
@@ -127,10 +147,9 @@ public class SQLiteHabitList extends HabitList
|
|||||||
@Nullable
|
@Nullable
|
||||||
public Habit getByPosition(int position)
|
public Habit getByPosition(int position)
|
||||||
{
|
{
|
||||||
HabitRecord record = selectWithArchived()
|
String query = HabitRecord.SELECT + "where position = ? limit 1";
|
||||||
.where("position = ?", position)
|
String params[] = { Integer.toString(position) };
|
||||||
.executeSingle();
|
HabitRecord record = sqlite.querySingle(query, params);
|
||||||
|
|
||||||
if (record != null) return getById(record.getId());
|
if (record != null) return getById(record.getId());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -222,18 +241,4 @@ public class SQLiteHabitList extends HabitList
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private From select()
|
|
||||||
{
|
|
||||||
return new Select()
|
|
||||||
.from(HabitRecord.class)
|
|
||||||
.where("archived = 0")
|
|
||||||
.orderBy("position");
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private From selectWithArchived()
|
|
||||||
{
|
|
||||||
return new Select().from(HabitRecord.class).orderBy("position");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,13 @@
|
|||||||
package org.isoron.uhabits.models.sqlite;
|
package org.isoron.uhabits.models.sqlite;
|
||||||
|
|
||||||
import android.support.annotation.*;
|
import android.support.annotation.*;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import com.activeandroid.query.*;
|
import com.activeandroid.query.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.*;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.models.sqlite.records.*;
|
import org.isoron.uhabits.models.sqlite.records.*;
|
||||||
import org.isoron.uhabits.utils.*;
|
import org.jetbrains.annotations.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -34,9 +35,15 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class SQLiteRepetitionList extends RepetitionList
|
public class SQLiteRepetitionList extends RepetitionList
|
||||||
{
|
{
|
||||||
|
private final SQLiteUtils<RepetitionRecord> sqlite;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private HabitRecord habitRecord;
|
||||||
|
|
||||||
public SQLiteRepetitionList(@NonNull Habit habit)
|
public SQLiteRepetitionList(@NonNull Habit habit)
|
||||||
{
|
{
|
||||||
super(habit);
|
super(habit);
|
||||||
|
sqlite = new SQLiteUtils<>(RepetitionRecord.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,25 +66,56 @@ public class SQLiteRepetitionList extends RepetitionList
|
|||||||
@Override
|
@Override
|
||||||
public List<Repetition> getByInterval(long timeFrom, long timeTo)
|
public List<Repetition> getByInterval(long timeFrom, long timeTo)
|
||||||
{
|
{
|
||||||
return toRepetitions(selectFromTo(timeFrom, timeTo).execute());
|
check(habit.getId());
|
||||||
|
String query = "select habit, timestamp " +
|
||||||
|
"from Repetitions " +
|
||||||
|
"where habit = ? and timestamp >= ? and timestamp <= ? " +
|
||||||
|
"order by timestamp";
|
||||||
|
|
||||||
|
String params[] = {
|
||||||
|
Long.toString(habit.getId()),
|
||||||
|
Long.toString(timeFrom),
|
||||||
|
Long.toString(timeTo)
|
||||||
|
};
|
||||||
|
|
||||||
|
List<RepetitionRecord> records = sqlite.query(query, params);
|
||||||
|
return toRepetitions(records);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public Repetition getByTimestamp(long timestamp)
|
public Repetition getByTimestamp(long timestamp)
|
||||||
{
|
{
|
||||||
RepetitionRecord record =
|
check(habit.getId());
|
||||||
select().where("timestamp = ?", timestamp).executeSingle();
|
String query = "select habit, timestamp " +
|
||||||
|
"from Repetitions " +
|
||||||
|
"where habit = ? and timestamp = ? " +
|
||||||
|
"limit 1";
|
||||||
|
|
||||||
|
String params[] =
|
||||||
|
{ Long.toString(habit.getId()), Long.toString(timestamp) };
|
||||||
|
|
||||||
|
RepetitionRecord record = sqlite.querySingle(query, params);
|
||||||
if (record == null) return null;
|
if (record == null) return null;
|
||||||
|
record.habit = habitRecord;
|
||||||
return record.toRepetition();
|
return record.toRepetition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Repetition getOldest()
|
public Repetition getOldest()
|
||||||
{
|
{
|
||||||
RepetitionRecord record = select().limit(1).executeSingle();
|
check(habit.getId());
|
||||||
|
String query = "select habit, timestamp " +
|
||||||
|
"from Repetitions " +
|
||||||
|
"where habit = ? " +
|
||||||
|
"order by timestamp asc " +
|
||||||
|
"limit 1";
|
||||||
|
|
||||||
|
String params[] = { Long.toString(habit.getId()) };
|
||||||
|
|
||||||
|
RepetitionRecord record = sqlite.querySingle(query, params);
|
||||||
if (record == null) return null;
|
if (record == null) return null;
|
||||||
|
record.habit = habitRecord;
|
||||||
return record.toRepetition();
|
return record.toRepetition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,33 +131,29 @@ public class SQLiteRepetitionList extends RepetitionList
|
|||||||
observable.notifyListeners();
|
observable.notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@Contract("null -> fail")
|
||||||
private From select()
|
private void check(Long id)
|
||||||
{
|
{
|
||||||
return new Select()
|
if (id == null) throw new RuntimeException("habit is not saved");
|
||||||
.from(RepetitionRecord.class)
|
|
||||||
.where("habit = ?", habit.getId())
|
|
||||||
.and("timestamp <= ?", DateUtils.getStartOfToday())
|
|
||||||
.orderBy("timestamp");
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
if (habitRecord != null) return;
|
||||||
private From selectFromTo(long timeFrom, long timeTo)
|
|
||||||
{
|
habitRecord = HabitRecord.get(id);
|
||||||
return select()
|
if (habitRecord == null) throw new RuntimeException("habit not found");
|
||||||
.and("timestamp >= ?", timeFrom)
|
|
||||||
.and("timestamp <= ?", timeTo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private List<Repetition> toRepetitions(
|
private List<Repetition> toRepetitions(
|
||||||
@Nullable List<RepetitionRecord> records)
|
@NonNull List<RepetitionRecord> records)
|
||||||
{
|
{
|
||||||
List<Repetition> reps = new LinkedList<>();
|
check(habit.getId());
|
||||||
if (records == null) return reps;
|
|
||||||
|
|
||||||
|
List<Repetition> reps = new LinkedList<>();
|
||||||
for (RepetitionRecord record : records)
|
for (RepetitionRecord record : records)
|
||||||
|
{
|
||||||
|
record.habit = habitRecord;
|
||||||
reps.add(record.toRepetition());
|
reps.add(record.toRepetition());
|
||||||
|
}
|
||||||
|
|
||||||
return reps;
|
return reps;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,14 @@ package org.isoron.uhabits.models.sqlite;
|
|||||||
|
|
||||||
import android.database.sqlite.*;
|
import android.database.sqlite.*;
|
||||||
import android.support.annotation.*;
|
import android.support.annotation.*;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import com.activeandroid.*;
|
import com.activeandroid.*;
|
||||||
import com.activeandroid.query.*;
|
import com.activeandroid.query.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.*;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.models.sqlite.records.*;
|
import org.isoron.uhabits.models.sqlite.records.*;
|
||||||
|
import org.jetbrains.annotations.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -35,6 +37,12 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class SQLiteScoreList extends ScoreList
|
public class SQLiteScoreList extends ScoreList
|
||||||
{
|
{
|
||||||
|
@Nullable
|
||||||
|
private HabitRecord habitRecord;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final SQLiteUtils<ScoreRecord> sqlite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new ScoreList associated with the given habit.
|
* Constructs a new ScoreList associated with the given habit.
|
||||||
*
|
*
|
||||||
@@ -43,36 +51,13 @@ public class SQLiteScoreList extends ScoreList
|
|||||||
public SQLiteScoreList(@NonNull Habit habit)
|
public SQLiteScoreList(@NonNull Habit habit)
|
||||||
{
|
{
|
||||||
super(habit);
|
super(habit);
|
||||||
}
|
sqlite = new SQLiteUtils<>(ScoreRecord.class);
|
||||||
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public List<Score> getAll()
|
|
||||||
{
|
|
||||||
computeAll();
|
|
||||||
|
|
||||||
List<ScoreRecord> records = select().execute();
|
|
||||||
List<Score> scores = new LinkedList<>();
|
|
||||||
|
|
||||||
for (ScoreRecord rec : records)
|
|
||||||
scores.add(rec.toScore());
|
|
||||||
|
|
||||||
return scores;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invalidateNewerThan(long timestamp)
|
|
||||||
{
|
|
||||||
new Delete()
|
|
||||||
.from(ScoreRecord.class)
|
|
||||||
.where("habit = ?", habit.getId())
|
|
||||||
.and("timestamp >= ?", timestamp)
|
|
||||||
.execute();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(List<Score> scores)
|
public void add(List<Score> scores)
|
||||||
{
|
{
|
||||||
|
check(habit.getId());
|
||||||
String query =
|
String query =
|
||||||
"insert into Score(habit, timestamp, score) values (?,?,?)";
|
"insert into Score(habit, timestamp, score) values (?,?,?)";
|
||||||
|
|
||||||
@@ -99,33 +84,83 @@ public class SQLiteScoreList extends ScoreList
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public List<Score> getAll()
|
||||||
|
{
|
||||||
|
check(habit.getId());
|
||||||
|
computeAll();
|
||||||
|
|
||||||
|
String query = "select habit, timestamp, score from Score " +
|
||||||
|
"where habit = ? order by timestamp desc";
|
||||||
|
|
||||||
|
String params[] = {Long.toString(habit.getId())};
|
||||||
|
|
||||||
|
List<ScoreRecord> records = sqlite.query(query, params);
|
||||||
|
for (ScoreRecord record : records) record.habit = habitRecord;
|
||||||
|
|
||||||
|
List<Score> scores = new LinkedList<>();
|
||||||
|
for (ScoreRecord rec : records)
|
||||||
|
scores.add(rec.toScore());
|
||||||
|
|
||||||
|
return scores;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public Score getByTimestamp(long timestamp)
|
public Score getByTimestamp(long timestamp)
|
||||||
{
|
{
|
||||||
|
check(habit.getId());
|
||||||
computeAll();
|
computeAll();
|
||||||
|
|
||||||
ScoreRecord record =
|
String query = "select habit, timestamp, score from Score " +
|
||||||
select().where("timestamp = ?", timestamp).executeSingle();
|
"where habit = ? and timestamp = ? " +
|
||||||
|
"order by timestamp desc";
|
||||||
|
|
||||||
|
String params[] =
|
||||||
|
{Long.toString(habit.getId()), Long.toString(timestamp)};
|
||||||
|
|
||||||
|
ScoreRecord record = sqlite.querySingle(query, params);
|
||||||
if (record == null) return null;
|
if (record == null) return null;
|
||||||
|
record.habit = habitRecord;
|
||||||
return record.toScore();
|
return record.toScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidateNewerThan(long timestamp)
|
||||||
|
{
|
||||||
|
new Delete()
|
||||||
|
.from(ScoreRecord.class)
|
||||||
|
.where("habit = ?", habit.getId())
|
||||||
|
.and("timestamp >= ?", timestamp)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
protected Score getNewestComputed()
|
protected Score getNewestComputed()
|
||||||
{
|
{
|
||||||
ScoreRecord record = select().limit(1).executeSingle();
|
check(habit.getId());
|
||||||
|
String query = "select habit, timestamp, score from Score " +
|
||||||
|
"where habit = ? order by timestamp desc " +
|
||||||
|
"limit 1";
|
||||||
|
|
||||||
|
String params[] = {Long.toString(habit.getId())};
|
||||||
|
|
||||||
|
ScoreRecord record = sqlite.querySingle(query, params);
|
||||||
if (record == null) return null;
|
if (record == null) return null;
|
||||||
|
record.habit = habitRecord;
|
||||||
return record.toScore();
|
return record.toScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
private From select()
|
@Contract("null -> fail")
|
||||||
|
private void check(Long id)
|
||||||
{
|
{
|
||||||
return new Select()
|
if (id == null) throw new RuntimeException("habit is not saved");
|
||||||
.from(ScoreRecord.class)
|
|
||||||
.where("habit = ?", habit.getId())
|
if(habitRecord != null) return;
|
||||||
.orderBy("timestamp desc");
|
|
||||||
|
habitRecord = HabitRecord.get(id);
|
||||||
|
if (habitRecord == null) throw new RuntimeException("habit not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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.sqlite;
|
||||||
|
|
||||||
|
import android.database.*;
|
||||||
|
import android.database.sqlite.*;
|
||||||
|
import android.support.annotation.*;
|
||||||
|
|
||||||
|
import com.activeandroid.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.models.sqlite.records.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class SQLiteUtils<T extends SQLiteRecord>
|
||||||
|
{
|
||||||
|
private Class klass;
|
||||||
|
|
||||||
|
public SQLiteUtils(Class klass)
|
||||||
|
{
|
||||||
|
this.klass = klass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public List<T> query(String query, String params[])
|
||||||
|
{
|
||||||
|
SQLiteDatabase db = Cache.openDatabase();
|
||||||
|
try (Cursor c = db.rawQuery(query, params))
|
||||||
|
{
|
||||||
|
return cursorToMultipleRecords(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public T querySingle(String query, String params[])
|
||||||
|
{
|
||||||
|
SQLiteDatabase db = Cache.openDatabase();
|
||||||
|
try(Cursor c = db.rawQuery(query, params))
|
||||||
|
{
|
||||||
|
if (!c.moveToNext()) return null;
|
||||||
|
return cursorToSingleRecord(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private List<T> cursorToMultipleRecords(Cursor c)
|
||||||
|
{
|
||||||
|
List<T> records = new LinkedList<>();
|
||||||
|
while (c.moveToNext()) records.add(cursorToSingleRecord(c));
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private T cursorToSingleRecord(Cursor c)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
T record = (T) klass.newInstance();
|
||||||
|
record.copyFrom(c);
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.models.sqlite.records;
|
package org.isoron.uhabits.models.sqlite.records;
|
||||||
|
|
||||||
|
import android.database.*;
|
||||||
|
|
||||||
import com.activeandroid.*;
|
import com.activeandroid.*;
|
||||||
import com.activeandroid.annotation.*;
|
import com.activeandroid.annotation.*;
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ import org.isoron.uhabits.models.sqlite.*;
|
|||||||
* The SQLite database record corresponding to a {@link Checkmark}.
|
* The SQLite database record corresponding to a {@link Checkmark}.
|
||||||
*/
|
*/
|
||||||
@Table(name = "Checkmarks")
|
@Table(name = "Checkmarks")
|
||||||
public class CheckmarkRecord extends Model
|
public class CheckmarkRecord extends Model implements SQLiteRecord
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The habit to which this checkmark belongs.
|
* The habit to which this checkmark belongs.
|
||||||
@@ -52,6 +54,13 @@ public class CheckmarkRecord extends Model
|
|||||||
@Column(name = "value")
|
@Column(name = "value")
|
||||||
public Integer value;
|
public Integer value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyFrom(Cursor c)
|
||||||
|
{
|
||||||
|
timestamp = c.getLong(1);
|
||||||
|
value = c.getInt(2);
|
||||||
|
}
|
||||||
|
|
||||||
public Checkmark toCheckmark()
|
public Checkmark toCheckmark()
|
||||||
{
|
{
|
||||||
SQLiteHabitList habitList = SQLiteHabitList.getInstance();
|
SQLiteHabitList habitList = SQLiteHabitList.getInstance();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
package org.isoron.uhabits.models.sqlite.records;
|
package org.isoron.uhabits.models.sqlite.records;
|
||||||
|
|
||||||
import android.annotation.*;
|
import android.annotation.*;
|
||||||
|
import android.database.*;
|
||||||
import android.support.annotation.*;
|
import android.support.annotation.*;
|
||||||
|
|
||||||
import com.activeandroid.*;
|
import com.activeandroid.*;
|
||||||
@@ -28,17 +29,24 @@ import com.activeandroid.query.*;
|
|||||||
import com.activeandroid.util.*;
|
import com.activeandroid.util.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.*;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.utils.*;
|
import org.isoron.uhabits.utils.DatabaseUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SQLite database record corresponding to a {@link Habit}.
|
* The SQLite database record corresponding to a {@link Habit}.
|
||||||
*/
|
*/
|
||||||
@Table(name = "Habits")
|
@Table(name = "Habits")
|
||||||
public class HabitRecord extends Model
|
public class HabitRecord extends Model implements SQLiteRecord
|
||||||
{
|
{
|
||||||
public static final String HABIT_URI_FORMAT =
|
public static final String HABIT_URI_FORMAT =
|
||||||
"content://org.isoron.uhabits/habit/%d";
|
"content://org.isoron.uhabits/habit/%d";
|
||||||
|
|
||||||
|
public static String SELECT =
|
||||||
|
"select id, color, description, freq_den, freq_num, " +
|
||||||
|
"name, position, reminder_hour, reminder_min, " +
|
||||||
|
"highlight, archived, reminder_days from habits ";
|
||||||
|
|
||||||
@Column(name = "name")
|
@Column(name = "name")
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
@@ -147,6 +155,23 @@ public class HabitRecord extends Model
|
|||||||
this.archived = model.getArchived();
|
this.archived = model.getArchived();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyFrom(Cursor c)
|
||||||
|
{
|
||||||
|
setId(c.getLong(0));
|
||||||
|
color = c.getInt(1);
|
||||||
|
description = c.getString(2);
|
||||||
|
freqDen = c.getInt(3);
|
||||||
|
freqNum = c.getInt(4);
|
||||||
|
name = c.getString(5);
|
||||||
|
position = c.getInt(6);
|
||||||
|
reminderHour = c.getInt(7);
|
||||||
|
reminderMin = c.getInt(8);
|
||||||
|
highlight = c.getInt(9);
|
||||||
|
archived = c.getInt(10);
|
||||||
|
reminderDays = c.getInt(11);
|
||||||
|
}
|
||||||
|
|
||||||
public void copyTo(Habit habit)
|
public void copyTo(Habit habit)
|
||||||
{
|
{
|
||||||
habit.setName(this.name);
|
habit.setName(this.name);
|
||||||
@@ -172,4 +197,20 @@ public class HabitRecord extends Model
|
|||||||
save();
|
save();
|
||||||
updateId(getId(), id);
|
updateId(getId(), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
f.setAccessible(true);
|
||||||
|
f.set(this, id);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.models.sqlite.records;
|
package org.isoron.uhabits.models.sqlite.records;
|
||||||
|
|
||||||
|
import android.database.*;
|
||||||
|
|
||||||
import com.activeandroid.*;
|
import com.activeandroid.*;
|
||||||
import com.activeandroid.annotation.*;
|
import com.activeandroid.annotation.*;
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ import org.isoron.uhabits.models.sqlite.*;
|
|||||||
* The SQLite database record corresponding to a {@link Repetition}.
|
* The SQLite database record corresponding to a {@link Repetition}.
|
||||||
*/
|
*/
|
||||||
@Table(name = "Repetitions")
|
@Table(name = "Repetitions")
|
||||||
public class RepetitionRecord extends Model
|
public class RepetitionRecord extends Model implements SQLiteRecord
|
||||||
{
|
{
|
||||||
@Column(name = "habit")
|
@Column(name = "habit")
|
||||||
public HabitRecord habit;
|
public HabitRecord habit;
|
||||||
@@ -37,15 +39,21 @@ public class RepetitionRecord extends Model
|
|||||||
@Column(name = "timestamp")
|
@Column(name = "timestamp")
|
||||||
public Long timestamp;
|
public Long timestamp;
|
||||||
|
|
||||||
|
public static RepetitionRecord get(Long id)
|
||||||
|
{
|
||||||
|
return RepetitionRecord.load(RepetitionRecord.class, id);
|
||||||
|
}
|
||||||
|
|
||||||
public void copyFrom(Repetition repetition)
|
public void copyFrom(Repetition repetition)
|
||||||
{
|
{
|
||||||
habit = HabitRecord.get(repetition.getHabit().getId());
|
habit = HabitRecord.get(repetition.getHabit().getId());
|
||||||
timestamp = repetition.getTimestamp();
|
timestamp = repetition.getTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RepetitionRecord get(Long id)
|
@Override
|
||||||
|
public void copyFrom(Cursor c)
|
||||||
{
|
{
|
||||||
return RepetitionRecord.load(RepetitionRecord.class, id);
|
timestamp = c.getLong(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Repetition toRepetition()
|
public Repetition toRepetition()
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.sqlite.records;
|
||||||
|
|
||||||
|
import android.database.*;
|
||||||
|
|
||||||
|
public interface SQLiteRecord
|
||||||
|
{
|
||||||
|
void copyFrom(Cursor c);
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.models.sqlite.records;
|
package org.isoron.uhabits.models.sqlite.records;
|
||||||
|
|
||||||
|
import android.database.*;
|
||||||
|
|
||||||
import com.activeandroid.*;
|
import com.activeandroid.*;
|
||||||
import com.activeandroid.annotation.*;
|
import com.activeandroid.annotation.*;
|
||||||
|
|
||||||
@@ -29,11 +31,8 @@ import org.isoron.uhabits.models.sqlite.*;
|
|||||||
* The SQLite database record corresponding to a Score.
|
* The SQLite database record corresponding to a Score.
|
||||||
*/
|
*/
|
||||||
@Table(name = "Score")
|
@Table(name = "Score")
|
||||||
public class ScoreRecord extends Model
|
public class ScoreRecord extends Model implements SQLiteRecord
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Habit to which this score belongs to.
|
|
||||||
*/
|
|
||||||
@Column(name = "habit")
|
@Column(name = "habit")
|
||||||
public HabitRecord habit;
|
public HabitRecord habit;
|
||||||
|
|
||||||
@@ -50,6 +49,13 @@ public class ScoreRecord extends Model
|
|||||||
@Column(name = "score")
|
@Column(name = "score")
|
||||||
public Integer score;
|
public Integer score;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyFrom(Cursor c)
|
||||||
|
{
|
||||||
|
timestamp = c.getLong(1);
|
||||||
|
score = c.getInt(2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs and returns a {@link Score} based on this record's data.
|
* Constructs and returns a {@link Score} based on this record's data.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -19,26 +19,20 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.ui.habits.list;
|
package org.isoron.uhabits.ui.habits.list;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.os.*;
|
||||||
|
import android.support.annotation.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.HabitsApplication;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.R;
|
import org.isoron.uhabits.commands.*;
|
||||||
import org.isoron.uhabits.commands.CommandRunner;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.commands.ToggleRepetitionCommand;
|
import org.isoron.uhabits.tasks.*;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.ui.*;
|
||||||
import org.isoron.uhabits.models.HabitList;
|
import org.isoron.uhabits.ui.habits.list.controllers.*;
|
||||||
import org.isoron.uhabits.tasks.ExportCSVTask;
|
import org.isoron.uhabits.utils.*;
|
||||||
import org.isoron.uhabits.tasks.ExportDBTask;
|
|
||||||
import org.isoron.uhabits.tasks.ImportDataTask;
|
|
||||||
import org.isoron.uhabits.ui.BaseSystem;
|
|
||||||
import org.isoron.uhabits.ui.habits.list.controllers.HabitCardListController;
|
|
||||||
import org.isoron.uhabits.utils.DateUtils;
|
|
||||||
import org.isoron.uhabits.utils.Preferences;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.*;
|
||||||
|
|
||||||
public class ListHabitsController
|
public class ListHabitsController
|
||||||
implements ImportDataTask.Listener, HabitCardListController.HabitListener
|
implements ImportDataTask.Listener, HabitCardListController.HabitListener
|
||||||
@@ -168,8 +162,10 @@ public class ListHabitsController
|
|||||||
prefs.updateLastAppVersion();
|
prefs.updateLastAppVersion();
|
||||||
if (prefs.isFirstRun()) onFirstRun();
|
if (prefs.isFirstRun()) onFirstRun();
|
||||||
|
|
||||||
|
new Handler().postDelayed(() -> {
|
||||||
system.updateWidgets();
|
system.updateWidgets();
|
||||||
system.scheduleReminders();
|
system.scheduleReminders();
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user