convert Habit to kotlin #300

pull/519/head
olegivo 6 years ago
parent 6433d28d78
commit d2d9f74372

@ -29,13 +29,13 @@ import org.isoron.uhabits.core.models.*
class EditSettingController(private val activity: Activity) { class EditSettingController(private val activity: Activity) {
fun onSave(habit: Habit, action: Int) { fun onSave(habit: Habit, action: Int) {
if (habit.getId() == null) return if (habit.id == null) return
val actionName = getActionName(action) val actionName = getActionName(action)
val blurb = String.format("%s: %s", actionName, habit.name) val blurb = String.format("%s: %s", actionName, habit.name)
val bundle = Bundle() val bundle = Bundle()
bundle.putInt("action", action) bundle.putInt("action", action)
bundle.putLong("habit", habit.getId()!!) bundle.putLong("habit", habit.id!!)
activity.setResult(Activity.RESULT_OK, Intent().apply { activity.setResult(Activity.RESULT_OK, Intent().apply {
putExtra(EXTRA_STRING_BLURB, blurb) putExtra(EXTRA_STRING_BLURB, blurb)

@ -76,7 +76,7 @@ class PendingIntentFactory
timestamp: Long): PendingIntent = timestamp: Long): PendingIntent =
PendingIntent.getBroadcast( PendingIntent.getBroadcast(
context, context,
(habit.getId()!! % Integer.MAX_VALUE).toInt() + 1, (habit.id!! % Integer.MAX_VALUE).toInt() + 1,
Intent(context, ReminderReceiver::class.java).apply { Intent(context, ReminderReceiver::class.java).apply {
action = ReminderReceiver.ACTION_SHOW_REMINDER action = ReminderReceiver.ACTION_SHOW_REMINDER
data = Uri.parse(habit.uriString) data = Uri.parse(habit.uriString)

@ -1,484 +0,0 @@
/*
* 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.core.models;
import android.support.annotation.*;
import org.apache.commons.lang3.builder.*;
import java.util.*;
import javax.annotation.concurrent.*;
import javax.inject.*;
import static org.isoron.uhabits.core.models.Checkmark.*;
import static org.isoron.uhabits.core.utils.StringUtils.defaultToStringStyle;
/**
* The thing that the user wants to track.
*/
@ThreadSafe
public class Habit
{
public static final int AT_LEAST = 0;
public static final int AT_MOST = 1;
public static final String HABIT_URI_FORMAT =
"content://org.isoron.uhabits/habit/%d";
public static final int NUMBER_HABIT = 1;
public static final int YES_NO_HABIT = 0;
@Nullable
public Long id;
@NonNull
private HabitData data;
@NonNull
private StreakList streaks;
@NonNull
private ScoreList scores;
@NonNull
private RepetitionList repetitions;
@NonNull
private CheckmarkList checkmarks;
private ModelObservable observable = new ModelObservable();
/**
* Constructs a habit with default data.
* <p>
* The habit is not archived, not highlighted, has no reminders and is
* placed in the last position of the list of habits.
*/
@Inject
Habit(@NonNull ModelFactory factory)
{
this.data = new HabitData();
checkmarks = factory.buildCheckmarkList(this);
streaks = factory.buildStreakList(this);
scores = factory.buildScoreList(this);
repetitions = factory.buildRepetitionList(this);
}
Habit(@NonNull ModelFactory factory, @NonNull HabitData data)
{
this.data = new HabitData(data);
checkmarks = factory.buildCheckmarkList(this);
streaks = factory.buildStreakList(this);
scores = factory.buildScoreList(this);
repetitions = factory.buildRepetitionList(this);
observable = new ModelObservable();
}
/**
* Clears the reminder for a habit.
*/
public synchronized void clearReminder()
{
data.reminder = null;
observable.notifyListeners();
}
/**
* Copies all the attributes of the specified habit into this habit
*
* @param model the model whose attributes should be copied from
*/
public synchronized void copyFrom(@NonNull Habit model)
{
this.data = new HabitData(model.data);
observable.notifyListeners();
}
/**
* List of checkmarks belonging to this habit.
*/
@NonNull
public synchronized CheckmarkList getCheckmarks()
{
return checkmarks;
}
/**
* Color of the habit.
* <p>
* This number is not an android.graphics.Color, but an index to the
* activity color palette, which changes according to the theme. To convert
* this color into an android.graphics.Color, use ColorHelper.getColor(context,
* habit.color).
*/
@NonNull
public synchronized Integer getColor()
{
return data.color;
}
public synchronized void setColor(@NonNull Integer color)
{
data.color = color;
}
@NonNull
public synchronized String getDescription()
{
return data.description;
}
public synchronized void setDescription(@NonNull String description)
{
data.description = description;
}
@NonNull
public synchronized Frequency getFrequency()
{
return data.frequency;
}
public synchronized void setFrequency(@NonNull Frequency frequency)
{
data.frequency = frequency;
}
@Nullable
public synchronized Long getId()
{
return id;
}
public synchronized void setId(@Nullable Long id)
{
this.id = id;
}
@NonNull
public synchronized String getName()
{
return data.name;
}
public synchronized void setName(@NonNull String name)
{
data.name = name;
}
public ModelObservable getObservable()
{
return observable;
}
/**
* Returns the reminder for this habit.
* <p>
* Before calling this method, you should call {@link #hasReminder()} to
* verify that a reminder does exist, otherwise an exception will be
* thrown.
*
* @return the reminder for this habit
* @throws IllegalStateException if habit has no reminder
*/
@NonNull
public synchronized Reminder getReminder()
{
if (data.reminder == null) throw new IllegalStateException();
return data.reminder;
}
public synchronized void setReminder(@Nullable Reminder reminder)
{
data.reminder = reminder;
}
@NonNull
public RepetitionList getRepetitions()
{
return repetitions;
}
@NonNull
public ScoreList getScores()
{
return scores;
}
@NonNull
public StreakList getStreaks()
{
return streaks;
}
public synchronized int getTargetType()
{
return data.targetType;
}
public synchronized void setTargetType(int targetType)
{
if (targetType != AT_LEAST && targetType != AT_MOST)
throw new IllegalArgumentException(
String.format("invalid targetType: %d", targetType));
data.targetType = targetType;
}
public synchronized double getTargetValue()
{
return data.targetValue;
}
public synchronized void setTargetValue(double targetValue)
{
if (targetValue < 0) throw new IllegalArgumentException();
data.targetValue = targetValue;
}
public synchronized int getType()
{
return data.type;
}
public synchronized void setType(int type)
{
if (type != YES_NO_HABIT && type != NUMBER_HABIT)
throw new IllegalArgumentException();
data.type = type;
}
@NonNull
public synchronized String getUnit()
{
return data.unit;
}
public synchronized void setUnit(@NonNull String unit)
{
data.unit = unit;
}
/**
* Returns the public URI that identifies this habit
*
* @return the URI
*/
public String getUriString()
{
return String.format(Locale.US, HABIT_URI_FORMAT, getId());
}
public synchronized boolean hasId()
{
return getId() != null;
}
/**
* Returns whether the habit has a reminder.
*
* @return true if habit has reminder, false otherwise
*/
public synchronized boolean hasReminder()
{
return data.reminder != null;
}
public void invalidateNewerThan(Timestamp timestamp)
{
getScores().invalidateNewerThan(timestamp);
getCheckmarks().invalidateNewerThan(timestamp);
getStreaks().invalidateNewerThan(timestamp);
}
public synchronized boolean isArchived()
{
return data.archived;
}
public synchronized void setArchived(boolean archived)
{
data.archived = archived;
}
public synchronized boolean isCompletedToday()
{
int todayCheckmark = getCheckmarks().getTodayValue();
if (isNumerical())
{
if(getTargetType() == AT_LEAST)
return todayCheckmark >= data.targetValue;
else
return todayCheckmark <= data.targetValue;
}
else return (todayCheckmark != UNCHECKED);
}
public synchronized boolean isNumerical()
{
return data.type == NUMBER_HABIT;
}
public HabitData getData()
{
return new HabitData(data);
}
public Integer getPosition()
{
return data.position;
}
public void setPosition(int newPosition)
{
data.position = newPosition;
}
public static final class HabitData
{
@NonNull
public String name;
@NonNull
public String description;
@NonNull
public Frequency frequency;
public int color;
public boolean archived;
public int targetType;
public double targetValue;
public int type;
@NonNull
public String unit;
@Nullable
public Reminder reminder;
public int position;
public HabitData()
{
this.color = 8;
this.archived = false;
this.frequency = new Frequency(3, 7);
this.type = YES_NO_HABIT;
this.name = "";
this.description = "";
this.targetType = AT_LEAST;
this.targetValue = 100;
this.unit = "";
this.position = 0;
}
public HabitData(@NonNull HabitData model)
{
this.name = model.name;
this.description = model.description;
this.frequency = model.frequency;
this.color = model.color;
this.archived = model.archived;
this.targetType = model.targetType;
this.targetValue = model.targetValue;
this.type = model.type;
this.unit = model.unit;
this.reminder = model.reminder;
this.position = model.position;
}
@Override
public String toString()
{
return new ToStringBuilder(this, defaultToStringStyle())
.append("name", name)
.append("description", description)
.append("frequency", frequency)
.append("color", color)
.append("archived", archived)
.append("targetType", targetType)
.append("targetValue", targetValue)
.append("type", type)
.append("unit", unit)
.append("reminder", reminder)
.append("position", position)
.toString();
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HabitData habitData = (HabitData) o;
return new EqualsBuilder()
.append(color, habitData.color)
.append(archived, habitData.archived)
.append(targetType, habitData.targetType)
.append(targetValue, habitData.targetValue)
.append(type, habitData.type)
.append(name, habitData.name)
.append(description, habitData.description)
.append(frequency, habitData.frequency)
.append(unit, habitData.unit)
.append(reminder, habitData.reminder)
.append(position, habitData.position)
.isEquals();
}
@Override
public int hashCode()
{
return new HashCodeBuilder(17, 37)
.append(name)
.append(description)
.append(frequency)
.append(color)
.append(archived)
.append(targetType)
.append(targetValue)
.append(type)
.append(unit)
.append(reminder)
.append(position)
.toHashCode();
}
}
@Override
public String toString()
{
return new ToStringBuilder(this, defaultToStringStyle())
.append("id", id)
.append("data", data)
.toString();
}
}

@ -0,0 +1,372 @@
/*
* 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.core.models
import org.apache.commons.lang3.builder.EqualsBuilder
import org.apache.commons.lang3.builder.HashCodeBuilder
import org.apache.commons.lang3.builder.ToStringBuilder
import org.isoron.uhabits.core.models.Checkmark.UNCHECKED
import org.isoron.uhabits.core.utils.StringUtils.defaultToStringStyle
import java.util.*
import javax.annotation.concurrent.ThreadSafe
import javax.inject.Inject
/**
* The thing that the user wants to track.
*/
@ThreadSafe
class Habit {
@get:Synchronized
@set:Synchronized
var id: Long? = null
private var data: HabitData
var streaks: StreakList
private set
var scores: ScoreList
private set
var repetitions: RepetitionList
private set
/**
* List of checkmarks belonging to this habit.
*/
@get:Synchronized
var checkmarks: CheckmarkList
private set
var observable = ModelObservable()
/**
* Color of the habit.
*
*
* This number is not an android.graphics.Color, but an index to the
* activity color palette, which changes according to the theme. To convert
* this color into an android.graphics.Color, use ColorHelper.getColor(context,
* habit.color).
*/
var color: Int
@Synchronized get() = data.color
@Synchronized set(color) {
data.color = color
}
var description: String
@Synchronized get() = data.description
@Synchronized set(description) {
data.description = description
}
var frequency: Frequency
@Synchronized get() = data.frequency
@Synchronized set(frequency) {
data.frequency = frequency
}
var name: String
@Synchronized get() = data.name
@Synchronized set(name) {
data.name = name
}
/**
* Returns the reminder for this habit.
*
*
* Before calling this method, you should call [.hasReminder] to
* verify that a reminder does exist, otherwise an exception will be
* thrown.
*
* @return the reminder for this habit
* @throws IllegalStateException if habit has no reminder
*/
var reminder: Reminder?
@Synchronized get() {
checkNotNull(data.reminder)
return data.reminder
}
@Synchronized set(reminder) {
data.reminder = reminder
}
var targetType: Int
@Synchronized get() = data.targetType
@Synchronized set(targetType) {
require(!(targetType != AT_LEAST && targetType != AT_MOST)) {
String.format("invalid targetType: %d", targetType)
}
data.targetType = targetType
}
var targetValue: Double
@Synchronized get() = data.targetValue
@Synchronized set(targetValue) {
require(targetValue >= 0)
data.targetValue = targetValue
}
var type: Int
@Synchronized get() = data.type
@Synchronized set(type) {
require(!(type != YES_NO_HABIT && type != NUMBER_HABIT))
data.type = type
}
var unit: String
@Synchronized get() = data.unit
@Synchronized set(unit) {
data.unit = unit
}
/**
* Returns the public URI that identifies this habit
*
* @return the URI
*/
val uriString: String
get() = String.format(Locale.US, HABIT_URI_FORMAT, id)
var isArchived: Boolean
@Synchronized get() = data.archived
@Synchronized set(archived) {
data.archived = archived
}
val isCompletedToday: Boolean
@Synchronized get() {
val todayCheckmark = checkmarks.todayValue
return if (isNumerical) {
if (targetType == AT_LEAST)
todayCheckmark >= data.targetValue
else
todayCheckmark <= data.targetValue
} else
todayCheckmark != UNCHECKED
}
val isNumerical: Boolean
@Synchronized get() = data.type == NUMBER_HABIT
val position: Int?
get() = data.position
/**
* Constructs a habit with default data.
*
*
* The habit is not archived, not highlighted, has no reminders and is
* placed in the last position of the list of habits.
*/
@Inject
internal constructor(factory: ModelFactory) {
this.data = HabitData()
checkmarks = factory.buildCheckmarkList(this)
streaks = factory.buildStreakList(this)
scores = factory.buildScoreList(this)
repetitions = factory.buildRepetitionList(this)
}
internal constructor(factory: ModelFactory, data: HabitData) {
this.data = HabitData(data)
checkmarks = factory.buildCheckmarkList(this)
streaks = factory.buildStreakList(this)
scores = factory.buildScoreList(this)
repetitions = factory.buildRepetitionList(this)
observable = ModelObservable()
}
/**
* Clears the reminder for a habit.
*/
@Synchronized
fun clearReminder() {
data.reminder = null
observable.notifyListeners()
}
/**
* Copies all the attributes of the specified habit into this habit
*
* @param model the model whose attributes should be copied from
*/
@Synchronized
fun copyFrom(model: Habit) {
this.data = HabitData(model.data)
observable.notifyListeners()
}
@Synchronized
fun hasId(): Boolean {
return id != null
}
/**
* Returns whether the habit has a reminder.
*
* @return true if habit has reminder, false otherwise
*/
@Synchronized
fun hasReminder(): Boolean {
return data.reminder != null
}
fun invalidateNewerThan(timestamp: Timestamp) {
scores.invalidateNewerThan(timestamp)
checkmarks.invalidateNewerThan(timestamp)
streaks.invalidateNewerThan(timestamp)
}
fun getData(): HabitData {
return HabitData(data)
}
fun setPosition(newPosition: Int) {
data.position = newPosition
}
class HabitData {
var name: String
var description: String
var frequency: Frequency
var color: Int = 0
var archived: Boolean = false
var targetType: Int = 0
var targetValue: Double = 0.toDouble()
var type: Int = 0
var unit: String
var reminder: Reminder? = null
var position: Int = 0
constructor() {
this.color = 8
this.archived = false
this.frequency = Frequency(3, 7)
this.type = YES_NO_HABIT
this.name = ""
this.description = ""
this.targetType = AT_LEAST
this.targetValue = 100.0
this.unit = ""
this.position = 0
}
constructor(model: HabitData) {
this.name = model.name
this.description = model.description
this.frequency = model.frequency
this.color = model.color
this.archived = model.archived
this.targetType = model.targetType
this.targetValue = model.targetValue
this.type = model.type
this.unit = model.unit
this.reminder = model.reminder
this.position = model.position
}
override fun toString(): String {
return ToStringBuilder(this, defaultToStringStyle())
.append("name", name)
.append("description", description)
.append("frequency", frequency)
.append("color", color)
.append("archived", archived)
.append("targetType", targetType)
.append("targetValue", targetValue)
.append("type", type)
.append("unit", unit)
.append("reminder", reminder)
.append("position", position)
.toString()
}
override fun equals(o: Any?): Boolean {
if (this === o) return true
if (o == null || javaClass != o.javaClass) return false
val habitData = o as HabitData?
return EqualsBuilder()
.append(color, habitData!!.color)
.append(archived, habitData.archived)
.append(targetType, habitData.targetType)
.append(targetValue, habitData.targetValue)
.append(type, habitData.type)
.append(name, habitData.name)
.append(description, habitData.description)
.append(frequency, habitData.frequency)
.append(unit, habitData.unit)
.append(reminder, habitData.reminder)
.append(position, habitData.position)
.isEquals
}
override fun hashCode(): Int {
return HashCodeBuilder(17, 37)
.append(name)
.append(description)
.append(frequency)
.append(color)
.append(archived)
.append(targetType)
.append(targetValue)
.append(type)
.append(unit)
.append(reminder)
.append(position)
.toHashCode()
}
}
override fun toString(): String {
return ToStringBuilder(this, defaultToStringStyle())
.append("id", id)
.append("data", data)
.toString()
}
companion object {
const val AT_LEAST = 0
const val AT_MOST = 1
const val HABIT_URI_FORMAT = "content://org.isoron.uhabits/habit/%d"
const val NUMBER_HABIT = 1
const val YES_NO_HABIT = 0
}
}
Loading…
Cancel
Save