mirror of https://github.com/tasks/tasks
Deleted and moved around a bunch of legacy things
parent
9727604d2f
commit
2a88772ae8
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program 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 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.backup;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class BackupDateUtilities {
|
||||||
|
|
||||||
|
private static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ssz";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Format a Date into ISO 8601 Compliant format.
|
||||||
|
|
||||||
|
*/
|
||||||
|
public static String getIso8601String(Date d) {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_FORMAT);
|
||||||
|
String result = "";
|
||||||
|
if (d != null) {
|
||||||
|
result = sdf.format(d);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Take an ISO 8601 string and return a Date object.
|
||||||
|
On failure, returns null.
|
||||||
|
*/
|
||||||
|
public static Date getDateFromIso8601String(String s) {
|
||||||
|
SimpleDateFormat df = new SimpleDateFormat(ISO_8601_FORMAT);
|
||||||
|
try {
|
||||||
|
return df.parse(s);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
Log.e("DateUtilities", "Error parsing ISO 8601 date");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get current date and time as a string.
|
||||||
|
Used in TasksXmlExporter
|
||||||
|
*/
|
||||||
|
public static String getDateForExport() {
|
||||||
|
DateFormat df = new SimpleDateFormat("yyMMdd-HHmm");
|
||||||
|
return df.format(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean wasCreatedBefore(String s, int daysAgo) {
|
||||||
|
DateFormat df = new SimpleDateFormat("yyMMdd");
|
||||||
|
Date date;
|
||||||
|
try {
|
||||||
|
date = df.parse(s);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.add(Calendar.DATE, -daysAgo);
|
||||||
|
Date calDate = cal.getTime();
|
||||||
|
return date.before(calDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.todoroo.astrid.activity;
|
package com.todoroo.astrid.locale;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
@ -1,633 +0,0 @@
|
|||||||
/*
|
|
||||||
* ASTRID: Android's Simple Task Recording Dashboard
|
|
||||||
*
|
|
||||||
* Copyright (c) 2009 Tim Su
|
|
||||||
*
|
|
||||||
* This program 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 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
package com.timsu.astrid.data.task;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.timsu.astrid.R;
|
|
||||||
import com.timsu.astrid.data.AbstractController;
|
|
||||||
import com.timsu.astrid.data.AbstractModel;
|
|
||||||
import com.timsu.astrid.data.enums.Importance;
|
|
||||||
import com.timsu.astrid.data.enums.RepeatInterval;
|
|
||||||
import com.timsu.astrid.utilities.DialogUtilities;
|
|
||||||
import com.timsu.astrid.utilities.Preferences;
|
|
||||||
|
|
||||||
|
|
||||||
/** Abstract model of a task. Subclasses implement the getters and setters
|
|
||||||
* they are interested in.
|
|
||||||
*
|
|
||||||
* @author timsu
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public abstract class AbstractTaskModel extends AbstractModel {
|
|
||||||
|
|
||||||
/** Version number of this model */
|
|
||||||
static final int VERSION = 8;
|
|
||||||
|
|
||||||
public static final int COMPLETE_PERCENTAGE = 100;
|
|
||||||
|
|
||||||
// field names
|
|
||||||
|
|
||||||
public static final String NAME = "name";
|
|
||||||
public static final String NOTES = "notes";
|
|
||||||
public static final String PROGRESS_PERCENTAGE = "progressPercentage";
|
|
||||||
public static final String IMPORTANCE = "importance";
|
|
||||||
public static final String ESTIMATED_SECONDS = "estimatedSeconds";
|
|
||||||
public static final String ELAPSED_SECONDS = "elapsedSeconds";
|
|
||||||
public static final String TIMER_START = "timerStart";
|
|
||||||
public static final String DEFINITE_DUE_DATE = "definiteDueDate";
|
|
||||||
public static final String PREFERRED_DUE_DATE = "preferredDueDate";
|
|
||||||
public static final String HIDDEN_UNTIL = "hiddenUntil";
|
|
||||||
public static final String POSTPONE_COUNT = "postponeCount";
|
|
||||||
public static final String NOTIFICATIONS = "notifications";
|
|
||||||
public static final String NOTIFICATION_FLAGS = "notificationFlags";
|
|
||||||
public static final String LAST_NOTIFIED = "lastNotified";
|
|
||||||
public static final String REPEAT = "repeat";
|
|
||||||
public static final String CREATION_DATE = "creationDate";
|
|
||||||
public static final String COMPLETION_DATE = "completionDate";
|
|
||||||
public static final String CALENDAR_URI = "calendarUri";
|
|
||||||
public static final String FLAGS = "flags";
|
|
||||||
|
|
||||||
// reserved fields ---
|
|
||||||
public static final String BLOCKING_ON = "blockingOn";
|
|
||||||
|
|
||||||
// notification flags
|
|
||||||
public static final int NOTIFY_BEFORE_DEADLINE = 1 << 0;
|
|
||||||
public static final int NOTIFY_AT_DEADLINE = 1 << 1;
|
|
||||||
public static final int NOTIFY_AFTER_DEADLINE = 1 << 2;
|
|
||||||
public static final int NOTIFY_NONSTOP = 1 << 3;
|
|
||||||
|
|
||||||
// other flags
|
|
||||||
public static final int FLAG_SYNC_ON_COMPLETE = 1 << 0;
|
|
||||||
|
|
||||||
/** Number of bits to shift repeat value by */
|
|
||||||
public static final int REPEAT_VALUE_OFFSET = 3;
|
|
||||||
|
|
||||||
/** Default values container */
|
|
||||||
private static final ContentValues defaultValues = new ContentValues();
|
|
||||||
|
|
||||||
static {
|
|
||||||
defaultValues.put(NAME, "");
|
|
||||||
defaultValues.put(NOTES, "");
|
|
||||||
defaultValues.put(PROGRESS_PERCENTAGE, 0);
|
|
||||||
defaultValues.put(IMPORTANCE, Importance.DEFAULT.ordinal());
|
|
||||||
defaultValues.put(ESTIMATED_SECONDS, 0);
|
|
||||||
defaultValues.put(ELAPSED_SECONDS, 0);
|
|
||||||
defaultValues.put(TIMER_START, 0);
|
|
||||||
defaultValues.put(DEFINITE_DUE_DATE, 0);
|
|
||||||
defaultValues.put(PREFERRED_DUE_DATE, 0);
|
|
||||||
defaultValues.put(HIDDEN_UNTIL, 0);
|
|
||||||
defaultValues.put(BLOCKING_ON, 0);
|
|
||||||
defaultValues.put(POSTPONE_COUNT, 0);
|
|
||||||
defaultValues.put(NOTIFICATIONS, 0);
|
|
||||||
defaultValues.put(NOTIFICATION_FLAGS, NOTIFY_AT_DEADLINE);
|
|
||||||
defaultValues.put(LAST_NOTIFIED, 0);
|
|
||||||
defaultValues.put(REPEAT, 0);
|
|
||||||
defaultValues.put(COMPLETION_DATE, 0);
|
|
||||||
defaultValues.put(CALENDAR_URI, (String)null);
|
|
||||||
defaultValues.put(FLAGS, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- database helper
|
|
||||||
|
|
||||||
/** Database Helper manages creating new tables and updating old ones */
|
|
||||||
public static class TaskModelDatabaseHelper extends SQLiteOpenHelper {
|
|
||||||
String tableName;
|
|
||||||
Context context;
|
|
||||||
|
|
||||||
public TaskModelDatabaseHelper(Context context, String databaseName, String tableName) {
|
|
||||||
super(context, databaseName, null, VERSION);
|
|
||||||
this.tableName = tableName;
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void onCreate(SQLiteDatabase db) {
|
|
||||||
String sql = new StringBuilder().
|
|
||||||
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
|
|
||||||
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
|
|
||||||
append(NAME).append(" text not null,").
|
|
||||||
append(NOTES).append(" text not null,").
|
|
||||||
append(PROGRESS_PERCENTAGE).append(" integer not null,").
|
|
||||||
append(IMPORTANCE).append(" integer not null,").
|
|
||||||
append(ESTIMATED_SECONDS).append(" integer,").
|
|
||||||
append(ELAPSED_SECONDS).append(" integer,").
|
|
||||||
append(TIMER_START).append(" integer,").
|
|
||||||
append(DEFINITE_DUE_DATE).append(" integer,").
|
|
||||||
append(PREFERRED_DUE_DATE).append(" integer,").
|
|
||||||
append(HIDDEN_UNTIL).append(" integer,").
|
|
||||||
append(BLOCKING_ON).append(" integer,").
|
|
||||||
append(POSTPONE_COUNT).append(" integer,").
|
|
||||||
append(NOTIFICATIONS).append(" integer,").
|
|
||||||
append(NOTIFICATION_FLAGS).append(" integer,").
|
|
||||||
append(LAST_NOTIFIED).append(" integer,").
|
|
||||||
append(REPEAT).append(" integer,").
|
|
||||||
append(FLAGS).append(" integer,").
|
|
||||||
append(CREATION_DATE).append(" integer,").
|
|
||||||
append(COMPLETION_DATE).append(" integer,").
|
|
||||||
append(CALENDAR_URI).append(" text").
|
|
||||||
append(");").toString();
|
|
||||||
db.execSQL(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("fallthrough")
|
|
||||||
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
|
||||||
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
|
|
||||||
oldVersion + " to " + newVersion + ".");
|
|
||||||
String sql;
|
|
||||||
|
|
||||||
// note: we execute sql statements in their own try block to be more
|
|
||||||
// graceful if an upgrade dies halfway or something
|
|
||||||
switch(oldVersion) {
|
|
||||||
case 1:
|
|
||||||
sql = new StringBuilder().append("ALTER TABLE ").
|
|
||||||
append(tableName).append(" ADD COLUMN ").
|
|
||||||
append(LAST_NOTIFIED).append(" integer").toString();
|
|
||||||
try {
|
|
||||||
db.execSQL(sql);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("astrid", "Error updating table!", e);
|
|
||||||
}
|
|
||||||
sql = new StringBuilder().append("ALTER TABLE ").
|
|
||||||
append(tableName).append(" ADD COLUMN ").
|
|
||||||
append(NOTIFICATION_FLAGS).append(" integer").toString();
|
|
||||||
try {
|
|
||||||
db.execSQL(sql);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("astrid", "Error updating table!", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
sql = new StringBuilder().append("ALTER TABLE ").
|
|
||||||
append(tableName).append(" ADD COLUMN ").
|
|
||||||
append(REPEAT).append(" integer").toString();
|
|
||||||
try {
|
|
||||||
db.execSQL(sql);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("astrid", "Error updating table!", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
sql = new StringBuilder().append("ALTER TABLE ").
|
|
||||||
append(tableName).append(" ADD COLUMN ").
|
|
||||||
append(CALENDAR_URI).append(" text").toString();
|
|
||||||
try {
|
|
||||||
db.execSQL(sql);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("astrid", "Error updating table!", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
sql = new StringBuilder().append("ALTER TABLE ").
|
|
||||||
append(tableName).append(" ADD COLUMN ").
|
|
||||||
append(POSTPONE_COUNT).append(" integer").toString();
|
|
||||||
try {
|
|
||||||
db.execSQL(sql);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("astrid", "Error updating table!", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
case 6:
|
|
||||||
// apparently some people didn't get the flags column
|
|
||||||
// from version 5 to version 6, so we try again
|
|
||||||
|
|
||||||
sql = new StringBuilder().append("ALTER TABLE ").
|
|
||||||
append(tableName).append(" ADD COLUMN ").
|
|
||||||
append(FLAGS).append(" integer").toString();
|
|
||||||
try {
|
|
||||||
db.execSQL(sql);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("astrid", "Error updating table!", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
case 7:
|
|
||||||
// not a real change, but make sure that columns that are null
|
|
||||||
// are converted into zeros, which was my previous assumption
|
|
||||||
|
|
||||||
for(String column : new String[] {
|
|
||||||
ESTIMATED_SECONDS,
|
|
||||||
ELAPSED_SECONDS,
|
|
||||||
TIMER_START,
|
|
||||||
DEFINITE_DUE_DATE,
|
|
||||||
PREFERRED_DUE_DATE,
|
|
||||||
HIDDEN_UNTIL,
|
|
||||||
POSTPONE_COUNT,
|
|
||||||
LAST_NOTIFIED,
|
|
||||||
REPEAT,
|
|
||||||
CREATION_DATE,
|
|
||||||
COMPLETION_DATE }) {
|
|
||||||
sql = String.format("UPDATE %s SET %s = 0 WHERE %s ISNULL",
|
|
||||||
tableName, column, column);
|
|
||||||
try {
|
|
||||||
db.execSQL(sql);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("astrid", "Error updating table!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- break point
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// we don't know how to handle it... show an error
|
|
||||||
Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion);
|
|
||||||
DialogUtilities.okDialog(context, "There was a database error reading from Alerts. Data may have been corrupted.", null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- utility methods
|
|
||||||
|
|
||||||
/** Gets task color. Requires definiteDueDate and importance */
|
|
||||||
protected int getTaskColorResource(Context context) {
|
|
||||||
if(getDefiniteDueDate() != null && getDefiniteDueDate().getTime() <
|
|
||||||
System.currentTimeMillis()) {
|
|
||||||
return R.color.task_list_overdue;
|
|
||||||
} else if(Preferences.isColorize(context)) {
|
|
||||||
return getImportance().getTaskListColor();
|
|
||||||
} else {
|
|
||||||
return R.color.task_list_normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks whether task is done. Requires progressPercentage */
|
|
||||||
protected boolean isTaskCompleted() {
|
|
||||||
return getProgressPercentage() >= COMPLETE_PERCENTAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Stops the timer & increments elapsed time. Requires timerStart and
|
|
||||||
* elapsedSeconds */
|
|
||||||
protected void stopTimerAndUpdateElapsedTime() {
|
|
||||||
if(getTimerStart() == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
long start = getTimerStart().getTime();
|
|
||||||
setTimerStart(null);
|
|
||||||
long secondsElapsed = (System.currentTimeMillis() - start)/1000;
|
|
||||||
setElapsedSeconds((int) (getElapsedSeconds() + secondsElapsed));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void prefetchData(String[] fields) {
|
|
||||||
for(String field : fields) {
|
|
||||||
if(field.equals(NAME))
|
|
||||||
getName();
|
|
||||||
else if(field.equals(NOTES))
|
|
||||||
getNotes();
|
|
||||||
else if(field.equals(PROGRESS_PERCENTAGE))
|
|
||||||
getProgressPercentage();
|
|
||||||
else if(field.equals(IMPORTANCE))
|
|
||||||
getImportance();
|
|
||||||
else if(field.equals(ESTIMATED_SECONDS))
|
|
||||||
getEstimatedSeconds();
|
|
||||||
else if(field.equals(ELAPSED_SECONDS))
|
|
||||||
getElapsedSeconds();
|
|
||||||
else if(field.equals(TIMER_START))
|
|
||||||
getTimerStart();
|
|
||||||
else if(field.equals(DEFINITE_DUE_DATE))
|
|
||||||
getDefiniteDueDate();
|
|
||||||
else if(field.equals(PREFERRED_DUE_DATE))
|
|
||||||
getPreferredDueDate();
|
|
||||||
else if(field.equals(HIDDEN_UNTIL))
|
|
||||||
getHiddenUntil();
|
|
||||||
else if(field.equals(BLOCKING_ON))
|
|
||||||
getBlockingOn();
|
|
||||||
else if(field.equals(POSTPONE_COUNT))
|
|
||||||
getPostponeCount();
|
|
||||||
else if(field.equals(NOTIFICATIONS))
|
|
||||||
getNotificationIntervalSeconds();
|
|
||||||
else if(field.equals(CREATION_DATE))
|
|
||||||
getCreationDate();
|
|
||||||
else if(field.equals(COMPLETION_DATE))
|
|
||||||
getCompletionDate();
|
|
||||||
else if(field.equals(NOTIFICATION_FLAGS))
|
|
||||||
getNotificationFlags();
|
|
||||||
else if(field.equals(LAST_NOTIFIED))
|
|
||||||
getLastNotificationDate();
|
|
||||||
else if(field.equals(REPEAT))
|
|
||||||
getRepeat();
|
|
||||||
else if(field.equals(FLAGS))
|
|
||||||
getFlags();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- helper classes
|
|
||||||
|
|
||||||
public static class RepeatInfo {
|
|
||||||
private final RepeatInterval interval;
|
|
||||||
private final int value;
|
|
||||||
|
|
||||||
public RepeatInfo(RepeatInterval repeatInterval, int value) {
|
|
||||||
this.interval = repeatInterval;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date shiftDate(Date input) {
|
|
||||||
Date newDate = (Date)input.clone();
|
|
||||||
interval.offsetDateBy(newDate, value);
|
|
||||||
return newDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RepeatInterval getInterval() {
|
|
||||||
return interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int toSingleField(RepeatInfo repeatInfo) {
|
|
||||||
int repeat;
|
|
||||||
if(repeatInfo == null)
|
|
||||||
repeat = 0;
|
|
||||||
else
|
|
||||||
repeat = (repeatInfo.value << REPEAT_VALUE_OFFSET) +
|
|
||||||
repeatInfo.interval.ordinal();
|
|
||||||
return repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RepeatInfo fromSingleField(int repeat) {
|
|
||||||
if(repeat == 0)
|
|
||||||
return null;
|
|
||||||
int value = repeat >> REPEAT_VALUE_OFFSET;
|
|
||||||
RepeatInterval interval = RepeatInterval.values()
|
|
||||||
[repeat - (value << REPEAT_VALUE_OFFSET)];
|
|
||||||
|
|
||||||
return new RepeatInfo(interval, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- task identifier
|
|
||||||
|
|
||||||
private TaskIdentifier identifier = null;
|
|
||||||
|
|
||||||
public TaskIdentifier getTaskIdentifier() {
|
|
||||||
return identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTaskIdentifier(TaskIdentifier identifier) {
|
|
||||||
this.identifier = identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- constructors and abstract methods
|
|
||||||
|
|
||||||
AbstractTaskModel() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read identifier from database */
|
|
||||||
AbstractTaskModel(Cursor cursor) {
|
|
||||||
super(cursor);
|
|
||||||
|
|
||||||
Integer id = retrieveInteger(AbstractController.KEY_ROWID);
|
|
||||||
setTaskIdentifier(new TaskIdentifier(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get identifier from argument */
|
|
||||||
AbstractTaskModel(TaskIdentifier identifier, Cursor cursor) {
|
|
||||||
super(cursor);
|
|
||||||
|
|
||||||
setTaskIdentifier(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ContentValues getDefaultValues() {
|
|
||||||
return defaultValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- getters and setters: expose them as you see fit
|
|
||||||
|
|
||||||
protected String getName() {
|
|
||||||
return retrieveString(NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getNotes() {
|
|
||||||
return retrieveString(NOTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getProgressPercentage() {
|
|
||||||
return retrieveInteger(PROGRESS_PERCENTAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Importance getImportance() {
|
|
||||||
Integer value = retrieveInteger(IMPORTANCE);
|
|
||||||
if(value == null)
|
|
||||||
return null;
|
|
||||||
return Importance.values()[value];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Integer getEstimatedSeconds() {
|
|
||||||
return retrieveInteger(ESTIMATED_SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Integer getElapsedSeconds() {
|
|
||||||
return retrieveInteger(ELAPSED_SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Date getTimerStart() {
|
|
||||||
return retrieveDate(TIMER_START);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Date getDefiniteDueDate() {
|
|
||||||
return retrieveDate(DEFINITE_DUE_DATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Date getPreferredDueDate() {
|
|
||||||
return retrieveDate(PREFERRED_DUE_DATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Date getHiddenUntil() {
|
|
||||||
return retrieveDate(HIDDEN_UNTIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isHidden() {
|
|
||||||
if(getHiddenUntil() == null)
|
|
||||||
return false;
|
|
||||||
return getHiddenUntil().getTime() > System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Date getCreationDate() {
|
|
||||||
return retrieveDate(CREATION_DATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Date getCompletionDate() {
|
|
||||||
return retrieveDate(COMPLETION_DATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TaskIdentifier getBlockingOn() {
|
|
||||||
Long value = retrieveLong(BLOCKING_ON);
|
|
||||||
if(value == null)
|
|
||||||
return null;
|
|
||||||
return new TaskIdentifier(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Integer getPostponeCount() {
|
|
||||||
return retrieveInteger(POSTPONE_COUNT);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Integer getNotificationIntervalSeconds() {
|
|
||||||
return retrieveInteger(NOTIFICATIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getNotificationFlags() {
|
|
||||||
return retrieveInteger(NOTIFICATION_FLAGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Date getLastNotificationDate() {
|
|
||||||
return retrieveDate(LAST_NOTIFIED);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected RepeatInfo getRepeat() {
|
|
||||||
int repeat = retrieveInteger(REPEAT);
|
|
||||||
if(repeat == 0)
|
|
||||||
return null;
|
|
||||||
int value = repeat >> REPEAT_VALUE_OFFSET;
|
|
||||||
RepeatInterval interval = RepeatInterval.values()
|
|
||||||
[repeat - (value << REPEAT_VALUE_OFFSET)];
|
|
||||||
|
|
||||||
return new RepeatInfo(interval, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getCalendarUri() {
|
|
||||||
String uri = retrieveString(CALENDAR_URI);
|
|
||||||
if(uri != null && uri.length() == 0)
|
|
||||||
return null;
|
|
||||||
else
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getFlags() {
|
|
||||||
return retrieveInteger(FLAGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- setters
|
|
||||||
|
|
||||||
protected void setName(String name) {
|
|
||||||
putIfChangedFromDatabase(NAME, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setNotes(String notes) {
|
|
||||||
putIfChangedFromDatabase(NOTES, notes);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setProgressPercentage(int progressPercentage) {
|
|
||||||
putIfChangedFromDatabase(PROGRESS_PERCENTAGE, progressPercentage);
|
|
||||||
|
|
||||||
if(getProgressPercentage() != progressPercentage &&
|
|
||||||
progressPercentage == COMPLETE_PERCENTAGE)
|
|
||||||
setCompletionDate(new Date());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setImportance(Importance importance) {
|
|
||||||
putIfChangedFromDatabase(IMPORTANCE, importance.ordinal());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setEstimatedSeconds(Integer estimatedSeconds) {
|
|
||||||
putIfChangedFromDatabase(ESTIMATED_SECONDS, estimatedSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setElapsedSeconds(int elapsedSeconds) {
|
|
||||||
putIfChangedFromDatabase(ELAPSED_SECONDS, elapsedSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setTimerStart(Date timerStart) {
|
|
||||||
putDate(TIMER_START, timerStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setDefiniteDueDate(Date definiteDueDate) {
|
|
||||||
putDate(DEFINITE_DUE_DATE, definiteDueDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setPreferredDueDate(Date preferredDueDate) {
|
|
||||||
putDate(PREFERRED_DUE_DATE, preferredDueDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setHiddenUntil(Date hiddenUntil) {
|
|
||||||
putDate(HIDDEN_UNTIL, hiddenUntil);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setBlockingOn(TaskIdentifier blockingOn) {
|
|
||||||
if(blockingOn == null || blockingOn.equals(getTaskIdentifier()))
|
|
||||||
putIfChangedFromDatabase(BLOCKING_ON, (Integer)null);
|
|
||||||
else
|
|
||||||
putIfChangedFromDatabase(BLOCKING_ON, blockingOn.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setPostponeCount(int postponeCount) {
|
|
||||||
putIfChangedFromDatabase(POSTPONE_COUNT, postponeCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setCreationDate(Date creationDate) {
|
|
||||||
putDate(CREATION_DATE, creationDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setCompletionDate(Date completionDate) {
|
|
||||||
putDate(COMPLETION_DATE, completionDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setNotificationIntervalSeconds(Integer intervalInSeconds) {
|
|
||||||
putIfChangedFromDatabase(NOTIFICATIONS, intervalInSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setNotificationFlags(int flags) {
|
|
||||||
putIfChangedFromDatabase(NOTIFICATION_FLAGS, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setLastNotificationTime(Date date) {
|
|
||||||
putDate(LAST_NOTIFIED, date);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setRepeat(RepeatInfo repeatInfo) {
|
|
||||||
int repeat;
|
|
||||||
if(repeatInfo == null)
|
|
||||||
repeat = 0;
|
|
||||||
else
|
|
||||||
repeat = (repeatInfo.value << REPEAT_VALUE_OFFSET) +
|
|
||||||
repeatInfo.interval.ordinal();
|
|
||||||
putIfChangedFromDatabase(REPEAT, repeat);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setCalendarUri(String uri) {
|
|
||||||
putIfChangedFromDatabase(CALENDAR_URI, uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setFlags(int flags) {
|
|
||||||
putIfChangedFromDatabase(FLAGS, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- utility methods
|
|
||||||
|
|
||||||
protected void putDate(String fieldName, Date date) {
|
|
||||||
if(date == null)
|
|
||||||
putIfChangedFromDatabase(fieldName, 0);
|
|
||||||
else
|
|
||||||
putIfChangedFromDatabase(fieldName, date.getTime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,246 +0,0 @@
|
|||||||
/*
|
|
||||||
* ASTRID: Android's Simple Task Recording Dashboard
|
|
||||||
*
|
|
||||||
* Copyright (c) 2009 Tim Su
|
|
||||||
*
|
|
||||||
* This program 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 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
package com.timsu.astrid.utilities;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.timsu.astrid.R;
|
|
||||||
|
|
||||||
public class DateUtilities {
|
|
||||||
|
|
||||||
private static SimpleDateFormat format = null;
|
|
||||||
private static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ssz";
|
|
||||||
|
|
||||||
/** Format a time into a medium length absolute format */
|
|
||||||
public static String getFormattedDate(Context context, Date date) {
|
|
||||||
if(format == null)
|
|
||||||
format = Preferences.getDateFormat(context);
|
|
||||||
return format.format(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method for dropping the preopsition argument.
|
|
||||||
*/
|
|
||||||
public static String getDurationString(Resources r, int timeInSeconds,
|
|
||||||
int unitsToShow) {
|
|
||||||
return getDurationString(r, timeInSeconds, unitsToShow, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a time into the format: 5 days, 3 hours, 2 minutes
|
|
||||||
*
|
|
||||||
* @param r Resources to get strings from
|
|
||||||
* @param timeInSeconds
|
|
||||||
* @param unitsToShow number of units to show (i.e. if 2, then 5 hours
|
|
||||||
* 3 minutes 2 seconds is truncated to 5 hours 3 minutes)
|
|
||||||
* @param withPreposition whether there is a preceeding preposition
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getDurationString(Resources r, int timeInSeconds,
|
|
||||||
int unitsToShow, boolean withPreposition) {
|
|
||||||
short days, hours, minutes, seconds;
|
|
||||||
short unitsDisplayed = 0;
|
|
||||||
|
|
||||||
if(timeInSeconds == 0)
|
|
||||||
return r.getQuantityString(R.plurals.Nseconds, 0, 0);
|
|
||||||
|
|
||||||
days = (short)(timeInSeconds / 24 / 3600);
|
|
||||||
timeInSeconds -= days*24*3600;
|
|
||||||
hours = (short)(timeInSeconds / 3600);
|
|
||||||
timeInSeconds -= hours * 3600;
|
|
||||||
minutes = (short)(timeInSeconds / 60);
|
|
||||||
timeInSeconds -= minutes * 60;
|
|
||||||
seconds = (short)timeInSeconds;
|
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
if(days > 0) {
|
|
||||||
int daysPlural = withPreposition ? R.plurals.NdaysPreposition : R.plurals.Ndays;
|
|
||||||
result.append(r.getQuantityString(daysPlural, days, days)).
|
|
||||||
append(" ");
|
|
||||||
unitsDisplayed++;
|
|
||||||
}
|
|
||||||
if(unitsDisplayed < unitsToShow && hours > 0) {
|
|
||||||
result.append(r.getQuantityString(R.plurals.Nhours, hours,
|
|
||||||
hours)).
|
|
||||||
append(" ");
|
|
||||||
unitsDisplayed++;
|
|
||||||
}
|
|
||||||
if(unitsDisplayed < unitsToShow && minutes > 0) {
|
|
||||||
result.append(r.getQuantityString(R.plurals.Nminutes, minutes,
|
|
||||||
minutes)).append(" ");
|
|
||||||
unitsDisplayed++;
|
|
||||||
}
|
|
||||||
if(unitsDisplayed < unitsToShow && seconds > 0) {
|
|
||||||
result.append(r.getQuantityString(R.plurals.Nseconds, seconds,
|
|
||||||
seconds)).append(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.toString().trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a time into the format: 5 days, 3 hrs, 2 min
|
|
||||||
*
|
|
||||||
* @param r Resources to get strings from
|
|
||||||
* @param timeInSeconds
|
|
||||||
* @param unitsToShow number of units to show (i.e. if 2, then 5 hours
|
|
||||||
* 3 minutes 2 seconds is truncated to 5 hours 3 minutes)
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getAbbreviatedDurationString(Resources r, int timeInSeconds,
|
|
||||||
int unitsToShow) {
|
|
||||||
short days, hours, minutes, seconds;
|
|
||||||
short unitsDisplayed = 0;
|
|
||||||
|
|
||||||
if(timeInSeconds == 0)
|
|
||||||
return r.getQuantityString(R.plurals.Nseconds, 0, 0);
|
|
||||||
|
|
||||||
days = (short)(timeInSeconds / 24 / 3600);
|
|
||||||
timeInSeconds -= days*24*3600;
|
|
||||||
hours = (short)(timeInSeconds / 3600);
|
|
||||||
timeInSeconds -= hours * 3600;
|
|
||||||
minutes = (short)(timeInSeconds / 60);
|
|
||||||
timeInSeconds -= minutes * 60;
|
|
||||||
seconds = (short)timeInSeconds;
|
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
if(days > 0) {
|
|
||||||
result.append(r.getQuantityString(R.plurals.Ndays, days, days)).
|
|
||||||
append(" ");
|
|
||||||
unitsDisplayed++;
|
|
||||||
}
|
|
||||||
if(unitsDisplayed < unitsToShow && hours > 0) {
|
|
||||||
result.append(r.getQuantityString(R.plurals.NhoursShort, hours,
|
|
||||||
hours)).
|
|
||||||
append(" ");
|
|
||||||
unitsDisplayed++;
|
|
||||||
}
|
|
||||||
if(unitsDisplayed < unitsToShow && minutes > 0) {
|
|
||||||
result.append(r.getQuantityString(R.plurals.NminutesShort, minutes,
|
|
||||||
minutes)).append(" ");
|
|
||||||
unitsDisplayed++;
|
|
||||||
}
|
|
||||||
if(unitsDisplayed < unitsToShow && seconds > 0) {
|
|
||||||
result.append(r.getQuantityString(R.plurals.NsecondsShort, seconds,
|
|
||||||
seconds)).append(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.toString().trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a time into the format: 5 d, 3 h, 2 m
|
|
||||||
*
|
|
||||||
* @param r Resources to get strings from
|
|
||||||
* @param timeInSeconds
|
|
||||||
* @param unitsToShow number of units to show
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getShortDurationString(Resources r, int timeInSeconds,
|
|
||||||
int unitsToShow) {
|
|
||||||
short days, hours, minutes, seconds;
|
|
||||||
short unitsDisplayed = 0;
|
|
||||||
|
|
||||||
if(timeInSeconds == 0)
|
|
||||||
return "0 s";
|
|
||||||
|
|
||||||
days = (short)(timeInSeconds / 24 / 3600);
|
|
||||||
timeInSeconds -= days*24*3600;
|
|
||||||
hours = (short)(timeInSeconds / 3600);
|
|
||||||
timeInSeconds -= hours * 3600;
|
|
||||||
minutes = (short)(timeInSeconds / 60);
|
|
||||||
timeInSeconds -= minutes * 60;
|
|
||||||
seconds = (short)timeInSeconds;
|
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
if(days > 0) {
|
|
||||||
result.append(days).append(" d ");
|
|
||||||
unitsDisplayed++;
|
|
||||||
}
|
|
||||||
if(unitsDisplayed < unitsToShow && hours > 0) {
|
|
||||||
result.append(hours).append(" h ");
|
|
||||||
unitsDisplayed++;
|
|
||||||
}
|
|
||||||
if(unitsDisplayed < unitsToShow && minutes > 0) {
|
|
||||||
result.append(minutes).append(" m ");
|
|
||||||
unitsDisplayed++;
|
|
||||||
}
|
|
||||||
if(unitsDisplayed < unitsToShow && seconds > 0) {
|
|
||||||
result.append(seconds).append(" s ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Format a Date into ISO 8601 Compliant format.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public static String getIso8601String(Date d) {
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_FORMAT);
|
|
||||||
String result = "";
|
|
||||||
if (d != null) {
|
|
||||||
result = sdf.format(d);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Take an ISO 8601 string and return a Date object.
|
|
||||||
On failure, returns null.
|
|
||||||
*/
|
|
||||||
public static Date getDateFromIso8601String(String s) {
|
|
||||||
SimpleDateFormat df = new SimpleDateFormat(ISO_8601_FORMAT);
|
|
||||||
try {
|
|
||||||
return df.parse(s);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
Log.e("DateUtilities", "Error parsing ISO 8601 date");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get current date and time as a string.
|
|
||||||
Used in TasksXmlExporter
|
|
||||||
*/
|
|
||||||
public static String getDateForExport() {
|
|
||||||
DateFormat df = new SimpleDateFormat("yyMMdd-HHmm");
|
|
||||||
return df.format(new Date());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean wasCreatedBefore(String s, int daysAgo) {
|
|
||||||
DateFormat df = new SimpleDateFormat("yyMMdd");
|
|
||||||
Date date;
|
|
||||||
try {
|
|
||||||
date = df.parse(s);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Calendar cal = Calendar.getInstance();
|
|
||||||
cal.add(Calendar.DATE, -daysAgo);
|
|
||||||
Date calDate = cal.getTime();
|
|
||||||
return date.before(calDate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,278 @@
|
|||||||
|
package com.timsu.astrid.utilities;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Xml;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.timsu.astrid.data.TaskController;
|
||||||
|
import com.timsu.astrid.data.TaskIdentifier;
|
||||||
|
import com.timsu.astrid.data.TaskModelForXml;
|
||||||
|
import com.timsu.astrid.data.alerts.AlertController;
|
||||||
|
import com.timsu.astrid.data.sync.SyncDataController;
|
||||||
|
import com.timsu.astrid.data.sync.SyncMapping;
|
||||||
|
import com.timsu.astrid.data.tag.TagController;
|
||||||
|
import com.timsu.astrid.data.tag.TagIdentifier;
|
||||||
|
import com.timsu.astrid.data.tag.TagModelForView;
|
||||||
|
import com.todoroo.astrid.backup.BackupDateUtilities;
|
||||||
|
|
||||||
|
public class LegacyTasksXmlExporter {
|
||||||
|
|
||||||
|
private TaskController taskController;
|
||||||
|
private TagController tagController;
|
||||||
|
private AlertController alertController;
|
||||||
|
private SyncDataController syncDataController;
|
||||||
|
private Context ctx;
|
||||||
|
private String output;
|
||||||
|
private final boolean isService;
|
||||||
|
private int exportCount;
|
||||||
|
private XmlSerializer xml;
|
||||||
|
private HashMap<TagIdentifier, TagModelForView> tagMap;
|
||||||
|
|
||||||
|
public static final String ASTRID_TAG = "astrid";
|
||||||
|
public static final String ASTRID_ATTR_VERSION = "version";
|
||||||
|
public static final String TASK_TAG = "task";
|
||||||
|
public static final String TAG_TAG = "tag";
|
||||||
|
public static final String TAG_ATTR_NAME = "name";
|
||||||
|
public static final String ALERT_TAG = "alert";
|
||||||
|
public static final String ALERT_ATTR_DATE = "date";
|
||||||
|
public static final String SYNC_TAG = "sync";
|
||||||
|
public static final String SYNC_ATTR_SERVICE = "service";
|
||||||
|
public static final String SYNC_ATTR_REMOTE_ID = "remote_id";
|
||||||
|
public static final String XML_ENCODING = "utf-8";
|
||||||
|
public static final String ASTRID_DIR = "/astrid";
|
||||||
|
private static final String EXPORT_FILE_NAME = "user.%s.xml";
|
||||||
|
private static final String BACKUP_FILE_NAME = "auto.%s.xml";
|
||||||
|
public static final int FILENAME_DATE_BEGIN_INDEX = 5;
|
||||||
|
public static final int FILENAME_DATE_END_INDEX = 11;
|
||||||
|
|
||||||
|
public LegacyTasksXmlExporter(boolean isService) {
|
||||||
|
this.isService = isService;
|
||||||
|
this.exportCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initTagMap() {
|
||||||
|
tagMap = tagController.getAllTagsAsMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void serializeTags(TaskIdentifier task)
|
||||||
|
throws IOException {
|
||||||
|
LinkedList<TagIdentifier> tags = tagController.getTaskTags(task);
|
||||||
|
for (TagIdentifier tag : tags) {
|
||||||
|
if(!tagMap.containsKey(tag) || tagMap.get(tag) == null)
|
||||||
|
continue;
|
||||||
|
xml.startTag(null, TAG_TAG);
|
||||||
|
xml.attribute(null, TAG_ATTR_NAME, tagMap.get(tag).toString());
|
||||||
|
xml.endTag(null, TAG_TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void serializeSyncMappings(TaskIdentifier task)
|
||||||
|
throws IOException {
|
||||||
|
HashSet<SyncMapping> syncMappings = syncDataController.getSyncMappings(task);
|
||||||
|
for (SyncMapping sync : syncMappings) {
|
||||||
|
xml.startTag(null, SYNC_TAG);
|
||||||
|
xml.attribute(null, SYNC_ATTR_SERVICE,
|
||||||
|
Integer.toString(sync.getSyncServiceId()));
|
||||||
|
xml.attribute(null, SYNC_ATTR_REMOTE_ID, sync.getRemoteId());
|
||||||
|
xml.endTag(null, SYNC_TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void serializeAlerts(TaskIdentifier task)
|
||||||
|
throws IOException {
|
||||||
|
List<Date> alerts = alertController.getTaskAlerts(task);
|
||||||
|
for (Date alert : alerts) {
|
||||||
|
xml.startTag(null, ALERT_TAG);
|
||||||
|
xml.attribute(null, ALERT_ATTR_DATE, BackupDateUtilities.getIso8601String(alert));
|
||||||
|
xml.endTag(null, ALERT_TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void serializeTasks()
|
||||||
|
throws IOException {
|
||||||
|
Cursor c = taskController.getBackupTaskListCursor();
|
||||||
|
if (! c.moveToFirst()) {
|
||||||
|
return; // No tasks.
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
TaskModelForXml task = new TaskModelForXml(c);
|
||||||
|
TaskIdentifier taskId = task.getTaskIdentifier();
|
||||||
|
xml.startTag(null, TASK_TAG);
|
||||||
|
HashMap<String, String> taskAttributes = task.getTaskAttributes();
|
||||||
|
for (String key : taskAttributes.keySet()) {
|
||||||
|
String value = taskAttributes.get(key);
|
||||||
|
xml.attribute(null, key, value);
|
||||||
|
}
|
||||||
|
serializeTags(taskId);
|
||||||
|
serializeAlerts(taskId);
|
||||||
|
serializeSyncMappings(taskId);
|
||||||
|
xml.endTag(null, TASK_TAG);
|
||||||
|
this.exportCount++;
|
||||||
|
} while (c.moveToNext());
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTasksExport() throws IOException {
|
||||||
|
File xmlFile = new File(this.output);
|
||||||
|
xmlFile.createNewFile();
|
||||||
|
FileOutputStream fos = new FileOutputStream(xmlFile);
|
||||||
|
xml = Xml.newSerializer();
|
||||||
|
xml.setOutput(fos, XML_ENCODING);
|
||||||
|
|
||||||
|
xml.startDocument(null, null);
|
||||||
|
xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
|
||||||
|
|
||||||
|
xml.startTag(null, ASTRID_TAG);
|
||||||
|
xml.attribute(null, ASTRID_ATTR_VERSION,
|
||||||
|
Integer.toString(Preferences.getCurrentVersion(ctx)));
|
||||||
|
|
||||||
|
openControllers();
|
||||||
|
initTagMap();
|
||||||
|
serializeTasks();
|
||||||
|
closeControllers();
|
||||||
|
|
||||||
|
xml.endTag(null, ASTRID_TAG);
|
||||||
|
xml.endDocument();
|
||||||
|
xml.flush();
|
||||||
|
fos.close();
|
||||||
|
|
||||||
|
if (!isService) {
|
||||||
|
displayToast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayToast() {
|
||||||
|
CharSequence text = String.format(ctx.getString(R.string.export_toast),
|
||||||
|
ctx.getResources().getQuantityString(R.plurals.Ntasks, exportCount,
|
||||||
|
exportCount), output);
|
||||||
|
Toast.makeText(ctx, text, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayErrorToast(String error) {
|
||||||
|
Toast.makeText(ctx, error, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeControllers() {
|
||||||
|
tagController.close();
|
||||||
|
taskController.close();
|
||||||
|
alertController.close();
|
||||||
|
syncDataController.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openControllers() {
|
||||||
|
taskController.open();
|
||||||
|
tagController.open();
|
||||||
|
alertController.open();
|
||||||
|
syncDataController.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exportTasks(File directory) {
|
||||||
|
if (isService && !Preferences.isBackupEnabled(ctx)) {
|
||||||
|
// Automatic backups are disabled.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (setupFile(directory)) {
|
||||||
|
Thread thread = new Thread(doBackgroundExport);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getExportDirectory() {
|
||||||
|
String storageState = Environment.getExternalStorageState();
|
||||||
|
if (storageState.equals(Environment.MEDIA_MOUNTED)) {
|
||||||
|
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||||
|
path = path + ASTRID_DIR;
|
||||||
|
return new File(path);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean setupFile(File directory) {
|
||||||
|
File astridDir = directory;
|
||||||
|
if (astridDir != null) {
|
||||||
|
// Check for /sdcard/astrid directory. If it doesn't exist, make it.
|
||||||
|
if (astridDir.exists() || astridDir.mkdir()) {
|
||||||
|
String fileName;
|
||||||
|
if (isService) {
|
||||||
|
fileName = BACKUP_FILE_NAME;
|
||||||
|
} else {
|
||||||
|
fileName = EXPORT_FILE_NAME;
|
||||||
|
}
|
||||||
|
fileName = String.format(fileName, BackupDateUtilities.getDateForExport());
|
||||||
|
setOutput(astridDir.getAbsolutePath() + "/" + fileName);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Unable to make the /sdcard/astrid directory.
|
||||||
|
String error = ctx.getString(R.string.error_sdcard, astridDir.getAbsolutePath());
|
||||||
|
Log.e("TasksXmlExporter", error);
|
||||||
|
if (!isService) {
|
||||||
|
displayErrorToast(error);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Unable to access the sdcard because it's not in the mounted state.
|
||||||
|
String error = ctx.getString(R.string.error_sdcard_general);
|
||||||
|
Log.e("TasksXmlExporter", error);
|
||||||
|
if (!isService) {
|
||||||
|
displayErrorToast(error);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setOutput(String file) {
|
||||||
|
this.output = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Runnable doBackgroundExport = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
/*Looper.prepare();
|
||||||
|
try {
|
||||||
|
doTasksExport();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e("TasksXmlExporter", "IOException in doTasksExport " + e.getMessage());
|
||||||
|
}
|
||||||
|
Looper.loop();*/
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public void setTaskController(TaskController taskController) {
|
||||||
|
this.taskController = taskController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTagController(TagController tagController) {
|
||||||
|
this.tagController = tagController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertController(AlertController alertController) {
|
||||||
|
this.alertController = alertController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSyncDataController(SyncDataController syncDataController) {
|
||||||
|
this.syncDataController = syncDataController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContext(Context ctx) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
setTaskController(new TaskController(ctx));
|
||||||
|
setTagController(new TagController(ctx));
|
||||||
|
setAlertController(new AlertController(ctx));
|
||||||
|
setSyncDataController(new SyncDataController(ctx));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue