Tables set up, JSON implementations deprecated

This commit is contained in:
Phillip Hsu 2016-06-26 15:31:54 -07:00
parent 918b935be0
commit a1c72f8ef9
11 changed files with 188 additions and 80 deletions

View File

@ -33,5 +33,4 @@ dependencies {
compile 'com.android.support:support-v4:23.2.1'
compile 'com.android.support:recyclerview-v7:23.2.1'
compile 'com.jakewharton:butterknife:7.0.1'
compile project(':datetimepicker')
}

View File

@ -5,13 +5,10 @@ import android.support.annotation.NonNull;
import com.google.auto.value.AutoValue;
import com.philliphsu.clock2.model.JsonSerializable;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.concurrent.atomic.AtomicLong;
import static com.philliphsu.clock2.DaysOfWeek.NUM_DAYS;
import static com.philliphsu.clock2.DaysOfWeek.SATURDAY;
@ -24,24 +21,13 @@ import static com.philliphsu.clock2.DaysOfWeek.SUNDAY;
public abstract class Alarm implements JsonSerializable {
private static final int MAX_MINUTES_CAN_SNOOZE = 30;
// JSON property names
private static final String KEY_SNOOZING_UNTIL_MILLIS = "snoozing_until_millis";
private static final String KEY_ENABLED = "enabled";
private static final String KEY_RECURRING_DAYS = "recurring_days";
//private static final String KEY_ID = "id"; // Defined in JsonSerializable
private static final String KEY_HOUR = "hour";
private static final String KEY_MINUTES = "minutes";
private static final String KEY_LABEL = "label";
private static final String KEY_RINGTONE = "ringtone";
private static final String KEY_VIBRATES = "vibrates";
// ========= MUTABLE ==============
// =================== MUTABLE =======================
private long id;
private long snoozingUntilMillis;
private boolean enabled;
private final boolean[] recurringDays = new boolean[NUM_DAYS];
// ================================
// ====================================================
//public abstract long id();
public abstract int hour();
public abstract int minutes();
public abstract String label();
@ -50,35 +36,15 @@ public abstract class Alarm implements JsonSerializable {
/** Initializes a Builder to the same property values as this instance */
public abstract Builder toBuilder();
@Deprecated
public static Alarm create(JSONObject jsonObject) {
try {
Alarm alarm = new AutoValue_Alarm.Builder()
.id(jsonObject.getLong(KEY_ID))
.hour(jsonObject.getInt(KEY_HOUR))
.minutes(jsonObject.getInt(KEY_MINUTES))
.label(jsonObject.getString(KEY_LABEL))
.ringtone(jsonObject.getString(KEY_RINGTONE))
.vibrates(jsonObject.getBoolean(KEY_VIBRATES))
.rebuild();
alarm.setEnabled(jsonObject.getBoolean(KEY_ENABLED));
alarm.snoozingUntilMillis = jsonObject.getLong(KEY_SNOOZING_UNTIL_MILLIS);
JSONArray a = (JSONArray) jsonObject.get(KEY_RECURRING_DAYS);
for (int i = 0; i < a.length(); i++) {
alarm.recurringDays[i] = a.getBoolean(i);
}
return alarm;
} catch (JSONException e) {
throw new RuntimeException(e);
}
return null;
}
public static Builder builder() {
// Unfortunately, default values must be provided for generated Builders.
// Fields that were not set when build() is called will throw an exception.
return new AutoValue_Alarm.Builder()
.id(-1)
.hour(0)
.minutes(0)
.label("")
@ -211,59 +177,46 @@ public abstract class Alarm implements JsonSerializable {
return ringsIn() <= hours * 3600000;
}
@Deprecated
public int intId() {
return (int) id();
return -1;
}
public void setId(long id) {
this.id = id;
}
public long getId() {
return id;
}
@Deprecated
@Override
public final long id() {
return -1;
}
@Deprecated
@Override
@NonNull
public JSONObject toJsonObject() {
try {
return new JSONObject()
.put(KEY_SNOOZING_UNTIL_MILLIS, snoozingUntilMillis)
.put(KEY_ENABLED, enabled)
.put(KEY_RECURRING_DAYS, new JSONArray(recurringDays))
.put(KEY_ID, id())
.put(KEY_HOUR, hour())
.put(KEY_MINUTES, minutes())
.put(KEY_LABEL, label())
.put(KEY_RINGTONE, ringtone())
.put(KEY_VIBRATES, vibrates());
} catch (JSONException e) {
throw new RuntimeException(e);
}
return null;
}
@AutoValue.Builder
public abstract static class Builder {
private static final AtomicLong ID_COUNTER = new AtomicLong(0);
// By omitting the set- prefix, we reduce the number of changes required to define the Builder
// class after copying and pasting the accessor fields here.
public abstract Builder id(long id);
public abstract Builder hour(int hour);
public abstract Builder minutes(int minutes);
public abstract Builder label(String label);
public abstract Builder ringtone(String ringtone);
public abstract Builder vibrates(boolean vibrates);
// To enforce preconditions, split the build method into two. autoBuild() is hidden from
// callers and is generated. You implement the public build(), which calls the generated
// autoBuild() and performs your desired validations.
/*not public*/abstract Alarm autoBuild();
/* package */ abstract Alarm autoBuild();
public Alarm build() {
this.id(ID_COUNTER.incrementAndGet()); // TOneverDO: change to getAndIncrement() without also adding offset of 1 in rebuild()
Alarm alarm = autoBuild();
doChecks(alarm);
return alarm;
}
/** <b>Should only be called when recreating an instance from JSON</b> */
private Alarm rebuild() {
Alarm alarm = autoBuild();
ID_COUNTER.set(alarm.id()); // prevent future instances from id collision
doChecks(alarm);
return alarm;
}
}
private static void doChecks(Alarm alarm) {

View File

@ -32,12 +32,6 @@ public class DummyContent {
}
private static Alarm createAlarm(int position) {
Alarm.Builder b = Alarm.builder();
if (position % 2 == 0) {
b.hour(21).minutes(0);
}
Alarm a = b.id(position).build();
a.setEnabled(true);
return a;
return null;
}
}

View File

@ -28,11 +28,14 @@ import com.philliphsu.clock2.DaysOfWeek;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.SharedPreferencesHelper;
import com.philliphsu.clock2.model.AlarmsRepository;
import com.philliphsu.clock2.model.DatabaseManager;
import com.philliphsu.clock2.ringtone.RingtoneActivity;
import com.philliphsu.clock2.util.AlarmUtils;
import com.philliphsu.clock2.util.LocalBroadcastHelper;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import butterknife.Bind;
import butterknife.OnCheckedChanged;
@ -182,7 +185,12 @@ public class EditAlarmActivity extends BaseActivity implements AlarmNumpad.KeyLi
@OnClick(R.id.save)
void save() {
mPresenter.save();
//mPresenter.save();
Calendar calendar = new GregorianCalendar();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minutes = calendar.get(Calendar.MINUTE);
Alarm alarm = Alarm.builder().hour(hour).minutes((minutes + 1) % 60).build();
DatabaseManager.getInstance(this).insertAlarm(alarm);
}
@OnClick(R.id.delete)

View File

@ -0,0 +1,115 @@
package com.philliphsu.clock2.model;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.DaysOfWeek;
/**
* Created by Phillip Hsu on 6/24/2016.
*
* TODO: We can generalize this class to all data models, not just Alarms.
*/
public class AlarmDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "alarms.db";
private static final int VERSION_1 = 1;
// TODO: Consider creating an inner class that implements BaseColumns
// and defines all the columns.
private static final String TABLE_ALARMS = "alarms";
private static final String COLUMN_ID = "_id";
private static final String COLUMN_HOUR = "hour";
private static final String COLUMN_MINUTES = "minutes";
private static final String COLUMN_LABEL = "label";
private static final String COLUMN_RINGTONE = "ringtone";
private static final String COLUMN_VIBRATES = "vibrates";
private static final String COLUMN_ENABLED = "enabled";
private static final String COLUMN_SNOOZING_UNTIL_MILLIS = "snoozing_until_millis";
// TODO: Consider creating an inner class that implements BaseColumns
// and defines all the columns.
private static final String TABLE_ALARM_RECURRING_DAYS = "alarm_recurring_days";
private static final String COLUMN_ALARM_ID = "alarm_id";
private static final String COLUMN_SUNDAY = "sunday";
private static final String COLUMN_MONDAY = "monday";
private static final String COLUMN_TUESDAY = "tuesday";
private static final String COLUMN_WEDNESDAY = "wednesday";
private static final String COLUMN_THURSDAY = "thursday";
private static final String COLUMN_FRIDAY = "friday";
private static final String COLUMN_SATURDAY = "saturday";
private static void createAlarmsTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_ALARMS + " ("
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COLUMN_HOUR + " INTEGER NOT NULL, "
+ COLUMN_MINUTES + " INTEGER NOT NULL, "
+ COLUMN_LABEL + " TEXT, "
+ COLUMN_RINGTONE + " TEXT NOT NULL, "
+ COLUMN_VIBRATES + " INTEGER NOT NULL, "
+ COLUMN_ENABLED + " INTEGER NOT NULL, "
+ COLUMN_SNOOZING_UNTIL_MILLIS + " INTEGER);");
}
private static void createRecurringDaysTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_ALARM_RECURRING_DAYS + " ("
+ COLUMN_ALARM_ID + " INTEGER REFERENCES " + TABLE_ALARMS + "(" + COLUMN_ID + "), "
+ COLUMN_SUNDAY + " INTEGER NOT NULL DEFAULT 0, "
+ COLUMN_MONDAY + " INTEGER NOT NULL DEFAULT 0, "
+ COLUMN_TUESDAY + " INTEGER NOT NULL DEFAULT 0, "
+ COLUMN_WEDNESDAY + " INTEGER NOT NULL DEFAULT 0, "
+ COLUMN_THURSDAY + " INTEGER NOT NULL DEFAULT 0, "
+ COLUMN_FRIDAY + " INTEGER NOT NULL DEFAULT 0, "
+ COLUMN_SATURDAY + " INTEGER NOT NULL DEFAULT 0);");
}
public AlarmDatabaseHelper(Context context) {
super(context, DB_NAME, null, VERSION_1);
}
@Override
public void onCreate(SQLiteDatabase db) {
// https://www.sqlite.org/datatype3.html
// INTEGER data type is stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude
// of the value. As soon as INTEGER values are read off of disk and into memory for processing,
// they are converted to the most general datatype (8-byte signed integer).
// 8 byte == 64 bits so this means they are read as longs...?
createAlarmsTable(db);
createRecurringDaysTable(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// I don't think we need to drop current tables unless you make structural changes
// to the schema in the new version.
}
// TODO: Consider changing param to Alarm.Builder so the Alarm that will be
// built can have its ID set.
public long insertAlarm(Alarm alarm) {
ContentValues values = new ContentValues();
values.put(COLUMN_HOUR, alarm.hour());
values.put(COLUMN_MINUTES, alarm.minutes());
values.put(COLUMN_LABEL, alarm.label());
values.put(COLUMN_RINGTONE, alarm.ringtone());
values.put(COLUMN_VIBRATES, alarm.vibrates());
values.put(COLUMN_ENABLED, alarm.isEnabled());
values.put(COLUMN_SNOOZING_UNTIL_MILLIS, alarm.snoozingUntil());
long id = getWritableDatabase().insert(TABLE_ALARMS, null, values);
alarm.setId(id);
values = new ContentValues();
values.put(COLUMN_ALARM_ID, id);
values.put(COLUMN_SUNDAY, alarm.isRecurring(DaysOfWeek.SUNDAY));
values.put(COLUMN_MONDAY, alarm.isRecurring(DaysOfWeek.MONDAY));
values.put(COLUMN_TUESDAY, alarm.isRecurring(DaysOfWeek.TUESDAY));
values.put(COLUMN_WEDNESDAY, alarm.isRecurring(DaysOfWeek.WEDNESDAY));
values.put(COLUMN_THURSDAY, alarm.isRecurring(DaysOfWeek.THURSDAY));
values.put(COLUMN_FRIDAY, alarm.isRecurring(DaysOfWeek.FRIDAY));
values.put(COLUMN_SATURDAY, alarm.isRecurring(DaysOfWeek.SATURDAY));
getWritableDatabase().insert(TABLE_ALARM_RECURRING_DAYS, null, values);
return id;
}
}

