Merge branch 'feature/parallel' into dev

pull/286/head
Alinson S. Xavier 9 years ago
commit 81ad1ba8c8

@ -78,6 +78,7 @@ dependencies {
compile 'org.apmem.tools:layouts:1.10@aar' compile 'org.apmem.tools:layouts:1.10@aar'
compile 'org.jetbrains:annotations-java5:15.0' compile 'org.jetbrains:annotations-java5:15.0'
compile 'com.google.code.gson:gson:2.8.0' compile 'com.google.code.gson:gson:2.8.0'
compile 'com.google.code.findbugs:jsr305:2.0.1'
provided 'javax.annotation:jsr250-api:1.0' provided 'javax.annotation:jsr250-api:1.0'

@ -21,6 +21,8 @@ package org.isoron.uhabits.models;
import org.apache.commons.lang3.builder.*; import org.apache.commons.lang3.builder.*;
import javax.annotation.concurrent.*;
/** /**
* A Checkmark represents the completion status of the habit for a given day. * A Checkmark represents the completion status of the habit for a given day.
* <p> * <p>
@ -30,6 +32,7 @@ import org.apache.commons.lang3.builder.*;
* <p> * <p>
* Checkmarks are computed automatically from the list of repetitions. * Checkmarks are computed automatically from the list of repetitions.
*/ */
@ThreadSafe
public final class Checkmark public final class Checkmark
{ {
/** /**

@ -29,19 +29,21 @@ import java.util.*;
import static org.isoron.uhabits.models.Checkmark.CHECKED_EXPLICITLY; import static org.isoron.uhabits.models.Checkmark.CHECKED_EXPLICITLY;
import static org.isoron.uhabits.models.Checkmark.CHECKED_IMPLICITLY; import static org.isoron.uhabits.models.Checkmark.CHECKED_IMPLICITLY;
import javax.annotation.concurrent.*;
/** /**
* The collection of {@link Checkmark}s belonging to a habit. * The collection of {@link Checkmark}s belonging to a habit.
*/ */
@ThreadSafe
public abstract class CheckmarkList public abstract class CheckmarkList
{ {
protected Habit habit; protected final Habit habit;
public ModelObservable observable = new ModelObservable(); public final ModelObservable observable;
public CheckmarkList(Habit habit) public CheckmarkList(Habit habit)
{ {
this.habit = habit; this.habit = habit;
this.observable = new ModelObservable();
} }
/** /**
@ -67,7 +69,7 @@ public abstract class CheckmarkList
* @return values for the checkmarks in the interval * @return values for the checkmarks in the interval
*/ */
@NonNull @NonNull
public final int[] getAllValues() public synchronized final int[] getAllValues()
{ {
Repetition oldestRep = habit.getRepetitions().getOldest(); Repetition oldestRep = habit.getRepetitions().getOldest();
if (oldestRep == null) return new int[0]; if (oldestRep == null) return new int[0];
@ -100,7 +102,7 @@ public abstract class CheckmarkList
* @return checkmark for today * @return checkmark for today
*/ */
@Nullable @Nullable
public final Checkmark getToday() public synchronized final Checkmark getToday()
{ {
computeAll(); computeAll();
return getNewestComputed(); return getNewestComputed();
@ -111,7 +113,7 @@ public abstract class CheckmarkList
* *
* @return value of today's checkmark * @return value of today's checkmark
*/ */
public final int getTodayValue() public synchronized final int getTodayValue()
{ {
Checkmark today = getToday(); Checkmark today = getToday();
if (today != null) return today.getValue(); if (today != null) return today.getValue();
@ -162,9 +164,14 @@ public abstract class CheckmarkList
*/ */
public final void writeCSV(Writer out) throws IOException public final void writeCSV(Writer out) throws IOException
{ {
computeAll(); int values[];
synchronized (this)
{
computeAll();
values = getAllValues();
}
int values[] = getAllValues();
long timestamp = DateUtils.getStartOfToday(); long timestamp = DateUtils.getStartOfToday();
SimpleDateFormat dateFormat = DateFormats.getCSVDateFormat(); SimpleDateFormat dateFormat = DateFormats.getCSVDateFormat();
@ -274,7 +281,7 @@ public abstract class CheckmarkList
* repetition of the habit until today. Days that already have a * repetition of the habit until today. Days that already have a
* corresponding checkmark are skipped. * corresponding checkmark are skipped.
*/ */
protected final void computeAll() private synchronized void computeAll()
{ {
Repetition oldest = habit.getRepetitions().getOldest(); Repetition oldest = habit.getRepetitions().getOldest();
if (oldest == null) return; if (oldest == null) return;

@ -21,9 +21,12 @@ package org.isoron.uhabits.models;
import org.apache.commons.lang3.builder.*; import org.apache.commons.lang3.builder.*;
import javax.annotation.concurrent.*;
/** /**
* Represents how often is the habit repeated. * Represents how often is the habit repeated.
*/ */
@ThreadSafe
public class Frequency public class Frequency
{ {
public static final Frequency DAILY = new Frequency(1, 1); public static final Frequency DAILY = new Frequency(1, 1);

@ -26,6 +26,7 @@ import org.apache.commons.lang3.builder.*;
import java.util.*; import java.util.*;
import javax.annotation.concurrent.*;
import javax.inject.*; import javax.inject.*;
import static org.isoron.uhabits.models.Checkmark.*; import static org.isoron.uhabits.models.Checkmark.*;
@ -33,6 +34,7 @@ import static org.isoron.uhabits.models.Checkmark.*;
/** /**
* The thing that the user wants to track. * The thing that the user wants to track.
*/ */
@ThreadSafe
public class Habit public class Habit
{ {
public static final int AT_LEAST = 0; public static final int AT_LEAST = 0;
@ -89,12 +91,13 @@ public class Habit
streaks = factory.buildStreakList(this); streaks = factory.buildStreakList(this);
scores = factory.buildScoreList(this); scores = factory.buildScoreList(this);
repetitions = factory.buildRepetitionList(this); repetitions = factory.buildRepetitionList(this);
observable = new ModelObservable();
} }
/** /**
* Clears the reminder for a habit. * Clears the reminder for a habit.
*/ */
public void clearReminder() public synchronized void clearReminder()
{ {
data.reminder = null; data.reminder = null;
observable.notifyListeners(); observable.notifyListeners();
@ -105,7 +108,7 @@ public class Habit
* *
* @param model the model whose attributes should be copied from * @param model the model whose attributes should be copied from
*/ */
public void copyFrom(@NonNull Habit model) public synchronized void copyFrom(@NonNull Habit model)
{ {
this.data = new HabitData(model.data); this.data = new HabitData(model.data);
observable.notifyListeners(); observable.notifyListeners();
@ -115,7 +118,7 @@ public class Habit
* List of checkmarks belonging to this habit. * List of checkmarks belonging to this habit.
*/ */
@NonNull @NonNull
public CheckmarkList getCheckmarks() public synchronized CheckmarkList getCheckmarks()
{ {
return checkmarks; return checkmarks;
} }
@ -129,56 +132,56 @@ public class Habit
* habit.color). * habit.color).
*/ */
@NonNull @NonNull
public Integer getColor() public synchronized Integer getColor()
{ {
return data.color; return data.color;
} }
public void setColor(@NonNull Integer color) public synchronized void setColor(@NonNull Integer color)
{ {
data.color = color; data.color = color;
} }
@NonNull @NonNull
public String getDescription() public synchronized String getDescription()
{ {
return data.description; return data.description;
} }
public void setDescription(@NonNull String description) public synchronized void setDescription(@NonNull String description)
{ {
data.description = description; data.description = description;
} }
@NonNull @NonNull
public Frequency getFrequency() public synchronized Frequency getFrequency()
{ {
return data.frequency; return data.frequency;
} }
public void setFrequency(@NonNull Frequency frequency) public synchronized void setFrequency(@NonNull Frequency frequency)
{ {
data.frequency = frequency; data.frequency = frequency;
} }
@Nullable @Nullable
public Long getId() public synchronized Long getId()
{ {
return id; return id;
} }
public void setId(@Nullable Long id) public synchronized void setId(@Nullable Long id)
{ {
this.id = id; this.id = id;
} }
@NonNull @NonNull
public String getName() public synchronized String getName()
{ {
return data.name; return data.name;
} }
public void setName(@NonNull String name) public synchronized void setName(@NonNull String name)
{ {
data.name = name; data.name = name;
} }
@ -199,13 +202,13 @@ public class Habit
* @throws IllegalStateException if habit has no reminder * @throws IllegalStateException if habit has no reminder
*/ */
@NonNull @NonNull
public Reminder getReminder() public synchronized Reminder getReminder()
{ {
if (data.reminder == null) throw new IllegalStateException(); if (data.reminder == null) throw new IllegalStateException();
return data.reminder; return data.reminder;
} }
public void setReminder(@Nullable Reminder reminder) public synchronized void setReminder(@Nullable Reminder reminder)
{ {
data.reminder = reminder; data.reminder = reminder;
} }
@ -228,35 +231,35 @@ public class Habit
return streaks; return streaks;
} }
public int getTargetType() public synchronized int getTargetType()
{ {
return data.targetType; return data.targetType;
} }
public void setTargetType(int targetType) public synchronized void setTargetType(int targetType)
{ {
if (targetType != AT_LEAST && targetType != AT_MOST) if (targetType != AT_LEAST && targetType != AT_MOST)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
data.targetType = targetType; data.targetType = targetType;
} }
public double getTargetValue() public synchronized double getTargetValue()
{ {
return data.targetValue; return data.targetValue;
} }
public void setTargetValue(double targetValue) public synchronized void setTargetValue(double targetValue)
{ {
if (targetValue < 0) throw new IllegalArgumentException(); if (targetValue < 0) throw new IllegalArgumentException();
data.targetValue = targetValue; data.targetValue = targetValue;
} }
public int getType() public synchronized int getType()
{ {
return data.type; return data.type;
} }
public void setType(int type) public synchronized void setType(int type)
{ {
if (type != YES_NO_HABIT && type != NUMBER_HABIT) if (type != YES_NO_HABIT && type != NUMBER_HABIT)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
@ -265,12 +268,12 @@ public class Habit
} }
@NonNull @NonNull
public String getUnit() public synchronized String getUnit()
{ {
return data.unit; return data.unit;
} }
public void setUnit(@NonNull String unit) public synchronized void setUnit(@NonNull String unit)
{ {
data.unit = unit; data.unit = unit;
} }
@ -286,7 +289,7 @@ public class Habit
return Uri.parse(s); return Uri.parse(s);
} }
public boolean hasId() public synchronized boolean hasId()
{ {
return getId() != null; return getId() != null;
} }
@ -296,7 +299,7 @@ public class Habit
* *
* @return true if habit has reminder, false otherwise * @return true if habit has reminder, false otherwise
*/ */
public boolean hasReminder() public synchronized boolean hasReminder()
{ {
return data.reminder != null; return data.reminder != null;
} }
@ -308,24 +311,24 @@ public class Habit
getStreaks().invalidateNewerThan(timestamp); getStreaks().invalidateNewerThan(timestamp);
} }
public boolean isArchived() public synchronized boolean isArchived()
{ {
return data.archived; return data.archived;
} }
public void setArchived(boolean archived) public synchronized void setArchived(boolean archived)
{ {
data.archived = archived; data.archived = archived;
} }
public boolean isCompletedToday() public synchronized boolean isCompletedToday()
{ {
int todayCheckmark = getCheckmarks().getTodayValue(); int todayCheckmark = getCheckmarks().getTodayValue();
if (isNumerical()) return todayCheckmark >= data.targetValue; if (isNumerical()) return todayCheckmark >= data.targetValue;
else return (todayCheckmark != UNCHECKED); else return (todayCheckmark != UNCHECKED);
} }
public boolean isNumerical() public synchronized boolean isNumerical()
{ {
return data.type == NUMBER_HABIT; return data.type == NUMBER_HABIT;
} }

@ -28,12 +28,15 @@ import org.isoron.uhabits.utils.*;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import javax.annotation.concurrent.*;
/** /**
* An ordered collection of {@link Habit}s. * An ordered collection of {@link Habit}s.
*/ */
@ThreadSafe
public abstract class HabitList implements Iterable<Habit> public abstract class HabitList implements Iterable<Habit>
{ {
private ModelObservable observable; private final ModelObservable observable;
@NonNull @NonNull
protected final HabitMatcher filter; protected final HabitMatcher filter;

@ -21,10 +21,13 @@ package org.isoron.uhabits.models;
import java.util.*; import java.util.*;
import javax.annotation.concurrent.*;
/** /**
* A ModelObservable allows objects to subscribe themselves to it and receive * A ModelObservable allows objects to subscribe themselves to it and receive
* notifications whenever the model is changed. * notifications whenever the model is changed.
*/ */
@ThreadSafe
public class ModelObservable public class ModelObservable
{ {
private List<Listener> listeners; private List<Listener> listeners;
@ -43,7 +46,7 @@ public class ModelObservable
* *
* @param l the listener to be added. * @param l the listener to be added.
*/ */
public void addListener(Listener l) public synchronized void addListener(Listener l)
{ {
listeners.add(l); listeners.add(l);
} }
@ -53,7 +56,7 @@ public class ModelObservable
* <p> * <p>
* Only models should call this method. * Only models should call this method.
*/ */
public void notifyListeners() public synchronized void notifyListeners()
{ {
for (Listener l : listeners) l.onModelChange(); for (Listener l : listeners) l.onModelChange();
} }
@ -66,7 +69,7 @@ public class ModelObservable
* *
* @param l the listener to be removed * @param l the listener to be removed
*/ */
public void removeListener(Listener l) public synchronized void removeListener(Listener l)
{ {
listeners.remove(l); listeners.remove(l);
} }

Loading…
Cancel
Save