Initial implementation of filters

pull/145/head
Alinson S. Xavier 9 years ago
parent 31fdae1c8b
commit 922b234307

@ -84,7 +84,7 @@ public class HabitFixtures
public void purgeHabits(HabitList habitList) public void purgeHabits(HabitList habitList)
{ {
for (Habit h : habitList.getAll(true)) for (Habit h : habitList)
habitList.remove(h); habitList.remove(h);
} }
} }

@ -19,27 +19,22 @@
package org.isoron.uhabits.io; package org.isoron.uhabits.io;
import android.content.Context; import android.content.*;
import android.support.test.InstrumentationRegistry; import android.support.test.*;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.*;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.*;
import org.isoron.uhabits.BaseAndroidTest; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.utils.FileUtils; import org.isoron.uhabits.utils.*;
import org.junit.Before; import org.junit.*;
import org.junit.Test; import org.junit.runner.*;
import org.junit.runner.RunWith;
import java.io.*;
import java.io.File; import java.util.*;
import java.io.IOException; import java.util.zip.*;
import java.io.InputStream;
import java.util.Enumeration; import static junit.framework.Assert.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import static junit.framework.Assert.assertTrue;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
@ -63,9 +58,11 @@ public class HabitsCSVExporterTest extends BaseAndroidTest
@Test @Test
public void testExportCSV() throws IOException public void testExportCSV() throws IOException
{ {
List<Habit> habits = habitList.getAll(true); List<Habit> selected = new LinkedList<>();
for (Habit h : habitList) selected.add(h);
HabitsCSVExporter exporter = new HabitsCSVExporter(habits, baseDir); HabitsCSVExporter exporter =
new HabitsCSVExporter(habitList, selected, baseDir);
String filename = exporter.writeArchive(); String filename = exporter.writeArchive();
assertAbsolutePathExists(filename); assertAbsolutePathExists(filename);

@ -44,6 +44,7 @@ public class ImportTest extends BaseAndroidTest
private Context context; private Context context;
@Override
@Before @Before
public void setUp() public void setUp()
{ {
@ -61,10 +62,9 @@ public class ImportTest extends BaseAndroidTest
{ {
importFromFile("habitbull.csv"); importFromFile("habitbull.csv");
List<Habit> habits = habitList.getAll(true); assertThat(habitList.size(), equalTo(4));
assertThat(habits.size(), equalTo(4));
Habit habit = habits.get(0); Habit habit = habitList.getByPosition(0);
assertThat(habit.getName(), equalTo("Breed dragons")); assertThat(habit.getName(), equalTo("Breed dragons"));
assertThat(habit.getDescription(), equalTo("with love and fire")); assertThat(habit.getDescription(), equalTo("with love and fire"));
assertThat(habit.getFrequency(), equalTo(Frequency.DAILY)); assertThat(habit.getFrequency(), equalTo(Frequency.DAILY));
@ -78,10 +78,9 @@ public class ImportTest extends BaseAndroidTest
{ {
importFromFile("loop.db"); importFromFile("loop.db");
List<Habit> habits = habitList.getAll(true); assertThat(habitList.size(), equalTo(9));
assertThat(habits.size(), equalTo(9));
Habit habit = habits.get(0); Habit habit = habitList.getByPosition(0);
assertThat(habit.getName(), equalTo("Wake up early")); assertThat(habit.getName(), equalTo("Wake up early"));
assertThat(habit.getFrequency(), equalTo(Frequency.THREE_TIMES_PER_WEEK)); assertThat(habit.getFrequency(), equalTo(Frequency.THREE_TIMES_PER_WEEK));
assertTrue(containsRepetition(habit, 2016, 3, 14)); assertTrue(containsRepetition(habit, 2016, 3, 14));
@ -94,10 +93,9 @@ public class ImportTest extends BaseAndroidTest
{ {
importFromFile("rewire.db"); importFromFile("rewire.db");
List<Habit> habits = habitList.getAll(true); assertThat(habitList.size(), equalTo(3));
assertThat(habits.size(), equalTo(3));
Habit habit = habits.get(0); Habit habit = habitList.getByPosition(0);
assertThat(habit.getName(), equalTo("Wake up early")); assertThat(habit.getName(), equalTo("Wake up early"));
assertThat(habit.getFrequency(), assertThat(habit.getFrequency(),
equalTo(Frequency.THREE_TIMES_PER_WEEK)); equalTo(Frequency.THREE_TIMES_PER_WEEK));
@ -107,7 +105,7 @@ public class ImportTest extends BaseAndroidTest
assertTrue(containsRepetition(habit, 2016, 1, 28)); assertTrue(containsRepetition(habit, 2016, 1, 28));
assertFalse(containsRepetition(habit, 2016, 3, 10)); assertFalse(containsRepetition(habit, 2016, 3, 10));
habit = habits.get(1); habit = habitList.getByPosition(1);
assertThat(habit.getName(), equalTo("brush teeth")); assertThat(habit.getName(), equalTo("brush teeth"));
assertThat(habit.getFrequency(), assertThat(habit.getFrequency(),
equalTo(Frequency.THREE_TIMES_PER_WEEK)); equalTo(Frequency.THREE_TIMES_PER_WEEK));
@ -126,10 +124,9 @@ public class ImportTest extends BaseAndroidTest
{ {
importFromFile("tickmate.db"); importFromFile("tickmate.db");
List<Habit> habits = habitList.getAll(true); assertThat(habitList.size(), equalTo(3));
assertThat(habits.size(), equalTo(3));
Habit h = habits.get(0); Habit h = habitList.getByPosition(0);
assertThat(h.getName(), equalTo("Vegan")); assertThat(h.getName(), equalTo("Vegan"));
assertTrue(containsRepetition(h, 2016, 1, 24)); assertTrue(containsRepetition(h, 2016, 1, 24));
assertTrue(containsRepetition(h, 2016, 2, 5)); assertTrue(containsRepetition(h, 2016, 2, 5));
@ -158,7 +155,7 @@ public class ImportTest extends BaseAndroidTest
assertTrue(file.exists()); assertTrue(file.exists());
assertTrue(file.canRead()); assertTrue(file.canRead());
GenericImporter importer = new GenericImporter(); GenericImporter importer = new GenericImporter(habitList);
assertThat(importer.canHandle(file), is(true)); assertThat(importer.canHandle(file), is(true));
importer.importHabitsFromFile(file); importer.importHabitsFromFile(file);

@ -45,10 +45,13 @@ public class SQLiteHabitListTest extends BaseAndroidTest
@Rule @Rule
public ExpectedException exception = ExpectedException.none(); public ExpectedException exception = ExpectedException.none();
private SQLiteHabitList habitList;
@Override @Override
public void setUp() public void setUp()
{ {
super.setUp(); super.setUp();
this.habitList = (SQLiteHabitList) super.habitList;
fixtures.purgeHabits(habitList); fixtures.purgeHabits(habitList);
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
@ -105,35 +108,29 @@ public class SQLiteHabitListTest extends BaseAndroidTest
} }
@Test @Test
public void testCountActive() public void testSize()
{
assertThat(habitList.countActive(), equalTo(5));
}
@Test
public void testCountWithArchived()
{ {
assertThat(habitList.countWithArchived(), equalTo(10)); assertThat(habitList.size(), equalTo(10));
} }
@Test @Test
public void testGetAll_withArchived() public void testGetAll_withArchived()
{ {
List<Habit> habits = habitList.getAll(true); List<Habit> habits = habitList.toList();
assertThat(habits.size(), equalTo(10)); assertThat(habits.size(), equalTo(10));
assertThat(habits.get(3).getName(), equalTo("habit 3")); assertThat(habits.get(3).getName(), equalTo("habit 3"));
} }
@Test // @Test
public void testGetAll_withoutArchived() // public void testGetAll_withoutArchived()
{ // {
List<Habit> habits = habitList.getAll(false); // List<Habit> habits = habitList.toList();
assertThat(habits.size(), equalTo(5)); // assertThat(habits.size(), equalTo(5));
assertThat(habits.get(3).getName(), equalTo("habit 7")); // assertThat(habits.get(3).getName(), equalTo("habit 7"));
//
List<Habit> another = habitList.getAll(false); // List<Habit> another = habitList.toList();
assertThat(habits, equalTo(another)); // assertThat(habits, equalTo(another));
} // }
@Test @Test
public void testGetById() public void testGetById()

@ -49,9 +49,10 @@ public class ExportCSVTaskTest extends BaseAndroidTest
public void testExportCSV() throws Throwable public void testExportCSV() throws Throwable
{ {
fixtures.createShortHabit(); fixtures.createShortHabit();
List<Habit> habits = habitList.getAll(true); List<Habit> selected = new LinkedList<>();
for(Habit h : habitList) selected.add(h);
ExportCSVTask task = new ExportCSVTask(habits, null); ExportCSVTask task = new ExportCSVTask(habitList, selected, null);
task.setListener(archiveFilename -> { task.setListener(archiveFilename -> {
assertThat(archiveFilename, is(not(nullValue()))); assertThat(archiveFilename, is(not(nullValue())));

@ -80,7 +80,7 @@ public class ImportDataTaskTest extends BaseAndroidTest
{ {
File file = new File(String.format("%s/%s", baseDir.getPath(), assetFilename)); File file = new File(String.format("%s/%s", baseDir.getPath(), assetFilename));
copyAssetToFile(assetFilename, file); copyAssetToFile(assetFilename, file);
return new ImportDataTask(file, null); return new ImportDataTask(habitList, file, null);
} }
@Test @Test

@ -55,7 +55,7 @@ public class HabitBroadcastReceiver extends BroadcastReceiver
"org.isoron.uhabits.ACTION_SNOOZE"; "org.isoron.uhabits.ACTION_SNOOZE";
@Inject @Inject
HabitList habitList; HabitList habits;
@Inject @Inject
CommandRunner commandRunner; CommandRunner commandRunner;
@ -99,7 +99,7 @@ public class HabitBroadcastReceiver extends BroadcastReceiver
break; break;
case Intent.ACTION_BOOT_COMPLETED: case Intent.ACTION_BOOT_COMPLETED:
ReminderUtils.createReminderAlarms(context, habitList); ReminderUtils.createReminderAlarms(context, habits);
break; break;
} }
} }
@ -111,7 +111,7 @@ public class HabitBroadcastReceiver extends BroadcastReceiver
Long timestamp = intent.getLongExtra("timestamp", today); Long timestamp = intent.getLongExtra("timestamp", today);
long habitId = ContentUris.parseId(data); long habitId = ContentUris.parseId(data);
Habit habit = habitList.getById(habitId); Habit habit = habits.getById(habitId);
if (habit != null) if (habit != null)
{ {
ToggleRepetitionCommand command = ToggleRepetitionCommand command =
@ -140,7 +140,7 @@ public class HabitBroadcastReceiver extends BroadcastReceiver
private void createNotification(final Context context, final Intent intent) private void createNotification(final Context context, final Intent intent)
{ {
final Uri data = intent.getData(); final Uri data = intent.getData();
final Habit habit = habitList.getById(ContentUris.parseId(data)); final Habit habit = habits.getById(ContentUris.parseId(data));
final Long timestamp = final Long timestamp =
intent.getLongExtra("timestamp", DateUtils.getStartOfToday()); intent.getLongExtra("timestamp", DateUtils.getStartOfToday());
final Long reminderTime = final Long reminderTime =
@ -223,7 +223,7 @@ public class HabitBroadcastReceiver extends BroadcastReceiver
private void createReminderAlarmsDelayed(final Context context) private void createReminderAlarmsDelayed(final Context context)
{ {
new Handler().postDelayed( new Handler().postDelayed(
() -> ReminderUtils.createReminderAlarms(context, habitList), 5000); () -> ReminderUtils.createReminderAlarms(context, habits), 5000);
} }
private void dismissAllHabits() private void dismissAllHabits()
@ -250,7 +250,7 @@ public class HabitBroadcastReceiver extends BroadcastReceiver
Long.parseLong(prefs.getString("pref_snooze_interval", "15")); Long.parseLong(prefs.getString("pref_snooze_interval", "15"));
long habitId = ContentUris.parseId(data); long habitId = ContentUris.parseId(data);
Habit habit = habitList.getById(habitId); Habit habit = habits.getById(habitId);
if (habit != null) ReminderUtils.createReminderAlarm(context, habit, if (habit != null) ReminderUtils.createReminderAlarm(context, habit,
new Date().getTime() + delayMinutes * 60 * 1000); new Date().getTime() + delayMinutes * 60 * 1000);
dismissNotification(context, habitId); dismissNotification(context, habitId);

@ -19,43 +19,32 @@
package org.isoron.uhabits.commands; package org.isoron.uhabits.commands;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.HabitList;
import java.util.List; import java.util.*;
import javax.inject.Inject;
/** /**
* Command to archive a list of habits. * Command to archive a list of habits.
*/ */
public class ArchiveHabitsCommand extends Command public class ArchiveHabitsCommand extends Command
{ {
@Inject private List<Habit> selectedHabits;
HabitList habitList;
private List<Habit> habits; private final HabitList habitList;
public ArchiveHabitsCommand(List<Habit> habits) public ArchiveHabitsCommand(HabitList habitList, List<Habit> selectedHabits)
{ {
this.habitList = habitList;
HabitsApplication.getComponent().inject(this); HabitsApplication.getComponent().inject(this);
this.habits = habits; this.selectedHabits = selectedHabits;
} }
@Override @Override
public void execute() public void execute()
{ {
for(Habit h : habits) h.setArchived(true); for (Habit h : selectedHabits) h.setArchived(true);
habitList.update(habits); habitList.update(selectedHabits);
}
@Override
public void undo()
{
for(Habit h : habits) h.setArchived(false);
habitList.update(habits);
} }
@Override @Override
@ -69,4 +58,11 @@ public class ArchiveHabitsCommand extends Command
{ {
return R.string.toast_habit_unarchived; return R.string.toast_habit_unarchived;
} }
@Override
public void undo()
{
for (Habit h : selectedHabits) h.setArchived(false);
habitList.update(selectedHabits);
}
} }

@ -19,46 +19,41 @@
package org.isoron.uhabits.commands; package org.isoron.uhabits.commands;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.HabitList;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import javax.inject.Inject;
/** /**
* Command to change the color of a list of habits. * Command to change the color of a list of habits.
*/ */
public class ChangeHabitColorCommand extends Command public class ChangeHabitColorCommand extends Command
{ {
@Inject
HabitList habitList; HabitList habitList;
List<Habit> habits; List<Habit> selected;
List<Integer> originalColors; List<Integer> originalColors;
Integer newColor; Integer newColor;
public ChangeHabitColorCommand(List<Habit> habits, Integer newColor) public ChangeHabitColorCommand(HabitList habitList,
List<Habit> selected,
Integer newColor)
{ {
HabitsApplication.getComponent().inject(this); this.habitList = habitList;
this.selected = selected;
this.habits = habits;
this.newColor = newColor; this.newColor = newColor;
this.originalColors = new ArrayList<>(habits.size()); this.originalColors = new ArrayList<>(selected.size());
for (Habit h : habits) originalColors.add(h.getColor()); for (Habit h : selected) originalColors.add(h.getColor());
} }
@Override @Override
public void execute() public void execute()
{ {
for(Habit h : habits) h.setColor(newColor); for (Habit h : selected) h.setColor(newColor);
habitList.update(habits); habitList.update(selected);
} }
@Override @Override
@ -77,7 +72,7 @@ public class ChangeHabitColorCommand extends Command
public void undo() public void undo()
{ {
int k = 0; int k = 0;
for (Habit h : habits) h.setColor(originalColors.get(k++)); for (Habit h : selected) h.setColor(originalColors.get(k++));
habitList.update(habits); habitList.update(selected);
} }
} }

@ -19,28 +19,23 @@
package org.isoron.uhabits.commands; package org.isoron.uhabits.commands;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.HabitList;
import javax.inject.Inject;
/** /**
* Command to create a habit. * Command to create a habit.
*/ */
public class CreateHabitCommand extends Command public class CreateHabitCommand extends Command
{ {
@Inject
HabitList habitList; HabitList habitList;
private Habit model; private Habit model;
private Long savedId; private Long savedId;
public CreateHabitCommand(Habit model) public CreateHabitCommand(HabitList habitList, Habit model)
{ {
this.habitList = habitList;
this.model = model; this.model = model;
HabitsApplication.getComponent().inject(this);
} }
@Override @Override

@ -19,29 +19,24 @@
package org.isoron.uhabits.commands; package org.isoron.uhabits.commands;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.HabitList;
import java.util.List; import java.util.*;
import javax.inject.Inject;
/** /**
* Command to delete a list of habits. * Command to delete a list of habits.
*/ */
public class DeleteHabitsCommand extends Command public class DeleteHabitsCommand extends Command
{ {
@Inject
HabitList habitList; HabitList habitList;
private List<Habit> habits; private List<Habit> habits;
public DeleteHabitsCommand(List<Habit> habits) public DeleteHabitsCommand(HabitList habitList, List<Habit> habits)
{ {
this.habits = habits; this.habits = habits;
HabitsApplication.getComponent().inject(this); this.habitList = habitList;
} }
@Override @Override

@ -22,14 +22,11 @@ package org.isoron.uhabits.commands;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import javax.inject.*;
/** /**
* Command to modify a habit. * Command to modify a habit.
*/ */
public class EditHabitCommand extends Command public class EditHabitCommand extends Command
{ {
@Inject
HabitList habitList; HabitList habitList;
private Habit original; private Habit original;
@ -40,10 +37,9 @@ public class EditHabitCommand extends Command
private boolean hasFrequencyChanged; private boolean hasFrequencyChanged;
public EditHabitCommand(Habit original, Habit modified) public EditHabitCommand(HabitList habitList, Habit original, Habit modified)
{ {
HabitsApplication.getComponent().inject(this); this.habitList = habitList;
this.savedId = original.getId(); this.savedId = original.getId();
this.modified = new Habit(); this.modified = new Habit();
this.original = new Habit(); this.original = new Habit();

@ -19,29 +19,24 @@
package org.isoron.uhabits.commands; package org.isoron.uhabits.commands;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.HabitList;
import java.util.List; import java.util.*;
import javax.inject.Inject;
/** /**
* Command to unarchive a list of habits. * Command to unarchive a list of habits.
*/ */
public class UnarchiveHabitsCommand extends Command public class UnarchiveHabitsCommand extends Command
{ {
@Inject
HabitList habitList; HabitList habitList;
private List<Habit> habits; private List<Habit> habits;
public UnarchiveHabitsCommand(List<Habit> habits) public UnarchiveHabitsCommand(HabitList habitList, List<Habit> selected)
{ {
this.habits = habits; this.habits = selected;
HabitsApplication.getComponent().inject(this); this.habitList = habitList;
} }
@Override @Override

@ -19,17 +19,13 @@
package org.isoron.uhabits.io; package org.isoron.uhabits.io;
import android.support.annotation.NonNull; import android.support.annotation.*;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.HabitList; import org.isoron.uhabits.models.*;
import java.io.File; import java.io.*;
import java.io.FileInputStream; import java.util.*;
import java.io.IOException;
import java.util.Arrays;
import javax.inject.Inject;
/** /**
* AbstractImporter is the base class for all classes that import data from * AbstractImporter is the base class for all classes that import data from
@ -37,12 +33,12 @@ import javax.inject.Inject;
*/ */
public abstract class AbstractImporter public abstract class AbstractImporter
{ {
@Inject protected final HabitList habits;
HabitList habitList;
public AbstractImporter() public AbstractImporter(HabitList habits)
{ {
HabitsApplication.getComponent().inject(this); HabitsApplication.getComponent().inject(this);
this.habits = habits;
} }
public abstract boolean canHandle(@NonNull File file) throws IOException; public abstract boolean canHandle(@NonNull File file) throws IOException;

@ -21,6 +21,8 @@ package org.isoron.uhabits.io;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import org.isoron.uhabits.models.*;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.LinkedList; import java.util.LinkedList;
@ -34,13 +36,14 @@ public class GenericImporter extends AbstractImporter
{ {
List<AbstractImporter> importers; List<AbstractImporter> importers;
public GenericImporter() public GenericImporter(HabitList habits)
{ {
super(habits);
importers = new LinkedList<>(); importers = new LinkedList<>();
importers.add(new LoopDBImporter()); importers.add(new LoopDBImporter(habits));
importers.add(new RewireDBImporter()); importers.add(new RewireDBImporter(habits));
importers.add(new TickmateDBImporter()); importers.add(new TickmateDBImporter(habits));
importers.add(new HabitBullCSVImporter()); importers.add(new HabitBullCSVImporter(habits));
} }
@Override @Override

@ -39,6 +39,11 @@ import java.util.HashMap;
*/ */
public class HabitBullCSVImporter extends AbstractImporter public class HabitBullCSVImporter extends AbstractImporter
{ {
public HabitBullCSVImporter(HabitList habits)
{
super(habits);
}
@Override @Override
public boolean canHandle(@NonNull File file) throws IOException public boolean canHandle(@NonNull File file) throws IOException
{ {
@ -66,7 +71,7 @@ public class HabitBullCSVImporter extends AbstractImporter
private void parseFile(@NonNull File file) throws IOException private void parseFile(@NonNull File file) throws IOException
{ {
CSVReader reader = new CSVReader(new FileReader(file)); CSVReader reader = new CSVReader(new FileReader(file));
HashMap<String, Habit> habits = new HashMap<>(); HashMap<String, Habit> map = new HashMap<>();
for(String line[] : reader) for(String line[] : reader)
{ {
@ -87,7 +92,7 @@ public class HabitBullCSVImporter extends AbstractImporter
int value = Integer.parseInt(line[4]); int value = Integer.parseInt(line[4]);
if(value != 1) continue; if(value != 1) continue;
Habit h = habits.get(name); Habit h = map.get(name);
if(h == null) if(h == null)
{ {
@ -95,8 +100,8 @@ public class HabitBullCSVImporter extends AbstractImporter
h.setName(name); h.setName(name);
h.setDescription(description); h.setDescription(description);
h.setFrequency(Frequency.DAILY); h.setFrequency(Frequency.DAILY);
habitList.add(h); habits.add(h);
habits.put(name, h); map.put(name, h);
} }
if(!h.getRepetitions().containsTimestamp(timestamp)) if(!h.getRepetitions().containsTimestamp(timestamp))

@ -19,67 +19,116 @@
package org.isoron.uhabits.io; package org.isoron.uhabits.io;
import android.support.annotation.NonNull; import android.support.annotation.*;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.CheckmarkList; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.utils.*;
import org.isoron.uhabits.models.HabitList;
import org.isoron.uhabits.models.ScoreList; import java.io.*;
import org.isoron.uhabits.utils.DateUtils; import java.text.*;
import java.util.*;
import java.io.File; import java.util.zip.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.inject.Inject;
/** /**
* Class that exports the application data to CSV files. * Class that exports the application data to CSV files.
*/ */
public class HabitsCSVExporter public class HabitsCSVExporter
{ {
private List<Habit> habits; private List<Habit> selectedHabits;
private List<String> generateDirs; private List<String> generateDirs;
private List<String> generateFilenames; private List<String> generateFilenames;
private String exportDirName; private String exportDirName;
@Inject @NonNull
HabitList habitList; private final HabitList allHabits;
public HabitsCSVExporter(List<Habit> habits, File dir) public HabitsCSVExporter(@NonNull HabitList allHabits,
@NonNull List<Habit> selectedHabits,
@NonNull File dir)
{ {
HabitsApplication.getComponent().inject(this); HabitsApplication.getComponent().inject(this);
this.habits = habits; this.allHabits = allHabits;
this.selectedHabits = selectedHabits;
this.exportDirName = dir.getAbsolutePath() + "/"; this.exportDirName = dir.getAbsolutePath() + "/";
generateDirs = new LinkedList<>(); generateDirs = new LinkedList<>();
generateFilenames = new LinkedList<>(); generateFilenames = new LinkedList<>();
} }
public String writeArchive() throws IOException
{
String zipFilename;
writeHabits();
zipFilename = writeZipFile();
cleanup();
return zipFilename;
}
private void addFileToZip(ZipOutputStream zos, String filename)
throws IOException
{
FileInputStream fis =
new FileInputStream(new File(exportDirName + filename));
ZipEntry ze = new ZipEntry(filename);
zos.putNextEntry(ze);
int length;
byte bytes[] = new byte[1024];
while ((length = fis.read(bytes)) >= 0) zos.write(bytes, 0, length);
zos.closeEntry();
fis.close();
}
private void cleanup()
{
for (String filename : generateFilenames)
new File(exportDirName + filename).delete();
for (String filename : generateDirs)
new File(exportDirName + filename).delete();
new File(exportDirName).delete();
}
@NonNull
private String sanitizeFilename(String name)
{
String s = name.replaceAll("[^ a-zA-Z0-9\\._-]+", "");
return s.substring(0, Math.min(s.length(), 100));
}
private void writeCheckmarks(String habitDirName, CheckmarkList checkmarks)
throws IOException
{
String filename = habitDirName + "Checkmarks.csv";
FileWriter out = new FileWriter(exportDirName + filename);
generateFilenames.add(filename);
checkmarks.writeCSV(out);
out.close();
}
private void writeHabits() throws IOException private void writeHabits() throws IOException
{ {
String filename = "Habits.csv"; String filename = "Habits.csv";
new File(exportDirName).mkdirs(); new File(exportDirName).mkdirs();
FileWriter out = new FileWriter(exportDirName + filename); FileWriter out = new FileWriter(exportDirName + filename);
generateFilenames.add(filename); generateFilenames.add(filename);
habitList.writeCSV(out); allHabits.writeCSV(out);
out.close(); out.close();
for(Habit h : habits) for (Habit h : selectedHabits)
{ {
String sane = sanitizeFilename(h.getName()); String sane = sanitizeFilename(h.getName());
String habitDirName = String.format("%03d %s", habitList.indexOf(h) + 1, sane); String habitDirName =
String.format("%03d %s", allHabits.indexOf(h) + 1, sane);
habitDirName = habitDirName.trim() + "/"; habitDirName = habitDirName.trim() + "/";
new File(exportDirName + habitDirName).mkdirs(); new File(exportDirName + habitDirName).mkdirs();
@ -90,14 +139,8 @@ public class HabitsCSVExporter
} }
} }
@NonNull private void writeScores(String habitDirName, ScoreList scores)
private String sanitizeFilename(String name) throws IOException
{
String s = name.replaceAll("[^ a-zA-Z0-9\\._-]+", "");
return s.substring(0, Math.min(s.length(), 100));
}
private void writeScores(String habitDirName, ScoreList scores) throws IOException
{ {
String path = habitDirName + "Scores.csv"; String path = habitDirName + "Scores.csv";
FileWriter out = new FileWriter(exportDirName + path); FileWriter out = new FileWriter(exportDirName + path);
@ -106,25 +149,17 @@ public class HabitsCSVExporter
out.close(); out.close();
} }
private void writeCheckmarks(String habitDirName, CheckmarkList checkmarks) throws IOException
{
String filename = habitDirName + "Checkmarks.csv";
FileWriter out = new FileWriter(exportDirName + filename);
generateFilenames.add(filename);
checkmarks.writeCSV(out);
out.close();
}
private String writeZipFile() throws IOException private String writeZipFile() throws IOException
{ {
SimpleDateFormat dateFormat = DateUtils.getCSVDateFormat(); SimpleDateFormat dateFormat = DateUtils.getCSVDateFormat();
String date = dateFormat.format(DateUtils.getStartOfToday()); String date = dateFormat.format(DateUtils.getStartOfToday());
String zipFilename = String.format("%s/Loop Habits CSV %s.zip", exportDirName, date); String zipFilename =
String.format("%s/Loop Habits CSV %s.zip", exportDirName, date);
FileOutputStream fos = new FileOutputStream(zipFilename); FileOutputStream fos = new FileOutputStream(zipFilename);
ZipOutputStream zos = new ZipOutputStream(fos); ZipOutputStream zos = new ZipOutputStream(fos);
for(String filename : generateFilenames) for (String filename : generateFilenames)
addFileToZip(zos, filename); addFileToZip(zos, filename);
zos.close(); zos.close();
@ -132,41 +167,4 @@ public class HabitsCSVExporter
return zipFilename; return zipFilename;
} }
private void addFileToZip(ZipOutputStream zos, String filename) throws IOException
{
FileInputStream fis = new FileInputStream(new File(exportDirName + filename));
ZipEntry ze = new ZipEntry(filename);
zos.putNextEntry(ze);
int length;
byte bytes[] = new byte[1024];
while((length = fis.read(bytes)) >= 0)
zos.write(bytes, 0, length);
zos.closeEntry();
fis.close();
}
public String writeArchive() throws IOException
{
String zipFilename;
writeHabits();
zipFilename = writeZipFile();
cleanup();
return zipFilename;
}
private void cleanup()
{
for(String filename : generateFilenames)
new File(exportDirName + filename).delete();
for(String filename : generateDirs)
new File(exportDirName + filename).delete();
new File(exportDirName).delete();
}
} }

@ -25,6 +25,7 @@ import android.support.annotation.NonNull;
import com.activeandroid.ActiveAndroid; import com.activeandroid.ActiveAndroid;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.utils.DatabaseUtils; import org.isoron.uhabits.utils.DatabaseUtils;
import org.isoron.uhabits.utils.FileUtils; import org.isoron.uhabits.utils.FileUtils;
@ -36,6 +37,11 @@ import java.io.IOException;
*/ */
public class LoopDBImporter extends AbstractImporter public class LoopDBImporter extends AbstractImporter
{ {
public LoopDBImporter(HabitList habits)
{
super(habits);
}
@Override @Override
public boolean canHandle(@NonNull File file) throws IOException public boolean canHandle(@NonNull File file) throws IOException
{ {

@ -35,6 +35,11 @@ import java.util.*;
*/ */
public class RewireDBImporter extends AbstractImporter public class RewireDBImporter extends AbstractImporter
{ {
public RewireDBImporter(HabitList habits)
{
super(habits);
}
@Override @Override
public boolean canHandle(@NonNull File file) throws IOException public boolean canHandle(@NonNull File file) throws IOException
{ {
@ -157,7 +162,7 @@ public class RewireDBImporter extends AbstractImporter
} }
habit.setFrequency(new Frequency(numerator, denominator)); habit.setFrequency(new Frequency(numerator, denominator));
habitList.add(habit); habits.add(habit);
createReminder(db, habit, id); createReminder(db, habit, id);
createCheckmarks(db, habit, id); createCheckmarks(db, habit, id);
@ -202,7 +207,7 @@ public class RewireDBImporter extends AbstractImporter
Reminder reminder = new Reminder(hour, minute, days); Reminder reminder = new Reminder(hour, minute, days);
habit.setReminder(reminder); habit.setReminder(reminder);
habitList.update(habit); habits.update(habit);
} }
finally finally
{ {

@ -36,6 +36,11 @@ import java.util.GregorianCalendar;
*/ */
public class TickmateDBImporter extends AbstractImporter public class TickmateDBImporter extends AbstractImporter
{ {
public TickmateDBImporter(HabitList habits)
{
super(habits);
}
@Override @Override
public boolean canHandle(@NonNull File file) throws IOException public boolean canHandle(@NonNull File file) throws IOException
{ {
@ -118,7 +123,7 @@ public class TickmateDBImporter extends AbstractImporter
habit.setName(name); habit.setName(name);
habit.setDescription(description); habit.setDescription(description);
habit.setFrequency(Frequency.DAILY); habit.setFrequency(Frequency.DAILY);
habitList.add(habit); habits.add(habit);
createCheckmarks(db, habit, id); createCheckmarks(db, habit, id);

@ -31,10 +31,13 @@ import java.util.*;
/** /**
* An ordered collection of {@link Habit}s. * An ordered collection of {@link Habit}s.
*/ */
public abstract class HabitList public abstract class HabitList implements Iterable<Habit>
{ {
private ModelObservable observable; private ModelObservable observable;
@NonNull
protected final HabitMatcher filter;
/** /**
* Creates a new HabitList. * Creates a new HabitList.
* <p> * <p>
@ -45,6 +48,15 @@ public abstract class HabitList
public HabitList() public HabitList()
{ {
observable = new ModelObservable(); observable = new ModelObservable();
filter = new HabitMatcherBuilder()
.setArchivedAllowed(true)
.build();
}
protected HabitList(@NonNull HabitMatcher filter)
{
observable = new ModelObservable();
this.filter = filter;
} }
/** /**
@ -61,30 +73,6 @@ public abstract class HabitList
public abstract void add(@NonNull Habit habit) public abstract void add(@NonNull Habit habit)
throws IllegalArgumentException; throws IllegalArgumentException;
/**
* Returns the total number of active habits.
*
* @return number of active habits
*/
public abstract int countActive();
/**
* Returns the total number of habits, including archived habits.
*
* @return number of habits, including archived
*/
public abstract int countWithArchived();
/**
* Returns a list of all habits, optionally including archived habits.
*
* @param includeArchive whether archived habits should be included the
* list
* @return list of all habits
*/
@NonNull
public abstract List<Habit> getAll(boolean includeArchive);
/** /**
* Returns the habit with specified id. * Returns the habit with specified id.
* *
@ -110,30 +98,13 @@ public abstract class HabitList
* @return the list of matching habits * @return the list of matching habits
*/ */
@NonNull @NonNull
public List<Habit> getFiltered(HabitMatcher matcher) public abstract HabitList getFiltered(HabitMatcher matcher);
{
LinkedList<Habit> habits = new LinkedList<>();
for (Habit h : getAll(true)) if (matcher.matches(h)) habits.add(h);
return habits;
}
public ModelObservable getObservable() public ModelObservable getObservable()
{ {
return observable; return observable;
} }
/**
* Returns a list the habits that have a reminder. Does not include archived
* habits.
*
* @return list of habits with reminder
*/
@NonNull
public List<Habit> getWithReminder()
{
return getFiltered(habit -> habit.hasReminder());
}
/** /**
* Returns the index of the given habit in the list, or -1 if the list does * Returns the index of the given habit in the list, or -1 if the list does
* not contain the habit. * not contain the habit.
@ -143,6 +114,11 @@ public abstract class HabitList
*/ */
public abstract int indexOf(@NonNull Habit h); public abstract int indexOf(@NonNull Habit h);
public boolean isEmpty()
{
return size() == 0;
}
/** /**
* Removes the given habit from the list. * Removes the given habit from the list.
* <p> * <p>
@ -152,6 +128,16 @@ public abstract class HabitList
*/ */
public abstract void remove(@NonNull Habit h); public abstract void remove(@NonNull Habit h);
/**
* Removes all the habits from the list.
*/
public void removeAll()
{
List<Habit> copy = new LinkedList<>();
for (Habit h : this) copy.add(h);
for (Habit h : copy) remove(h);
}
/** /**
* Changes the position of a habit in the list. * Changes the position of a habit in the list.
* *
@ -160,6 +146,13 @@ public abstract class HabitList
*/ */
public abstract void reorder(Habit from, Habit to); public abstract void reorder(Habit from, Habit to);
/**
* Returns the number of habits in this list.
*
* @return number of habits
*/
public abstract int size();
/** /**
* Notifies the list that a certain list of habits has been modified. * Notifies the list that a certain list of habits has been modified.
* <p> * <p>
@ -206,7 +199,7 @@ public abstract class HabitList
CSVWriter csv = new CSVWriter(out); CSVWriter csv = new CSVWriter(out);
csv.writeNext(header, false); csv.writeNext(header, false);
for (Habit habit : getAll(true)) for (Habit habit : this)
{ {
Frequency freq = habit.getFrequency(); Frequency freq = habit.getFrequency();
@ -224,19 +217,4 @@ public abstract class HabitList
csv.close(); csv.close();
} }
/**
* A HabitMatcher decides whether habits match or not a certain condition.
* They can be used to produce filtered lists of habits.
*/
public interface HabitMatcher
{
/**
* Returns true if the given habit matches.
*
* @param habit the habit to be checked.
* @return true if matches, false otherwise.
*/
boolean matches(Habit habit);
}
} }

@ -0,0 +1,71 @@
/*
* 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 static org.isoron.uhabits.models.Checkmark.*;
public class HabitMatcher
{
public static final HabitMatcher WITH_ALARM = new HabitMatcherBuilder()
.setArchivedAllowed(true)
.setReminderRequired(true)
.build();
private final boolean archivedAllowed;
private final boolean reminderRequired;
private final boolean completedAllowed;
public HabitMatcher(boolean allowArchived,
boolean reminderRequired,
boolean completedAllowed)
{
this.archivedAllowed = allowArchived;
this.reminderRequired = reminderRequired;
this.completedAllowed = completedAllowed;
}
public boolean isArchivedAllowed()
{
return archivedAllowed;
}
public boolean isCompletedAllowed()
{
return completedAllowed;
}
public boolean isReminderRequired()
{
return reminderRequired;
}
public boolean matches(Habit habit)
{
if (!isArchivedAllowed() && habit.isArchived()) return false;
if (isReminderRequired() && !habit.hasReminder()) return false;
int todayCheckmark = habit.getCheckmarks().getTodayValue();
if (todayCheckmark != UNCHECKED && !isCompletedAllowed()) return false;
return true;
}
}

@ -0,0 +1,53 @@
/*
* 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;
public class HabitMatcherBuilder
{
private boolean archivedAllowed = false;
private boolean reminderRequired = false;
private boolean completedAllowed = true;
public HabitMatcher build()
{
return new HabitMatcher(archivedAllowed, reminderRequired,
completedAllowed);
}
public HabitMatcherBuilder setArchivedAllowed(boolean archivedAllowed)
{
this.archivedAllowed = archivedAllowed;
return this;
}
public HabitMatcherBuilder setCompletedAllowed(boolean completedAllowed)
{
this.completedAllowed = completedAllowed;
return this;
}
public HabitMatcherBuilder setReminderRequired(boolean reminderRequired)
{
this.reminderRequired = reminderRequired;
return this;
}
}

@ -35,6 +35,13 @@ public class MemoryHabitList extends HabitList
public MemoryHabitList() public MemoryHabitList()
{ {
super();
list = new LinkedList<>();
}
protected MemoryHabitList(@NonNull HabitMatcher matcher)
{
super(matcher);
list = new LinkedList<>(); list = new LinkedList<>();
} }
@ -53,45 +60,42 @@ public class MemoryHabitList extends HabitList
} }
@Override @Override
public int countActive() public Habit getById(long id)
{ {
int count = 0; for (Habit h : list)
for (Habit h : list) if (!h.isArchived()) count++; {
return count; if (h.getId() == null) continue;
if (h.getId() == id) return h;
}
return null;
} }
@Nullable
@Override @Override
public int countWithArchived() public Habit getByPosition(int position)
{ {
return list.size(); return list.get(position);
} }
@NonNull @NonNull
@Override @Override
public List<Habit> getAll(boolean includeArchive) public HabitList getFiltered(HabitMatcher matcher)
{
if (includeArchive) return new LinkedList<>(list);
return getFiltered(habit -> !habit.isArchived());
}
@Override
public Habit getById(long id)
{ {
for (Habit h : list) if (h.getId() == id) return h; MemoryHabitList habits = new MemoryHabitList(matcher);
return null; for(Habit h : this) if (matcher.matches(h)) habits.add(h);
return habits;
} }
@Nullable
@Override @Override
public Habit getByPosition(int position) public int indexOf(@NonNull Habit h)
{ {
return list.get(position); return list.indexOf(h);
} }
@Override @Override
public int indexOf(@NonNull Habit h) public Iterator<Habit> iterator()
{ {
return list.indexOf(h); return Collections.unmodifiableCollection(list).iterator();
} }
@Override @Override
@ -108,6 +112,12 @@ public class MemoryHabitList extends HabitList
list.add(toPos, from); list.add(toPos, from);
} }
@Override
public int size()
{
return list.size();
}
@Override @Override
public void update(List<Habit> habits) public void update(List<Habit> habits)
{ {

@ -19,12 +19,11 @@
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.apache.commons.lang3.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.models.sqlite.records.*; import org.isoron.uhabits.models.sqlite.records.*;
@ -41,9 +40,17 @@ public class SQLiteHabitList extends HabitList
private final SQLiteUtils<HabitRecord> sqlite; private final SQLiteUtils<HabitRecord> sqlite;
protected SQLiteHabitList()
{
super();
cache = new HashMap<>();
sqlite = new SQLiteUtils<>(HabitRecord.class);
}
private SQLiteHabitList() protected SQLiteHabitList(
@NonNull org.isoron.uhabits.models.HabitMatcher filter)
{ {
super(filter);
cache = new HashMap<>(); cache = new HashMap<>();
sqlite = new SQLiteUtils<>(HabitRecord.class); sqlite = new SQLiteUtils<>(HabitRecord.class);
} }
@ -70,7 +77,7 @@ public class SQLiteHabitList extends HabitList
HabitRecord record = new HabitRecord(); HabitRecord record = new HabitRecord();
record.copyFrom(habit); record.copyFrom(habit);
record.position = countWithArchived(); record.position = size();
Long id = habit.getId(); Long id = habit.getId();
if (id == null) id = record.save(); if (id == null) id = record.save();
@ -80,52 +87,6 @@ public class SQLiteHabitList extends HabitList
cache.put(id, habit); cache.put(id, habit);
} }
@Override
public int countActive()
{
SQLiteDatabase db = Cache.openDatabase();
SQLiteStatement st = db.compileStatement(
"select count(*) from habits where archived = 0");
return (int) st.simpleQueryForLong();
}
@Override
public int countWithArchived()
{
SQLiteDatabase db = Cache.openDatabase();
SQLiteStatement st = db.compileStatement("select count(*) from habits");
return (int) st.simpleQueryForLong();
}
@Override
@NonNull
public List<Habit> getAll(boolean includeArchive)
{
List<HabitRecord> recordList;
if (includeArchive)
{
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<>();
for (HabitRecord record : recordList)
{
Habit habit = getById(record.getId());
if (habit == null)
throw new RuntimeException("habit not in database");
habits.add(habit);
}
return habits;
}
@Override @Override
@Nullable @Nullable
public Habit getById(long id) public Habit getById(long id)
@ -147,26 +108,36 @@ public class SQLiteHabitList extends HabitList
@Nullable @Nullable
public Habit getByPosition(int position) public Habit getByPosition(int position)
{ {
String query = HabitRecord.SELECT + "where position = ? limit 1"; String query = buildSelectQuery() + "limit 1 offset ?";
String params[] = { Integer.toString(position) }; String params[] = { Integer.toString(position) };
HabitRecord record = sqlite.querySingle(query, params); HabitRecord record = sqlite.querySingle(query, params);
if (record != null) return getById(record.getId()); if (record != null) return getById(record.getId());
return null; return null;
} }
@NonNull
@Override
public HabitList getFiltered(org.isoron.uhabits.models.HabitMatcher filter)
{
return new SQLiteHabitList(filter);
}
@Override @Override
public int indexOf(@NonNull Habit h) public int indexOf(@NonNull Habit h)
{ {
if (h.getId() == null) return -1; return toList().indexOf(h);
HabitRecord record = HabitRecord.get(h.getId()); }
if (record == null) return -1;
return record.position; @Override
public Iterator<Habit> iterator()
{
return Collections.unmodifiableCollection(toList()).iterator();
} }
@Deprecated @Deprecated
public void rebuildOrder() public void rebuildOrder()
{ {
List<Habit> habits = getAll(true); List<Habit> habits = toList();
int i = 0; int i = 0;
for (Habit h : habits) for (Habit h : habits)
@ -195,6 +166,16 @@ public class SQLiteHabitList extends HabitList
rebuildOrder(); rebuildOrder();
} }
@Override
public void removeAll()
{
sqlite.query("delete from checkmarks", null);
sqlite.query("delete from score", null);
sqlite.query("delete from streak", null);
sqlite.query("delete from repetitions", null);
sqlite.query("delete from habits", null);
}
@Override @Override
public void reorder(Habit from, Habit to) public void reorder(Habit from, Habit to)
{ {
@ -228,6 +209,16 @@ public class SQLiteHabitList extends HabitList
getObservable().notifyListeners(); getObservable().notifyListeners();
} }
@Override
public int size()
{
// SQLiteDatabase db = Cache.openDatabase();
// SQLiteStatement st = db.compileStatement(buildCountQuery());
// return (int) st.simpleQueryForLong();
return toList().size();
}
@Override @Override
public void update(List<Habit> habits) public void update(List<Habit> habits)
{ {
@ -241,4 +232,66 @@ public class SQLiteHabitList extends HabitList
} }
} }
protected List<Habit> toList()
{
String query = buildSelectQuery();
List<HabitRecord> recordList = sqlite.query(query, null);
List<Habit> habits = new LinkedList<>();
for (HabitRecord record : recordList)
{
Habit habit = getById(record.getId());
if (habit == null)
throw new RuntimeException("habit not in database");
if(!filter.matches(habit)) continue;
habits.add(habit);
}
return habits;
}
private void appendCount(StringBuilder query)
{
query.append("select count (*) from habits ");
}
private void appendOrderBy(StringBuilder query)
{
query.append("order by position ");
}
private void appendSelect(StringBuilder query)
{
query.append(HabitRecord.SELECT);
}
private void appendWhere(StringBuilder query)
{
ArrayList<Object> where = new ArrayList<>();
if (filter.isReminderRequired()) where.add("reminder_hour is not null");
if (!filter.isArchivedAllowed()) where.add("archived = 0");
if(where.isEmpty()) return;
query.append("where ");
query.append(StringUtils.join(where, " and "));
query.append(" ");
}
private String buildCountQuery()
{
StringBuilder query = new StringBuilder();
appendCount(query);
appendWhere(query);
return query.toString();
}
private String buildSelectQuery()
{
StringBuilder query = new StringBuilder();
appendSelect(query);
appendWhere(query);
appendOrderBy(query);
return query.toString();
}
} }

@ -82,7 +82,6 @@ public class HabitRecord extends Model implements SQLiteRecord
public HabitRecord() public HabitRecord()
{ {
} }
@Nullable @Nullable
@ -149,7 +148,7 @@ public class HabitRecord extends Model implements SQLiteRecord
this.freqNum = freq.getNumerator(); this.freqNum = freq.getNumerator();
this.freqDen = freq.getDenominator(); this.freqDen = freq.getDenominator();
if(model.hasReminder()) if (model.hasReminder())
{ {
Reminder reminder = model.getReminder(); Reminder reminder = model.getReminder();
this.reminderHour = reminder.getHour(); this.reminderHour = reminder.getHour();

@ -19,30 +19,33 @@
package org.isoron.uhabits.tasks; package org.isoron.uhabits.tasks;
import android.support.annotation.Nullable; import android.support.annotation.*;
import org.isoron.uhabits.io.HabitsCSVExporter; import org.isoron.uhabits.io.*;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.utils.FileUtils; import org.isoron.uhabits.utils.*;
import java.io.File; import java.io.*;
import java.io.IOException; import java.util.*;
import java.util.List;
public class ExportCSVTask extends BaseTask public class ExportCSVTask extends BaseTask
{ {
public interface Listener
{
void onExportCSVFinished(@Nullable String archiveFilename);
}
private ProgressBar progressBar; private ProgressBar progressBar;
private final List<Habit> selectedHabits; private final List<Habit> selectedHabits;
private String archiveFilename; private String archiveFilename;
private ExportCSVTask.Listener listener; private ExportCSVTask.Listener listener;
public ExportCSVTask(List<Habit> selectedHabits, ProgressBar progressBar) @NonNull
private final HabitList habitList;
public ExportCSVTask(HabitList habitList,
List<Habit> selectedHabits,
ProgressBar progressBar)
{ {
this.habitList = habitList;
this.selectedHabits = selectedHabits; this.selectedHabits = selectedHabits;
this.progressBar = progressBar; this.progressBar = progressBar;
} }
@ -53,36 +56,41 @@ public class ExportCSVTask extends BaseTask
} }
@Override @Override
protected void onPreExecute() protected void doInBackground()
{ {
super.onPreExecute(); try
if(progressBar != null) progressBar.show(); {
File dir = FileUtils.getFilesDir("CSV");
if (dir == null) return;
HabitsCSVExporter exporter =
new HabitsCSVExporter(habitList, selectedHabits, dir);
archiveFilename = exporter.writeArchive();
}
catch (IOException e)
{
e.printStackTrace();
}
} }
@Override @Override
protected void onPostExecute(Void aVoid) protected void onPostExecute(Void aVoid)
{ {
if(listener != null) if (listener != null) listener.onExportCSVFinished(archiveFilename);
listener.onExportCSVFinished(archiveFilename);
if(progressBar != null) progressBar.hide(); if (progressBar != null) progressBar.hide();
super.onPostExecute(null); super.onPostExecute(null);
} }
@Override @Override
protected void doInBackground() protected void onPreExecute()
{ {
try super.onPreExecute();
{ if (progressBar != null) progressBar.show();
File dir = FileUtils.getFilesDir("CSV"); }
if(dir == null) return;
HabitsCSVExporter exporter = new HabitsCSVExporter(selectedHabits, dir); public interface Listener
archiveFilename = exporter.writeArchive(); {
} void onExportCSVFinished(@Nullable String archiveFilename);
catch (IOException e)
{
e.printStackTrace();
}
} }
} }

@ -19,23 +19,20 @@
package org.isoron.uhabits.tasks; package org.isoron.uhabits.tasks;
import android.support.annotation.NonNull; import android.support.annotation.*;
import android.support.annotation.Nullable;
import org.isoron.uhabits.io.GenericImporter; import org.isoron.uhabits.io.*;
import org.isoron.uhabits.models.*;
import java.io.File; import java.io.*;
public class ImportDataTask extends BaseTask public class ImportDataTask extends BaseTask
{ {
public static final int SUCCESS = 1;
public static final int NOT_RECOGNIZED = 2;
public static final int FAILED = 3; public static final int FAILED = 3;
public interface Listener public static final int NOT_RECOGNIZED = 2;
{
void onImportDataFinished(int result); public static final int SUCCESS = 1;
}
@Nullable @Nullable
private final ProgressBar progressBar; private final ProgressBar progressBar;
@ -48,8 +45,14 @@ public class ImportDataTask extends BaseTask
int result; int result;
public ImportDataTask(@NonNull File file, @Nullable ProgressBar progressBar) @NonNull
private HabitList habits;
public ImportDataTask(@NonNull HabitList habits,
@NonNull File file,
@Nullable ProgressBar progressBar)
{ {
this.habits = habits;
this.file = file; this.file = file;
this.progressBar = progressBar; this.progressBar = progressBar;
} }
@ -59,29 +62,13 @@ public class ImportDataTask extends BaseTask
this.listener = listener; this.listener = listener;
} }
@Override
protected void onPreExecute()
{
super.onPreExecute();
if(progressBar != null) progressBar.show();
}
@Override
protected void onPostExecute(Void aVoid)
{
if(progressBar != null) progressBar.hide();
if(listener != null) listener.onImportDataFinished(result);
super.onPostExecute(null);
}
@Override @Override
protected void doInBackground() protected void doInBackground()
{ {
try try
{ {
GenericImporter importer = new GenericImporter(); GenericImporter importer = new GenericImporter(habits);
if(importer.canHandle(file)) if (importer.canHandle(file))
{ {
importer.importHabitsFromFile(file); importer.importHabitsFromFile(file);
result = SUCCESS; result = SUCCESS;
@ -97,4 +84,25 @@ public class ImportDataTask extends BaseTask
e.printStackTrace(); e.printStackTrace();
} }
} }
@Override
protected void onPostExecute(Void aVoid)
{
if (progressBar != null) progressBar.hide();
if (listener != null) listener.onImportDataFinished(result);
super.onPostExecute(null);
}
@Override
protected void onPreExecute()
{
super.onPreExecute();
if (progressBar != null) progressBar.show();
}
public interface Listener
{
void onImportDataFinished(int result);
}
} }

@ -40,9 +40,10 @@ public class CreateHabitDialogFragment extends BaseDialogFragment
prefs.getDefaultHabitColor(modifiedHabit.getColor())); prefs.getDefaultHabitColor(modifiedHabit.getColor()));
} }
@Override
protected void saveHabit() protected void saveHabit()
{ {
Command command = new CreateHabitCommand(modifiedHabit); Command command = new CreateHabitCommand(habitList, modifiedHabit);
commandRunner.execute(command, null); commandRunner.execute(command, null);
} }
} }

@ -19,12 +19,11 @@
package org.isoron.uhabits.ui.habits.edit; package org.isoron.uhabits.ui.habits.edit;
import android.os.Bundle; import android.os.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.*;
import org.isoron.uhabits.commands.Command; import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.commands.EditHabitCommand; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.models.Habit;
public class EditHabitDialogFragment extends BaseDialogFragment public class EditHabitDialogFragment extends BaseDialogFragment
{ {
@ -58,7 +57,8 @@ public class EditHabitDialogFragment extends BaseDialogFragment
@Override @Override
protected void saveHabit() protected void saveHabit()
{ {
Command command = new EditHabitCommand(originalHabit, modifiedHabit); Command command =
new EditHabitCommand(habitList, originalHabit, modifiedHabit);
commandRunner.execute(command, originalHabit.getId()); commandRunner.execute(command, originalHabit.getId());
} }
} }

@ -34,7 +34,7 @@ import javax.inject.*;
public class ListHabitsActivity extends BaseActivity public class ListHabitsActivity extends BaseActivity
{ {
@Inject @Inject
HabitList habitList; HabitList habits;
private HabitCardListAdapter adapter; private HabitCardListAdapter adapter;
@ -59,14 +59,22 @@ public class ListHabitsActivity extends BaseActivity
int checkmarkCount = ListHabitsRootView.MAX_CHECKMARK_COUNT; int checkmarkCount = ListHabitsRootView.MAX_CHECKMARK_COUNT;
system = new BaseSystem(this); system = new BaseSystem(this);
adapter = new HabitCardListAdapter(checkmarkCount); adapter = new HabitCardListAdapter(habits, checkmarkCount);
// HabitMatcher matcher = new HabitMatcherBuilder()
// .setCompletedAllowed(false)
// .setArchivedAllowed(false)
// .build();
// adapter.setFilter(matcher);
rootView = new ListHabitsRootView(this, adapter); rootView = new ListHabitsRootView(this, adapter);
screen = new ListHabitsScreen(this, rootView); screen = new ListHabitsScreen(this, rootView);
menu = new ListHabitsMenu(this, screen, adapter); menu = new ListHabitsMenu(this, screen, adapter);
selectionMenu = new ListHabitsSelectionMenu(screen, adapter); selectionMenu = new ListHabitsSelectionMenu(habits, screen, adapter);
controller = new ListHabitsController(screen, system, habitList); controller = new ListHabitsController(habits, screen, system);
screen.setMenu(menu); screen.setMenu(menu);
screen.setController(controller);
screen.setSelectionMenu(selectionMenu); screen.setSelectionMenu(selectionMenu);
rootView.setController(controller, selectionMenu); rootView.setController(controller, selectionMenu);

@ -31,6 +31,7 @@ import org.isoron.uhabits.ui.habits.list.controllers.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
import java.io.*; import java.io.*;
import java.util.*;
import javax.inject.*; import javax.inject.*;
@ -52,9 +53,9 @@ public class ListHabitsController
@Inject @Inject
CommandRunner commandRunner; CommandRunner commandRunner;
public ListHabitsController(@NonNull ListHabitsScreen screen, public ListHabitsController(@NonNull HabitList habitList,
@NonNull BaseSystem system, @NonNull ListHabitsScreen screen,
@NonNull HabitList habitList) @NonNull BaseSystem system)
{ {
this.screen = screen; this.screen = screen;
this.system = system; this.system = system;
@ -64,8 +65,13 @@ public class ListHabitsController
public void onExportCSV() public void onExportCSV()
{ {
List<Habit> selected = new LinkedList<>();
for (Habit h : habitList) selected.add(h);
ProgressBar progressBar = screen.getProgressBar();
ExportCSVTask task = ExportCSVTask task =
new ExportCSVTask(habitList.getAll(true), screen.getProgressBar()); new ExportCSVTask(habitList, selected, progressBar);
task.setListener(filename -> { task.setListener(filename -> {
if (filename != null) screen.showSendFileScreen(filename); if (filename != null) screen.showSendFileScreen(filename);
else screen.showMessage(R.string.could_not_export); else screen.showMessage(R.string.could_not_export);
@ -97,7 +103,8 @@ public class ListHabitsController
public void onImportData(@NonNull File file) public void onImportData(@NonNull File file)
{ {
ImportDataTask task = new ImportDataTask(file, screen.getProgressBar()); ProgressBar bar = screen.getProgressBar();
ImportDataTask task = new ImportDataTask(habitList, file, bar);
task.setListener(this); task.setListener(this);
task.execute(); task.execute();
} }

@ -76,6 +76,11 @@ public class ListHabitsScreen extends BaseScreen
} }
} }
public void setController(@Nullable ListHabitsController controller)
{
this.controller = controller;
}
public void showAboutScreen() public void showAboutScreen()
{ {
Intent intent = new Intent(activity, AboutActivity.class); Intent intent = new Intent(activity, AboutActivity.class);

@ -48,9 +48,14 @@ public class ListHabitsSelectionMenu extends BaseSelectionMenu
@Nullable @Nullable
private HabitCardListController listController; private HabitCardListController listController;
public ListHabitsSelectionMenu(@NonNull ListHabitsScreen screen, @NonNull
HabitCardListAdapter listAdapter) private final HabitList habitList;
public ListHabitsSelectionMenu(@NonNull HabitList habitList,
@NonNull ListHabitsScreen screen,
@NonNull HabitCardListAdapter listAdapter)
{ {
this.habitList = habitList;
this.screen = screen; this.screen = screen;
HabitsApplication.getComponent().inject(this); HabitsApplication.getComponent().inject(this);
this.listAdapter = listAdapter; this.listAdapter = listAdapter;
@ -161,13 +166,15 @@ public class ListHabitsSelectionMenu extends BaseSelectionMenu
private void archive(@NonNull List<Habit> selected) private void archive(@NonNull List<Habit> selected)
{ {
commandRunner.execute(new ArchiveHabitsCommand(selected), null); commandRunner.execute(new ArchiveHabitsCommand(habitList, selected),
null);
} }
private void delete(@NonNull List<Habit> selected) private void delete(@NonNull List<Habit> selected)
{ {
screen.showDeleteConfirmationScreen(() -> { screen.showDeleteConfirmationScreen(() -> {
commandRunner.execute(new DeleteHabitsCommand(selected), null); commandRunner.execute(new DeleteHabitsCommand(habitList, selected),
null);
finish(); finish();
}); });
} }
@ -181,14 +188,15 @@ public class ListHabitsSelectionMenu extends BaseSelectionMenu
@NonNull Habit firstHabit) @NonNull Habit firstHabit)
{ {
screen.showColorPicker(firstHabit, color -> { screen.showColorPicker(firstHabit, color -> {
commandRunner.execute(new ChangeHabitColorCommand(selected, color), commandRunner.execute(
null); new ChangeHabitColorCommand(habitList, selected, color), null);
finish(); finish();
}); });
} }
private void unarchive(@NonNull List<Habit> selected) private void unarchive(@NonNull List<Habit> selected)
{ {
commandRunner.execute(new UnarchiveHabitsCommand(selected), null); commandRunner.execute(new UnarchiveHabitsCommand(habitList, selected),
null);
} }
} }

@ -50,14 +50,15 @@ public class HabitCardListAdapter extends BaseAdapter
@NonNull @NonNull
private final HabitCardListCache cache; private final HabitCardListCache cache;
public HabitCardListAdapter(int checkmarkCount) public HabitCardListAdapter(@NonNull HabitList allHabits,
int checkmarkCount)
{ {
this.selected = new LinkedList<>(); this.selected = new LinkedList<>();
this.observable = new ModelObservable(); this.observable = new ModelObservable();
HabitsApplication.getComponent().inject(this); HabitsApplication.getComponent().inject(this);
cache = new HabitCardListCache(); cache = new HabitCardListCache(allHabits);
cache.setListener(this); cache.setListener(this);
cache.setCheckmarkCount(checkmarkCount); cache.setCheckmarkCount(checkmarkCount);
} }
@ -185,6 +186,11 @@ public class HabitCardListAdapter extends BaseAdapter
cache.reorder(from, to); cache.reorder(from, to);
} }
public void setFilter(HabitMatcher matcher)
{
cache.setFilter(matcher);
}
/** /**
* Sets the HabitCardListView that this adapter will provide data for. * Sets the HabitCardListView that this adapter will provide data for.
* <p> * <p>

@ -60,19 +60,23 @@ public class HabitCardListCache implements CommandRunner.Listener
@Inject @Inject
CommandRunner commandRunner; CommandRunner commandRunner;
@Inject @NonNull
HabitList allHabits; private HabitList allHabits;
@NonNull
private HabitList filteredHabits;
public HabitCardListCache() public HabitCardListCache(@NonNull HabitList allHabits)
{ {
this.allHabits = allHabits;
this.filteredHabits = allHabits;
data = new CacheData(); data = new CacheData();
HabitsApplication.getComponent().inject(this); HabitsApplication.getComponent().inject(this);
} }
public void cancelTasks() public void cancelTasks()
{ {
if(currentFetchTask != null) if (currentFetchTask != null) currentFetchTask.cancel(true);
currentFetchTask.cancel(true);
} }
public int[] getCheckmarks(long habitId) public int[] getCheckmarks(long habitId)
@ -90,7 +94,7 @@ public class HabitCardListCache implements CommandRunner.Listener
@NonNull @NonNull
public Habit getHabitByPosition(int position) public Habit getHabitByPosition(int position)
{ {
return data.habitsList.get(position); return data.habits.get(position);
} }
public int getHabitCount() public int getHabitCount()
@ -98,6 +102,16 @@ public class HabitCardListCache implements CommandRunner.Listener
return data.habits.size(); return data.habits.size();
} }
public boolean getIncludeArchived()
{
return includeArchived;
}
public void setIncludeArchived(boolean includeArchived)
{
this.includeArchived = includeArchived;
}
@Nullable @Nullable
public Long getLastLoadTimestamp() public Long getLastLoadTimestamp()
{ {
@ -109,11 +123,6 @@ public class HabitCardListCache implements CommandRunner.Listener
return data.scores.get(habitId); return data.scores.get(habitId);
} }
public boolean getIncludeArchived()
{
return includeArchived;
}
public void onAttached() public void onAttached()
{ {
refreshAllHabits(true); refreshAllHabits(true);
@ -149,10 +158,10 @@ public class HabitCardListCache implements CommandRunner.Listener
public void reorder(int from, int to) public void reorder(int from, int to)
{ {
Habit fromHabit = data.habitsList.get(from); Habit fromHabit = data.habits.get(from);
data.habitsList.remove(from); data.habits.remove(from);
data.habitsList.add(to, fromHabit); data.habits.add(to, fromHabit);
if(listener != null) listener.onCacheRefresh(); if (listener != null) listener.onCacheRefresh();
} }
public void setCheckmarkCount(int checkmarkCount) public void setCheckmarkCount(int checkmarkCount)
@ -160,9 +169,9 @@ public class HabitCardListCache implements CommandRunner.Listener
this.checkmarkCount = checkmarkCount; this.checkmarkCount = checkmarkCount;
} }
public void setIncludeArchived(boolean includeArchived) public void setFilter(HabitMatcher matcher)
{ {
this.includeArchived = includeArchived; filteredHabits = allHabits.getFiltered(matcher);
} }
public void setListener(@Nullable Listener listener) public void setListener(@Nullable Listener listener)
@ -185,10 +194,10 @@ public class HabitCardListCache implements CommandRunner.Listener
private class CacheData private class CacheData
{ {
@NonNull @NonNull
public HashMap<Long, Habit> habits; public HashMap<Long, Habit> map;
@NonNull @NonNull
public List<Habit> habitsList; public List<Habit> habits;
@NonNull @NonNull
public HashMap<Long, int[]> checkmarks; public HashMap<Long, int[]> checkmarks;
@ -201,8 +210,8 @@ public class HabitCardListCache implements CommandRunner.Listener
*/ */
public CacheData() public CacheData()
{ {
habits = new HashMap<>(); map = new HashMap<>();
habitsList = new LinkedList<>(); habits = new LinkedList<>();
checkmarks = new HashMap<>(); checkmarks = new HashMap<>();
scores = new HashMap<>(); scores = new HashMap<>();
} }
@ -211,7 +220,7 @@ public class HabitCardListCache implements CommandRunner.Listener
{ {
int[] empty = new int[checkmarkCount]; int[] empty = new int[checkmarkCount];
for (Long id : habits.keySet()) for (Long id : map.keySet())
{ {
if (oldData.checkmarks.containsKey(id)) if (oldData.checkmarks.containsKey(id))
checkmarks.put(id, oldData.checkmarks.get(id)); checkmarks.put(id, oldData.checkmarks.get(id));
@ -221,7 +230,7 @@ public class HabitCardListCache implements CommandRunner.Listener
public void copyScoresFrom(@NonNull CacheData oldData) public void copyScoresFrom(@NonNull CacheData oldData)
{ {
for (Long id : habits.keySet()) for (Long id : map.keySet())
{ {
if (oldData.scores.containsKey(id)) if (oldData.scores.containsKey(id))
scores.put(id, oldData.scores.get(id)); scores.put(id, oldData.scores.get(id));
@ -231,9 +240,11 @@ public class HabitCardListCache implements CommandRunner.Listener
public void fetchHabits() public void fetchHabits()
{ {
habitsList = allHabits.getAll(includeArchived); for (Habit h : filteredHabits)
for (Habit h : habitsList) {
habits.put(h.getId(), h); habits.add(h);
map.put(h.getId(), h);
}
} }
} }
@ -250,11 +261,6 @@ public class HabitCardListCache implements CommandRunner.Listener
newData = new CacheData(); newData = new CacheData();
} }
private void commit()
{
data = newData;
}
@Override @Override
protected void doInBackground() protected void doInBackground()
{ {
@ -272,7 +278,7 @@ public class HabitCardListCache implements CommandRunner.Listener
dateTo - (checkmarkCount - 1) * DateUtils.millisecondsInOneDay; dateTo - (checkmarkCount - 1) * DateUtils.millisecondsInOneDay;
int current = 0; int current = 0;
for (Habit h : newData.habitsList) for (Habit h : newData.habits)
{ {
if (isCancelled()) return; if (isCancelled()) return;
@ -282,19 +288,7 @@ public class HabitCardListCache implements CommandRunner.Listener
h.getCheckmarks().getValues(dateFrom, dateTo)); h.getCheckmarks().getValues(dateFrom, dateTo));
// sleep(1000); // sleep(1000);
publishProgress(current++, newData.habits.size()); publishProgress(current++, newData.map.size());
}
}
private void sleep(int time)
{
try
{
Thread.sleep(time);
}
catch (InterruptedException e)
{
e.printStackTrace();
} }
} }
@ -316,6 +310,23 @@ public class HabitCardListCache implements CommandRunner.Listener
if (listener != null) listener.onCacheRefresh(); if (listener != null) listener.onCacheRefresh();
} }
private void commit()
{
data = newData;
}
private void sleep(int time)
{
try
{
Thread.sleep(time);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
} }
private class RefreshHabitTask extends BaseTask private class RefreshHabitTask extends BaseTask
@ -337,9 +348,10 @@ public class HabitCardListCache implements CommandRunner.Listener
Habit h = allHabits.getById(id); Habit h = allHabits.getById(id);
if (h == null) return; if (h == null) return;
data.habits.put(id, h); data.map.put(id, h);
data.scores.put(id, h.getScores().getTodayValue()); data.scores.put(id, h.getScores().getTodayValue());
data.checkmarks.put(id, h.getCheckmarks().getValues(dateFrom, dateTo)); data.checkmarks.put(id,
h.getCheckmarks().getValues(dateFrom, dateTo));
} }
@Override @Override

@ -38,7 +38,7 @@ import javax.inject.*;
public class ShowHabitActivity extends BaseActivity public class ShowHabitActivity extends BaseActivity
{ {
@Inject @Inject
HabitList habitList; HabitList habits;
private ShowHabitController controller; private ShowHabitController controller;
@ -70,7 +70,7 @@ public class ShowHabitActivity extends BaseActivity
private Habit getHabitFromIntent() private Habit getHabitFromIntent()
{ {
Uri data = getIntent().getData(); Uri data = getIntent().getData();
Habit habit = habitList.getById(ContentUris.parseId(data)); Habit habit = habits.getById(ContentUris.parseId(data));
if (habit == null) throw new RuntimeException("habit not found"); if (habit == null) throw new RuntimeException("habit not found");
return habit; return habit;
} }

@ -82,8 +82,7 @@ public class HabitPickerDialog extends Activity
habitIds = new ArrayList<>(); habitIds = new ArrayList<>();
ArrayList<String> habitNames = new ArrayList<>(); ArrayList<String> habitNames = new ArrayList<>();
List<Habit> habits = habitList.getAll(false); for (Habit h : habitList)
for (Habit h : habits)
{ {
habitIds.add(h.getId()); habitIds.add(h.getId());
habitNames.add(h.getName()); habitNames.add(h.getName());

@ -85,16 +85,17 @@ public abstract class ReminderUtils
pendingIntent); pendingIntent);
else manager.set(AlarmManager.RTC_WAKEUP, reminderTime, pendingIntent); else manager.set(AlarmManager.RTC_WAKEUP, reminderTime, pendingIntent);
String name = habit.getName().substring(0, Math.min(3, habit.getName().length())); String name =
habit.getName().substring(0, Math.min(3, habit.getName().length()));
Log.d("ReminderHelper", String.format("Setting alarm (%s): %s", Log.d("ReminderHelper", String.format("Setting alarm (%s): %s",
DateFormat.getDateTimeInstance().format(new Date(reminderTime)), DateFormat.getDateTimeInstance().format(new Date(reminderTime)),
name)); name));
} }
public static void createReminderAlarms(Context context, public static void createReminderAlarms(Context context, HabitList habits)
HabitList habitList)
{ {
for (Habit habit : habitList.getWithReminder()) HabitList reminderHabits = habits.getFiltered(HabitMatcher.WITH_ALARM);
for (Habit habit : reminderHabits)
createReminderAlarm(context, habit, null); createReminderAlarm(context, habit, null);
} }

@ -39,7 +39,7 @@ import static org.isoron.uhabits.utils.WidgetUtils.*;
public abstract class BaseWidgetProvider extends AppWidgetProvider public abstract class BaseWidgetProvider extends AppWidgetProvider
{ {
@Inject @Inject
HabitList habitList; HabitList habits;
@Inject @Inject
WidgetPreferences widgetPrefs; WidgetPreferences widgetPrefs;
@ -105,7 +105,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
protected Habit getHabitFromWidgetId(int widgetId) protected Habit getHabitFromWidgetId(int widgetId)
{ {
long habitId = widgetPrefs.getHabitIdFromWidgetId(widgetId); long habitId = widgetPrefs.getHabitIdFromWidgetId(widgetId);
Habit habit = habitList.getById(habitId); Habit habit = habits.getById(habitId);
if (habit == null) throw new RuntimeException("habit not found"); if (habit == null) throw new RuntimeException("habit not found");
return habit; return habit;
} }

@ -40,7 +40,8 @@ public class ArchiveHabitsCommandTest extends BaseUnitTest
super.setUp(); super.setUp();
habit = fixtures.createShortHabit(); habit = fixtures.createShortHabit();
command = new ArchiveHabitsCommand(Collections.singletonList(habit)); command = new ArchiveHabitsCommand(habitList, Collections
.singletonList(habit));
} }
@Test @Test

@ -49,7 +49,7 @@ public class ChangeHabitColorCommandTest extends BaseUnitTest
habits.add(habit); habits.add(habit);
} }
command = new ChangeHabitColorCommand(habits, 0); command = new ChangeHabitColorCommand(habitList, habits, 0);
} }
@Test @Test

@ -23,8 +23,6 @@ import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.junit.*; import org.junit.*;
import java.util.*;
import static junit.framework.Assert.*; import static junit.framework.Assert.*;
import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.MatcherAssert.*;
@ -44,32 +42,30 @@ public class CreateHabitCommandTest extends BaseUnitTest
model = new Habit(); model = new Habit();
model.setName("New habit"); model.setName("New habit");
command = new CreateHabitCommand(model); command = new CreateHabitCommand(habitList, model);
fixtures.purgeHabits(); fixtures.purgeHabits();
} }
@Test @Test
public void testExecuteUndoRedo() public void testExecuteUndoRedo()
{ {
assertTrue(habitList.getAll(true).isEmpty()); assertTrue(habitList.isEmpty());
command.execute(); command.execute();
List<Habit> allHabits = habitList.getAll(true); assertThat(habitList.size(), equalTo(1));
assertThat(allHabits.size(), equalTo(1));
Habit habit = allHabits.get(0); Habit habit = habitList.getByPosition(0);
Long id = habit.getId(); Long id = habit.getId();
assertThat(habit.getName(), equalTo(model.getName())); assertThat(habit.getName(), equalTo(model.getName()));
command.undo(); command.undo();
assertTrue(habitList.getAll(true).isEmpty()); assertTrue(habitList.isEmpty());
command.execute(); command.execute();
allHabits = habitList.getAll(true); assertThat(habitList.size(), equalTo(1));
assertThat(allHabits.size(), equalTo(1));
habit = allHabits.get(0); habit = habitList.getByPosition(0);
Long newId = habit.getId(); Long newId = habit.getId();
assertThat(id, equalTo(newId)); assertThat(id, equalTo(newId));
assertThat(habit.getName(), equalTo(model.getName())); assertThat(habit.getName(), equalTo(model.getName()));

@ -58,17 +58,17 @@ public class DeleteHabitsCommandTest extends BaseUnitTest
Habit extraHabit = fixtures.createShortHabit(); Habit extraHabit = fixtures.createShortHabit();
extraHabit.setName("extra"); extraHabit.setName("extra");
command = new DeleteHabitsCommand(habits); command = new DeleteHabitsCommand(habitList, habits);
} }
@Test @Test
public void testExecuteUndoRedo() public void testExecuteUndoRedo()
{ {
assertThat(habitList.getAll(true).size(), equalTo(4)); assertThat(habitList.size(), equalTo(4));
command.execute(); command.execute();
assertThat(habitList.getAll(true).size(), equalTo(1)); assertThat(habitList.size(), equalTo(1));
assertThat(habitList.getAll(true).get(0).getName(), equalTo("extra")); assertThat(habitList.getByPosition(0).getName(), equalTo("extra"));
thrown.expect(UnsupportedOperationException.class); thrown.expect(UnsupportedOperationException.class);
command.undo(); command.undo();

@ -53,7 +53,7 @@ public class EditHabitCommandTest extends BaseUnitTest
@Test @Test
public void testExecuteUndoRedo() public void testExecuteUndoRedo()
{ {
command = new EditHabitCommand(habit, modified); command = new EditHabitCommand(habitList, habit, modified);
int originalScore = habit.getScores().getTodayValue(); int originalScore = habit.getScores().getTodayValue();
assertThat(habit.getName(), equalTo("original")); assertThat(habit.getName(), equalTo("original"));
@ -75,7 +75,7 @@ public class EditHabitCommandTest extends BaseUnitTest
public void testExecuteUndoRedo_withModifiedInterval() public void testExecuteUndoRedo_withModifiedInterval()
{ {
modified.setFrequency(Frequency.TWO_TIMES_PER_WEEK); modified.setFrequency(Frequency.TWO_TIMES_PER_WEEK);
command = new EditHabitCommand(habit, modified); command = new EditHabitCommand(habitList, habit, modified);
int originalScore = habit.getScores().getTodayValue(); int originalScore = habit.getScores().getTodayValue();
assertThat(habit.getName(), equalTo("original")); assertThat(habit.getName(), equalTo("original"));

@ -42,7 +42,9 @@ public class UnarchiveHabitsCommandTest extends BaseUnitTest
habit.setArchived(true); habit.setArchived(true);
habitList.update(habit); habitList.update(habit);
command = new UnarchiveHabitsCommand(Collections.singletonList(habit)); command = new UnarchiveHabitsCommand(habitList, Collections
.singletonList
(habit));
} }
@Test @Test

@ -83,7 +83,6 @@ public class HabitFixtures
public void purgeHabits() public void purgeHabits()
{ {
for (Habit h : habitList.getAll(true)) habitList.removeAll();
habitList.remove(h);
} }
} }

@ -32,93 +32,90 @@ import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsEqual.equalTo;
@SuppressWarnings("JavaDoc")
public class HabitListTest extends BaseUnitTest public class HabitListTest extends BaseUnitTest
{ {
private HabitList list; private HabitList allHabits;
private ArrayList<Habit> habits; private ArrayList<Habit> habitsArray;
private HabitList activeHabits;
private HabitList reminderHabits;
@Override @Override
public void setUp() public void setUp()
{ {
super.setUp(); super.setUp();
list = modelFactory.buildHabitList(); allHabits = modelFactory.buildHabitList();
habits = new ArrayList<>(); habitsArray = new ArrayList<>();
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
Habit habit = new Habit(); Habit habit = new Habit();
habit.setId((long) i); habit.setId((long) i);
habits.add(habit); habitsArray.add(habit);
list.add(habit); allHabits.add(habit);
if (i % 3 == 0) if (i % 3 == 0)
habit.setReminder(new Reminder(8, 30, DateUtils.ALL_WEEK_DAYS)); habit.setReminder(new Reminder(8, 30, DateUtils.ALL_WEEK_DAYS));
} }
habits.get(0).setArchived(true); habitsArray.get(0).setArchived(true);
habits.get(1).setArchived(true); habitsArray.get(1).setArchived(true);
habits.get(4).setArchived(true); habitsArray.get(4).setArchived(true);
habits.get(7).setArchived(true); habitsArray.get(7).setArchived(true);
}
activeHabits = allHabits.getFiltered(
@Test new HabitMatcherBuilder().build());
public void test_count() reminderHabits = allHabits.getFiltered(new HabitMatcherBuilder()
{ .setArchivedAllowed(true)
assertThat(list.countActive(), equalTo(6)); .setReminderRequired(true)
.build());
} }
@Test @Test
public void test_countWithArchived() public void testSize()
{ {
assertThat(list.countWithArchived(), equalTo(10)); assertThat(allHabits.size(), equalTo(10));
} }
@Test @Test
public void test_getAll() public void test_countActive()
{ {
List<Habit> filteredList = list.getAll(false); assertThat(activeHabits.size(), equalTo(6));
assertThat(filteredList.size(), equalTo(6));
assertThat(filteredList.contains(habits.get(2)), is(true));
assertThat(filteredList.contains(habits.get(4)), is(false));
filteredList = list.getAll(true);
assertThat(filteredList.size(), equalTo(10));
assertThat(filteredList.contains(habits.get(2)), is(true));
assertThat(filteredList.contains(habits.get(4)), is(true));
} }
@Test @Test
public void test_getByPosition() public void test_getByPosition()
{ {
assertThat(list.getByPosition(0), equalTo(habits.get(0))); assertThat(allHabits.getByPosition(0), equalTo(habitsArray.get(0)));
assertThat(list.getByPosition(3), equalTo(habits.get(3))); assertThat(allHabits.getByPosition(3), equalTo(habitsArray.get(3)));
assertThat(list.getByPosition(9), equalTo(habits.get(9))); assertThat(allHabits.getByPosition(9), equalTo(habitsArray.get(9)));
assertThat(activeHabits.getByPosition(0), equalTo(habitsArray.get(2)));
} }
@Test @Test
public void test_getHabitsWithReminder() public void test_getHabitsWithReminder()
{ {
List<Habit> filtered = list.getWithReminder(); assertThat(reminderHabits.size(), equalTo(4));
assertThat(filtered.size(), equalTo(4)); assertThat(reminderHabits.getByPosition(1),
assertThat(filtered.contains(habits.get(0)), equalTo(true)); equalTo(habitsArray.get(3)));
assertThat(filtered.contains(habits.get(1)), equalTo(false));
} }
@Test @Test
public void test_get_withInvalidId() public void test_get_withInvalidId()
{ {
assertThat(list.getById(100L), is(nullValue())); assertThat(allHabits.getById(100L), is(nullValue()));
} }
@Test @Test
public void test_get_withValidId() public void test_get_withValidId()
{ {
Habit habit1 = habits.get(0); Habit habit1 = habitsArray.get(0);
Habit habit2 = list.getById(habit1.getId()); Habit habit2 = allHabits.getById(habit1.getId());
assertThat(habit1, equalTo(habit2)); assertThat(habit1, equalTo(habit2));
} }
@ -141,17 +138,17 @@ public class HabitListTest extends BaseUnitTest
int from = operations[i][0]; int from = operations[i][0];
int to = operations[i][1]; int to = operations[i][1];
Habit fromHabit = list.getByPosition(from); Habit fromHabit = allHabits.getByPosition(from);
Habit toHabit = list.getByPosition(to); Habit toHabit = allHabits.getByPosition(to);
list.reorder(fromHabit, toHabit); allHabits.reorder(fromHabit, toHabit);
int actualPositions[] = new int[10]; int actualPositions[] = new int[10];
for (int j = 0; j < 10; j++) for (int j = 0; j < 10; j++)
{ {
Habit h = list.getById(j); Habit h = allHabits.getById(j);
if (h == null) fail(); if (h == null) fail();
actualPositions[j] = list.indexOf(h); actualPositions[j] = allHabits.indexOf(h);
} }
assertThat(actualPositions, equalTo(expectedPosition[i])); assertThat(actualPositions, equalTo(expectedPosition[i]));

Loading…
Cancel
Save