View File

@ -10,6 +10,7 @@ import org.json.JSONObject;
/**
* Created by Phillip Hsu on 5/31/2016.
*/
@Deprecated
public class AlarmIoHelper extends JsonIoHelper<Alarm> {
private static final String FILENAME = "alarms.json";

View File

@ -9,6 +9,7 @@ import com.philliphsu.clock2.Alarm;
/**
* Created by Phillip Hsu on 5/31/2016.
*/
@Deprecated
public class AlarmsRepository extends BaseRepository<Alarm> {
private static final String TAG = "AlarmsRepository";
// Singleton, so this is the sole instance for the lifetime

View File

@ -13,6 +13,7 @@ import java.util.List;
/**
* Created by Phillip Hsu on 5/31/2016.
*/
@Deprecated
public abstract class BaseRepository<T extends JsonSerializable> implements Repository<T> {
private static final String TAG = "BaseRepository";
// Cannot do this! Multiple classes will extend from this,

View File

@ -0,0 +1,34 @@
package com.philliphsu.clock2.model;
import android.content.Context;
import com.philliphsu.clock2.Alarm;
/**
* Created by Phillip Hsu on 6/25/2016.
*
* TODO: Not sure this class is all that useful? We could make the DbHelper singleton instance in its own class.
*/
public class DatabaseManager {
private static DatabaseManager sDatabaseManager;
private final Context mContext;
private final AlarmDatabaseHelper mHelper;
private DatabaseManager(Context context) {
mContext = context.getApplicationContext();
mHelper = new AlarmDatabaseHelper(mContext);
}
public static DatabaseManager getInstance(Context context) {
if (sDatabaseManager == null) {
sDatabaseManager = new DatabaseManager(context);
}
return sDatabaseManager;
}
public Alarm insertAlarm(Alarm alarm) {
mHelper.insertAlarm(alarm);
return alarm;
}
}

View File

@ -19,6 +19,7 @@ import java.util.List;
/**
* Created by Phillip Hsu on 5/31/2016.
*/
@Deprecated
public abstract class JsonIoHelper<T extends JsonSerializable> {
@NonNull private final Context mContext;
@NonNull private final String mFilename;

View File

@ -8,6 +8,7 @@ import org.json.JSONObject;
/**
* Created by Phillip Hsu on 5/31/2016.
*/
@Deprecated
public interface JsonSerializable {
String KEY_ID = "id";