Producteev Shared Desktop initial work. what's here: synchronizing multiple workspaces, displaying this information, displaying task responsiblity info, switching things into multiple workspaces

pull/14/head
Tim Su 16 years ago
parent 8b4b79db88
commit aa2fe7db1b

@ -13,9 +13,12 @@ import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer; import com.todoroo.astrid.api.DetailExposer;
import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.StoreObject;
import com.todoroo.astrid.producteev.sync.ProducteevDashboard;
import com.todoroo.astrid.producteev.sync.ProducteevDataService; import com.todoroo.astrid.producteev.sync.ProducteevDataService;
import com.todoroo.astrid.producteev.sync.ProducteevNote; import com.todoroo.astrid.producteev.sync.ProducteevNote;
import com.todoroo.astrid.producteev.sync.ProducteevTask; import com.todoroo.astrid.producteev.sync.ProducteevTask;
import com.todoroo.astrid.utility.Preferences;
/** /**
* Exposes Task Details for Producteev: * Exposes Task Details for Producteev:
@ -59,16 +62,36 @@ public class ProducteevDetailExposer extends BroadcastReceiver implements Detail
if(!extended) { if(!extended) {
long dashboardId = metadata.getValue(ProducteevTask.DASHBOARD_ID); long dashboardId = metadata.getValue(ProducteevTask.DASHBOARD_ID);
String dashboardName = ProducteevDataService.getInstance().getDashboardName(dashboardId); long responsibleId = metadata.getValue(ProducteevTask.RESPONSIBLE_ID);
// Prod dashboard is out of date. don't display Producteev stuff
if(dashboardName == null)
return null;
if(dashboardId > 0) { // display dashboard if not "no sync" or "default"
StoreObject ownerDashboard = null;
for(StoreObject dashboard : ProducteevDataService.getInstance().getDashboards()) {
if(dashboard.getValue(ProducteevDashboard.REMOTE_ID) == dashboardId) {
ownerDashboard = dashboard;
break;
}
}
if(dashboardId != ProducteevUtilities.DASHBOARD_NO_SYNC && dashboardId
!= Preferences.getLong(ProducteevUtilities.PREF_DEFAULT_DASHBOARD, 0L) &&
ownerDashboard != null) {
String dashboardName = ownerDashboard.getValue(ProducteevDashboard.NAME);
builder.append(context.getString(R.string.producteev_TLA_dashboard, builder.append(context.getString(R.string.producteev_TLA_dashboard,
dashboardId)).append(TaskAdapter.DETAIL_SEPARATOR); dashboardName)).append(TaskAdapter.DETAIL_SEPARATOR);
} }
// display responsible user if not current one
if(responsibleId > 0 && ownerDashboard != null && responsibleId !=
Preferences.getLong(ProducteevUtilities.PREF_USER_ID, 0L)) {
String users = ownerDashboard.getValue(ProducteevDashboard.USERS);
int index = users.indexOf(";" + responsibleId + ","); //$NON-NLS-1$ //$NON-NLS-2$
if(index > -1) {
String user = users.substring(users.indexOf(',', index),
users.indexOf(';', index + 1));
builder.append(context.getString(R.string.producteev_TLA_responsible,
user)).append(TaskAdapter.DETAIL_SEPARATOR);
}
}
} else { } else {
TodorooCursor<Metadata> notesCursor = ProducteevDataService.getInstance().getTaskNotesCursor(id); TodorooCursor<Metadata> notesCursor = ProducteevDataService.getInstance().getTaskNotesCursor(id);
try { try {

@ -10,6 +10,9 @@ import com.timsu.astrid.R;
import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.common.SyncProviderPreferences; import com.todoroo.astrid.common.SyncProviderPreferences;
import com.todoroo.astrid.common.SyncProviderUtilities; import com.todoroo.astrid.common.SyncProviderUtilities;
import com.todoroo.astrid.model.StoreObject;
import com.todoroo.astrid.producteev.sync.ProducteevDashboard;
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
import com.todoroo.astrid.producteev.sync.ProducteevSyncProvider; import com.todoroo.astrid.producteev.sync.ProducteevSyncProvider;
/** /**
@ -47,16 +50,23 @@ public class ProducteevPreferences extends SyncProviderPreferences {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
ListPreference defaultDash = (ListPreference)findPreference(getString(R.string.producteev_PPr_defaultdash_key)); ListPreference defaultDash = (ListPreference)findPreference(getString(R.string.producteev_PPr_defaultdash_key));
String[] entries, entryValues;
if(ProducteevUtilities.INSTANCE.isLoggedIn()) { if(ProducteevUtilities.INSTANCE.isLoggedIn()) {
// StoreObject[] dashboards = ProducteevDataService.getInstance().getDashboards();
entries = new String[dashboards.length + 1];
entryValues = new String[dashboards.length + 1];
for(int i = 0; i < dashboards.length; i++) {
entries[i + 1] = dashboards[i].getValue(ProducteevDashboard.NAME);
entryValues[i + 1] = Long.toString(dashboards[i].getValue(ProducteevDashboard.REMOTE_ID));
} }
String[] entries = new String[2]; } else {
entries[0] = getString(R.string.producteev_no_dashboard); entries = new String[2];
entries[1] = getString(R.string.producteev_default_dashboard); entries[1] = getString(R.string.producteev_default_dashboard);
entryValues = new String[2];
String[] entryValues = new String[2];
entryValues[0] = Integer.toString(ProducteevUtilities.DASHBOARD_NO_SYNC);
entryValues[1] = Integer.toString(ProducteevUtilities.DASHBOARD_DEFAULT); entryValues[1] = Integer.toString(ProducteevUtilities.DASHBOARD_DEFAULT);
}
entries[0] = getString(R.string.producteev_no_dashboard);
entryValues[0] = Integer.toString(ProducteevUtilities.DASHBOARD_NO_SYNC);
defaultDash.setEntries(entries); defaultDash.setEntries(entries);
defaultDash.setEntryValues(entryValues); defaultDash.setEntryValues(entryValues);
} }

@ -1,9 +1,8 @@
package com.todoroo.astrid.producteev; package com.todoroo.astrid.producteev;
import android.content.SharedPreferences.Editor;
import com.timsu.astrid.R; import com.timsu.astrid.R;
import com.todoroo.astrid.common.SyncProviderUtilities; import com.todoroo.astrid.common.SyncProviderUtilities;
import com.todoroo.astrid.utility.Preferences;
/** /**
* Displays synchronization preferences and an action panel so users can * Displays synchronization preferences and an action panel so users can
@ -37,22 +36,33 @@ public class ProducteevUtilities extends SyncProviderUtilities {
// --- producteev-specific preferences // --- producteev-specific preferences
private static final String PREF_SERVER_LAST_SYNC = "_last_server"; //$NON-NLS-1$ public static final String PREF_SERVER_LAST_SYNC = IDENTIFIER + "_last_server"; //$NON-NLS-1$
/** @return last sync date, or null if no last */ public static final String PREF_EMAIL = IDENTIFIER + "_email"; //$NON-NLS-1$
public String getLastServerSync() {
return getPrefs().getString(getIdentifier() + PREF_SERVER_LAST_SYNC, null); public static final String PREF_PASSWORD = IDENTIFIER + "_password"; //$NON-NLS-1$
}
public static final String PREF_DEFAULT_DASHBOARD = IDENTIFIER + "_defaultdash"; //$NON-NLS-1$
/** Deletes Last Successful Sync Date */ public static final String PREF_USER_ID = IDENTIFIER + "_userid"; //$NON-NLS-1$
public void setLastServerSync(String value) {
Editor editor = getPrefs().edit(); /**
editor.putString(getIdentifier() + PREF_SERVER_LAST_SYNC, value); * Gets default dashboard from setting
editor.commit(); * @return DASHBOARD_NO_SYNC if should not sync, otherwise remote id
*/
public long getDefaultDashboard() {
int defaultDashboard = Preferences.getIntegerFromString(R.string.producteev_PPr_defaultdash_key,
DASHBOARD_DEFAULT);
if(defaultDashboard == DASHBOARD_NO_SYNC)
return DASHBOARD_NO_SYNC;
else if(defaultDashboard == DASHBOARD_DEFAULT)
return Preferences.getLong(PREF_DEFAULT_DASHBOARD, 0);
else
return (long) defaultDashboard;
} }
private ProducteevUtilities() { private ProducteevUtilities() {
// // prevent instantiation
} }
} }

@ -96,6 +96,22 @@ public class ProducteevInvoker {
"fbuid", fbUid); "fbuid", fbUid);
} }
// --- dashboards
/**
* show list
*
* @param idResponsible (optional) if null return every task for current user
* @param since (optional) if not null, the function only returns tasks modified or created since this date
*
* @return array tasks/view
*/
public JSONArray dashboardsShowList(String since) throws ApiServiceException, IOException {
return getResponse(callAuthenticated("dashboards/show_list.json",
"token", token,
"since", since), "dashboards");
}
// --- tasks // --- tasks
/** /**
@ -212,6 +228,21 @@ public class ProducteevInvoker {
"deadline", deadline); "deadline", deadline);
} }
/**
* set a workspace
*
* @param idTask
* @param id_dashboard
*
* @return array tasks/view
*/
public JSONObject tasksSetWorkspace(long idTask, long idDashboard) throws ApiServiceException, IOException {
return callAuthenticated("tasks/set_workspace.json",
"token", token,
"id_task", idTask,
"id_dashboard", idDashboard);
}
/** /**
* delete a task * delete a task
* *

@ -1,86 +1,30 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.producteev.sync; package com.todoroo.astrid.producteev.sync;
import android.content.ContentValues;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.data.Property.LongProperty; import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty; import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.astrid.model.Task; import com.todoroo.astrid.model.StoreObject;
/** /**
* Data Model which represents a dashboard in Producteev * {@link StoreObject} entries for a Producteev Dashboard
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
@SuppressWarnings("nls") public class ProducteevDashboard {
public class ProducteevDashboard extends AbstractModel {
// --- table
public static final Table TABLE = new Table("dashboards", ProducteevDashboard.class);
// --- properties
/** ID (corresponds to RTM ID) */
public static final LongProperty ID = new LongProperty(
TABLE, ID_PROPERTY_NAME);
/** Name */
public static final StringProperty NAME = new StringProperty(
TABLE, "name");
/** List of all properties for this model */
public static final Property<?>[] PROPERTIES = generateProperties(ProducteevDashboard.class);
// --- defaults
/** Default values container */ /** type*/
private static final ContentValues defaultValues = new ContentValues(); public static final String TYPE = "pdv-dash"; //$NON-NLS-1$
// static { /** dashboard id in producteev */
// defaultValues.put(POSITION.name, 0); public static final LongProperty REMOTE_ID = new LongProperty(StoreObject.TABLE,
// defaultValues.put(ARCHIVED.name, 0); StoreObject.ITEM.name);
// }
@Override /** dashboard name */
public ContentValues getDefaultValues() { public static final StringProperty NAME = new StringProperty(StoreObject.TABLE,
return defaultValues; StoreObject.VALUE1.name);
}
// --- data access boilerplate
public ProducteevDashboard() {
super();
}
public ProducteevDashboard(TodorooCursor<ProducteevDashboard> cursor) { /** users (list in the format "id_user,name;id_user,name;") */
this(); public static final StringProperty USERS = new StringProperty(StoreObject.TABLE,
readPropertiesFromCursor(cursor); StoreObject.VALUE2.name);
}
public void readFromCursor(TodorooCursor<ProducteevDashboard> cursor) {
super.readPropertiesFromCursor(cursor);
}
@Override
public long getId() {
return getIdHelper(ID);
};
// --- parcelable helpers
private static final Creator<Task> CREATOR = new ModelCreator<Task>(Task.class);
@Override
protected Creator<? extends AbstractModel> getCreator() {
return CREATOR;
}
} }

@ -4,13 +4,14 @@
package com.todoroo.astrid.producteev.sync; package com.todoroo.astrid.producteev.sync;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.Random; import java.util.Random;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context; import android.content.Context;
import com.todoroo.andlib.data.GenericDao;
import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.Autowired;
@ -19,12 +20,14 @@ import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Join; import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.SoftHashMap;
import com.todoroo.astrid.dao.MetadataDao; import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria; import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.StoreObjectDao;
import com.todoroo.astrid.dao.StoreObjectDao.StoreObjectCriteria;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria; import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.StoreObject;
import com.todoroo.astrid.model.Task; import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.producteev.ProducteevUtilities; import com.todoroo.astrid.producteev.ProducteevUtilities;
import com.todoroo.astrid.rmilk.data.MilkNote; import com.todoroo.astrid.rmilk.data.MilkNote;
@ -51,16 +54,15 @@ public final class ProducteevDataService {
protected final Context context; protected final Context context;
private final ProducteevDatabase prodDatabase = new ProducteevDatabase();
private final GenericDao<ProducteevDashboard> prodDashboardDao;
@Autowired @Autowired
private TaskDao taskDao; private TaskDao taskDao;
@Autowired @Autowired
private MetadataDao metadataDao; private MetadataDao metadataDao;
@Autowired
private StoreObjectDao storeObjectDao;
private final ProducteevUtilities preferences = ProducteevUtilities.INSTANCE; private final ProducteevUtilities preferences = ProducteevUtilities.INSTANCE;
static final Random random = new Random(); static final Random random = new Random();
@ -68,7 +70,6 @@ public final class ProducteevDataService {
private ProducteevDataService(Context context) { private ProducteevDataService(Context context) {
this.context = context; this.context = context;
DependencyInjectionService.getInstance().inject(this); DependencyInjectionService.getInstance().inject(this);
prodDashboardDao = new GenericDao<ProducteevDashboard>(ProducteevDashboard.class, prodDatabase);
} }
// --- task and metadata methods // --- task and metadata methods
@ -162,8 +163,7 @@ public final class ProducteevDataService {
where(Criterion.and(MetadataCriteria.byTask(task.getId()), where(Criterion.and(MetadataCriteria.byTask(task.getId()),
Criterion.or(MetadataCriteria.withKey(TagService.KEY), Criterion.or(MetadataCriteria.withKey(TagService.KEY),
MetadataCriteria.withKey(ProducteevTask.METADATA_KEY), MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
// FIXME: Constant from other plugin shouldnt be used MetadataCriteria.withKey(MilkNote.METADATA_KEY), // to sync rmilk notes
MetadataCriteria.withKey(MilkNote.METADATA_KEY),
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY))))); MetadataCriteria.withKey(ProducteevNote.METADATA_KEY)))));
try { try {
for(metadataCursor.moveToFirst(); !metadataCursor.isAfterLast(); metadataCursor.moveToNext()) { for(metadataCursor.moveToFirst(); !metadataCursor.isAfterLast(); metadataCursor.moveToNext()) {
@ -203,33 +203,82 @@ public final class ProducteevDataService {
return cursor; return cursor;
} }
// --- list methods // --- dashboard methods
private final Map<Long, String> dashboardCache = private StoreObject[] dashboards = null;
Collections.synchronizedMap(new SoftHashMap<Long, String>());
/** /**
* Get dashboard name by dashboard id * Reads dashboards
* @param dashboardId
* @return null if no dashboard by this id exists, otherwise dashboard name
*/ */
public String getDashboardName(long dashboardId) { private void readDashboards() {
if(dashboardCache.containsKey(dashboardId)) if(dashboards != null)
return dashboardCache.get(dashboardId); return;
TodorooCursor<ProducteevDashboard> cursor = prodDashboardDao.query(Query.select( TodorooCursor<StoreObject> cursor = storeObjectDao.query(Query.select(StoreObject.PROPERTIES).
ProducteevDashboard.NAME).where(ProducteevDashboard.ID.eq(dashboardId))); where(StoreObjectCriteria.byType(ProducteevDashboard.TYPE)));
try { try {
if(cursor.getCount() == 0) { dashboards = new StoreObject[cursor.getCount()];
dashboardCache.put(dashboardId, null); for(int i = 0; i < dashboards.length; i++) {
return null; cursor.moveToNext();
StoreObject dashboard = new StoreObject(cursor);
dashboards[i] = dashboard;
} }
cursor.moveToFirst();
String name = cursor.get(ProducteevDashboard.NAME);
dashboardCache.put(dashboardId, name);
return name;
} finally { } finally {
cursor.close(); cursor.close();
} }
} }
/**
* @return a list of dashboards
*/
public StoreObject[] getDashboards() {
readDashboards();
return dashboards;
}
/**
* Reads dashboards
* @throws JSONException
*/
@SuppressWarnings("nls")
public void updateDashboards(JSONArray changedDashboards) throws JSONException {
readDashboards();
for(int i = 0; i < changedDashboards.length(); i++) {
JSONObject remote = changedDashboards.getJSONObject(i).getJSONObject("dashboard");
long id = remote.getLong("id_dashboard");
StoreObject local = null;
for(StoreObject dashboard : dashboards) {
if(dashboard.getValue(ProducteevDashboard.REMOTE_ID).equals(id)) {
local = dashboard;
break;
}
}
if(remote.getInt("deleted") != 0) {
if(local != null)
storeObjectDao.delete(local.getId());
continue;
}
if(local == null)
local = new StoreObject();
local.setValue(StoreObject.TYPE, ProducteevDashboard.TYPE);
local.setValue(ProducteevDashboard.REMOTE_ID, id);
local.setValue(ProducteevDashboard.NAME, remote.getString("title"));
StringBuilder users = new StringBuilder();
JSONArray accessList = remote.getJSONArray("accesslist");
for(int j = 0; j < accessList.length(); j++) {
JSONObject user = accessList.getJSONObject(j).getJSONObject("user");
users.append(user.getLong("id_user")).append(',').
append(user.getString("firstName")).append(' ').
append(user.getString("lastName")).append(';');
}
local.setValue(ProducteevDashboard.USERS, users.toString());
storeObjectDao.persist(local);
}
// clear dashboard cache
dashboards = null;
}
} }

@ -1,76 +0,0 @@
/*
* Copyright (c) 2009, Todoroo Inc
* All Rights Reserved
* http://www.todoroo.com
*/
package com.todoroo.astrid.producteev.sync;
import com.todoroo.andlib.data.AbstractDatabase;
import com.todoroo.andlib.data.GenericDao;
import com.todoroo.andlib.data.Table;
/**
* Database wrapper
*
* @author Tim Su <tim@todoroo.com>
*
*/
@SuppressWarnings("nls")
public class ProducteevDatabase extends AbstractDatabase {
// --- constants
/**
* Database version number. This variable must be updated when database
* tables are updated, as it determines whether a database needs updating.
*/
public static final int VERSION = 1;
/**
* Database name (must be unique)
*/
private static final String NAME = "producteev";
/**
* List of table/ If you're adding a new table, add it to this list and
* also make sure that our SQLite helper does the right thing.
*/
public static final Table[] TABLES = new Table[] {
ProducteevDashboard.TABLE,
};
// --- implementation
private final GenericDao<ProducteevDashboard> dao = new GenericDao<ProducteevDashboard>(ProducteevDashboard.class, this);
@Override
protected String getName() {
return NAME;
}
@Override
protected int getVersion() {
return VERSION;
}
@Override
public Table[] getTables() {
return TABLES;
}
public GenericDao<ProducteevDashboard> getDao() {
return dao;
}
@Override
protected void onCreateTables() {
// do nothing
}
@Override
protected boolean onUpgrade(int oldVersion, int newVersion) {
return false;
}
}

@ -33,6 +33,7 @@ import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.api.TaskContainer; import com.todoroo.astrid.api.TaskContainer;
import com.todoroo.astrid.common.SyncProvider; import com.todoroo.astrid.common.SyncProvider;
import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.StoreObject;
import com.todoroo.astrid.model.Task; import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.producteev.ProducteevLoginActivity; import com.todoroo.astrid.producteev.ProducteevLoginActivity;
import com.todoroo.astrid.producteev.ProducteevPreferences; import com.todoroo.astrid.producteev.ProducteevPreferences;
@ -51,11 +52,10 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
private ProducteevDataService dataService = null; private ProducteevDataService dataService = null;
private ProducteevInvoker invoker = null; private ProducteevInvoker invoker = null;
private long defaultDashboard;
private final ProducteevUtilities preferences = ProducteevUtilities.INSTANCE; private final ProducteevUtilities preferences = ProducteevUtilities.INSTANCE;
/** map of producteev labels to id's */ /** map of producteev labels to id's */
private final HashMap<String, Long> labelMap = new HashMap<String, Long>(); private final HashMap<ProducteevLabel, Long> labelMap = new HashMap<ProducteevLabel, Long>();
static { static {
AstridDependencyInjector.initialize(); AstridDependencyInjector.initialize();
@ -193,20 +193,33 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
protected void performSync() { protected void performSync() {
try { try {
// load user information // load user information
JSONObject user = invoker.usersView(null); JSONObject user = invoker.usersView(null).getJSONObject("user");
defaultDashboard = user.getJSONObject("user").getLong("default_dashboard"); saveUserData(user);
// get labels String lastServerSync = Preferences.getStringValue(ProducteevUtilities.PREF_SERVER_LAST_SYNC);
JSONArray labels = invoker.labelsShowList(defaultDashboard, null);
readLabels(labels);
// read all tasks
String lastServerSync = preferences.getLastServerSync();
if(lastServerSync != null) if(lastServerSync != null)
lastServerSync = lastServerSync.substring(0, lastServerSync.lastIndexOf(' ')); lastServerSync = lastServerSync.substring(0, lastServerSync.lastIndexOf(' '));
JSONArray tasks = invoker.tasksShowList(defaultDashboard, lastServerSync);
SyncData<ProducteevTaskContainer> syncData = populateSyncData(tasks); // read dashboards
JSONArray dashboards = invoker.dashboardsShowList(lastServerSync);
dataService.updateDashboards(dashboards);
// read labels and tasks for each dashboard
ArrayList<ProducteevTaskContainer> remoteTasks = new ArrayList<ProducteevTaskContainer>();
for(StoreObject dashboard : dataService.getDashboards()) {
long dashboardId = dashboard.getValue(ProducteevDashboard.REMOTE_ID);
JSONArray labels = invoker.labelsShowList(dashboardId, null);
readLabels(labels);
JSONArray tasks = invoker.tasksShowList(dashboardId, lastServerSync);
for(int i = 0; i < tasks.length(); i++) {
ProducteevTaskContainer remote = parseRemoteTask(tasks.getJSONObject(i));
dataService.findLocalMatch(remote);
remoteTasks.add(remote);
}
}
SyncData<ProducteevTaskContainer> syncData = populateSyncData(remoteTasks);
try { try {
synchronizeTasks(syncData); synchronizeTasks(syncData);
} finally { } finally {
@ -214,7 +227,7 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
syncData.localUpdated.close(); syncData.localUpdated.close();
} }
preferences.setLastServerSync(invoker.time()); Preferences.setString(ProducteevUtilities.PREF_SERVER_LAST_SYNC, invoker.time());
preferences.recordSuccessfulSync(); preferences.recordSuccessfulSync();
FlurryAgent.onEvent("pdv-sync-finished"); //$NON-NLS-1$ FlurryAgent.onEvent("pdv-sync-finished"); //$NON-NLS-1$
@ -229,6 +242,13 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
// ------------------------------------------------------------ sync data // ------------------------------------------------------------ sync data
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
private void saveUserData(JSONObject user) throws JSONException {
long defaultDashboard = user.getLong("default_dashboard");
long userId = user.getLong("id_user");
Preferences.setLong(ProducteevUtilities.PREF_DEFAULT_DASHBOARD, defaultDashboard);
Preferences.setLong(ProducteevUtilities.PREF_USER_ID, userId);
}
// all synchronized properties // all synchronized properties
private static final Property<?>[] PROPERTIES = new Property<?>[] { private static final Property<?>[] PROPERTIES = new Property<?>[] {
Task.ID, Task.ID,
@ -246,21 +266,13 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
* Populate SyncData data structure * Populate SyncData data structure
* @throws JSONException * @throws JSONException
*/ */
private SyncData<ProducteevTaskContainer> populateSyncData(JSONArray tasks) throws JSONException { private SyncData<ProducteevTaskContainer> populateSyncData(ArrayList<ProducteevTaskContainer> remoteTasks) throws JSONException {
// fetch locally created tasks // fetch locally created tasks
TodorooCursor<Task> localCreated = dataService.getLocallyCreated(PROPERTIES); TodorooCursor<Task> localCreated = dataService.getLocallyCreated(PROPERTIES);
// fetch locally updated tasks // fetch locally updated tasks
TodorooCursor<Task> localUpdated = dataService.getLocallyUpdated(PROPERTIES); TodorooCursor<Task> localUpdated = dataService.getLocallyUpdated(PROPERTIES);
// read json response
ArrayList<ProducteevTaskContainer> remoteTasks = new ArrayList<ProducteevTaskContainer>(tasks.length());
for(int i = 0; i < tasks.length(); i++) {
ProducteevTaskContainer remote = parseRemoteTask(tasks.getJSONObject(i));
dataService.findLocalMatch(remote);
remoteTasks.add(remote);
}
return new SyncData<ProducteevTaskContainer>(remoteTasks, localCreated, localUpdated); return new SyncData<ProducteevTaskContainer>(remoteTasks, localCreated, localUpdated);
} }
@ -271,9 +283,16 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
@Override @Override
protected void create(ProducteevTaskContainer local) throws IOException { protected void create(ProducteevTaskContainer local) throws IOException {
Task localTask = local.task; Task localTask = local.task;
long dashboard = defaultDashboard; long dashboard = ProducteevUtilities.INSTANCE.getDefaultDashboard();
if(local.pdvTask.containsNonNullValue(ProducteevTask.DASHBOARD_ID)) if(local.pdvTask.containsNonNullValue(ProducteevTask.DASHBOARD_ID))
dashboard = local.pdvTask.getValue(ProducteevTask.DASHBOARD_ID); dashboard = local.pdvTask.getValue(ProducteevTask.DASHBOARD_ID);
if(dashboard == ProducteevUtilities.DASHBOARD_NO_SYNC) {
// set a bogus task id, then return without creating
local.pdvTask.setValue(ProducteevTask.ID, 1L);
return;
}
JSONObject response = invoker.tasksCreate(localTask.getValue(Task.TITLE), JSONObject response = invoker.tasksCreate(localTask.getValue(Task.TITLE),
null, dashboard, createDeadline(localTask), createReminder(localTask), null, dashboard, createDeadline(localTask), createReminder(localTask),
localTask.isCompleted() ? 2 : 1, createStars(localTask)); localTask.isCompleted() ? 2 : 1, createStars(localTask));
@ -348,14 +367,20 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
*/ */
@Override @Override
protected void push(ProducteevTaskContainer local, ProducteevTaskContainer remote) throws IOException { protected void push(ProducteevTaskContainer local, ProducteevTaskContainer remote) throws IOException {
boolean remerge = false; long idTask = local.pdvTask.getValue(ProducteevTask.ID);
long idDashboard = local.pdvTask.getValue(ProducteevTask.DASHBOARD_ID);
// if local is marked do not sync, handle accordingly
if(idDashboard == ProducteevUtilities.DASHBOARD_NO_SYNC) {
if(idTask != 1)
invoker.tasksDelete(idTask);
return;
}
// fetch remote task for comparison // fetch remote task for comparison
if(remote == null) if(remote == null)
remote = pull(local); remote = pull(local);
long idTask = local.pdvTask.getValue(ProducteevTask.ID);
// either delete or re-create if necessary // either delete or re-create if necessary
if(shouldTransmit(local, Task.DELETION_DATE, remote)) { if(shouldTransmit(local, Task.DELETION_DATE, remote)) {
if(local.task.getValue(Task.DELETION_DATE) > 0) if(local.task.getValue(Task.DELETION_DATE) > 0)
@ -364,6 +389,13 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
create(local); create(local);
} }
// dashboard
if(remote != null && idDashboard != remote.pdvTask.getValue(ProducteevTask.DASHBOARD_ID)) {
invoker.tasksSetWorkspace(idTask, idDashboard);
remote = pull(local);
}
// core properties
if(shouldTransmit(local, Task.TITLE, remote)) if(shouldTransmit(local, Task.TITLE, remote))
invoker.tasksSetTitle(idTask, local.task.getValue(Task.TITLE)); invoker.tasksSetTitle(idTask, local.task.getValue(Task.TITLE));
if(shouldTransmit(local, Task.IMPORTANCE, remote)) if(shouldTransmit(local, Task.IMPORTANCE, remote))
@ -373,7 +405,48 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
if(shouldTransmit(local, Task.COMPLETION_DATE, remote)) if(shouldTransmit(local, Task.COMPLETION_DATE, remote))
invoker.tasksSetStatus(idTask, local.task.isCompleted() ? 2 : 1); invoker.tasksSetStatus(idTask, local.task.isCompleted() ? 2 : 1);
try {
// tags // tags
transmitTags(local, remote, idTask, idDashboard);
// notes
if(!TextUtils.isEmpty(local.task.getValue(Task.NOTES))) {
String note = local.task.getValue(Task.NOTES);
JSONObject result = invoker.tasksNoteCreate(idTask, note);
local.metadata.add(ProducteevNote.create(result.getJSONObject("note")));
local.task.setValue(Task.NOTES, "");
}
// milk note => producteev note
if(local.findMetadata(MilkNote.METADATA_KEY) != null && (remote == null ||
(remote.findMetadata(ProducteevNote.METADATA_KEY) == null))) {
for(Metadata item : local.metadata) {
if(MilkNote.METADATA_KEY.equals(item.getValue(Metadata.KEY))) {
String message = MilkNote.toTaskDetail(item);
JSONObject result = invoker.tasksNoteCreate(idTask, message);
local.metadata.add(ProducteevNote.create(result.getJSONObject("note")));
}
}
}
} catch (JSONException e) {
throw new ApiResponseParseException(e);
}
}
/**
* Transmit tags
*
* @param local
* @param remote
* @param idTask
* @param idDashboard
* @throws ApiServiceException
* @throws JSONException
* @throws IOException
*/
private void transmitTags(ProducteevTaskContainer local,
ProducteevTaskContainer remote, long idTask, long idDashboard) throws ApiServiceException, JSONException, IOException {
HashSet<String> localTags = new HashSet<String>(); HashSet<String> localTags = new HashSet<String>();
HashSet<String> remoteTags = new HashSet<String>(); HashSet<String> remoteTags = new HashSet<String>();
for(Metadata item : local.metadata) for(Metadata item : local.metadata)
@ -385,7 +458,6 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
remoteTags.add(item.getValue(TagService.TAG)); remoteTags.add(item.getValue(TagService.TAG));
} }
try {
if(!localTags.equals(remoteTags)) { if(!localTags.equals(remoteTags)) {
HashSet<String> toAdd = new HashSet<String>(localTags); HashSet<String> toAdd = new HashSet<String>(localTags);
toAdd.removeAll(remoteTags); toAdd.removeAll(remoteTags);
@ -395,8 +467,8 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
if(toAdd.size() > 0) { if(toAdd.size() > 0) {
for(String label : toAdd) { for(String label : toAdd) {
if(!labelMap.containsKey(label)) { if(!labelMap.containsKey(label)) {
JSONObject result = invoker.labelsCreate(defaultDashboard, label).getJSONObject("label"); JSONObject result = invoker.labelsCreate(idDashboard, label).getJSONObject("label");
labelMap.put(ApiUtilities.decode(result.getString("title")), result.getLong("id_label")); putLabelIntoCache(result);
} }
invoker.tasksSetLabel(idTask, labelMap.get(label)); invoker.tasksSetLabel(idTask, labelMap.get(label));
} }
@ -410,37 +482,8 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
} }
} }
} }
// notes
if(!TextUtils.isEmpty(local.task.getValue(Task.NOTES))) {
String note = local.task.getValue(Task.NOTES);
JSONObject result = invoker.tasksNoteCreate(idTask, note);
local.metadata.add(ProducteevNote.create(result.getJSONObject("note")));
local.task.setValue(Task.NOTES, "");
}
// milk note => producteev note
if(local.findMetadata(MilkNote.METADATA_KEY) != null && (remote == null ||
(remote.findMetadata(ProducteevNote.METADATA_KEY) == null))) {
for(Metadata item : local.metadata)
if(MilkNote.METADATA_KEY.equals(item.getValue(Metadata.KEY))) {
String message = MilkNote.toTaskDetail(item);
JSONObject result = invoker.tasksNoteCreate(idTask, message);
local.metadata.add(ProducteevNote.create(result.getJSONObject("note")));
}
}
} catch (JSONException e) {
throw new ApiResponseParseException(e);
}
if(remerge) {
remote = pull(local);
remote.task.setId(local.task.getId());
write(remote);
}
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// --------------------------------------------------------- read / write // --------------------------------------------------------- read / write
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@ -548,9 +591,14 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
destination.pdvTask = source.pdvTask; destination.pdvTask = source.pdvTask;
} }
public class ProducteevLabel {
public String name;
public long dashboard;
}
/** /**
* Read labels into label map * Read labels into label map
* @param dashboardId
* @throws JSONException * @throws JSONException
* @throws ApiServiceException * @throws ApiServiceException
* @throws IOException * @throws IOException
@ -558,8 +606,22 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
private void readLabels(JSONArray labels) throws JSONException, ApiServiceException, IOException { private void readLabels(JSONArray labels) throws JSONException, ApiServiceException, IOException {
for(int i = 0; i < labels.length(); i++) { for(int i = 0; i < labels.length(); i++) {
JSONObject label = labels.getJSONObject(i).getJSONObject("label"); JSONObject label = labels.getJSONObject(i).getJSONObject("label");
labelMap.put(ApiUtilities.decode(label.getString("title")), label.getLong("id_label")); putLabelIntoCache(label);
}
} }
/**
* Puts a single label into the cache
* @param dashboardId
* @param label
* @throws JSONException
*/
private void putLabelIntoCache(JSONObject label)
throws JSONException {
ProducteevLabel labelContainer = new ProducteevLabel();
labelContainer.name = ApiUtilities.decode(label.getString("title"));
labelContainer.dashboard = label.getLong("id_dashboard");
labelMap.put(labelContainer, label.getLong("id_label"));
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------

@ -21,4 +21,12 @@ public class ProducteevTask {
public static final LongProperty DASHBOARD_ID = new LongProperty(Metadata.TABLE, public static final LongProperty DASHBOARD_ID = new LongProperty(Metadata.TABLE,
Metadata.VALUE2.name); Metadata.VALUE2.name);
/** creator id */
public static final LongProperty CREATOR_ID = new LongProperty(Metadata.TABLE,
Metadata.VALUE3.name);
/** responsible id */
public static final LongProperty RESPONSIBLE_ID = new LongProperty(Metadata.TABLE,
Metadata.VALUE4.name);
} }

@ -35,6 +35,8 @@ public class ProducteevTaskContainer extends TaskContainer {
pdvTask.setValue(Metadata.KEY, ProducteevTask.METADATA_KEY); pdvTask.setValue(Metadata.KEY, ProducteevTask.METADATA_KEY);
pdvTask.setValue(ProducteevTask.ID, remoteTask.optLong("id_task")); pdvTask.setValue(ProducteevTask.ID, remoteTask.optLong("id_task"));
pdvTask.setValue(ProducteevTask.DASHBOARD_ID, remoteTask.optLong("id_dashboard")); pdvTask.setValue(ProducteevTask.DASHBOARD_ID, remoteTask.optLong("id_dashboard"));
pdvTask.setValue(ProducteevTask.RESPONSIBLE_ID, remoteTask.optLong("id_responsible"));
pdvTask.setValue(ProducteevTask.CREATOR_ID, remoteTask.optLong("id_creator"));
} }
public ProducteevTaskContainer(Task task, ArrayList<Metadata> metadata) { public ProducteevTaskContainer(Task task, ArrayList<Metadata> metadata) {

@ -4,9 +4,12 @@
<!-- ====================== Plugin Boilerplate ========================= --> <!-- ====================== Plugin Boilerplate ========================= -->
<!-- task detail showing Producteev dashboard information --> <!-- task detail showing Producteev dashboard information (%s => workspace name) -->
<string name="producteev_TLA_dashboard">Workspace: %s</string> <string name="producteev_TLA_dashboard">Workspace: %s</string>
<!-- task detail showing Producteev responsible information (%s => responsible user) -->
<string name="producteev_TLA_responsible">Responsible: %s</string>
<!-- ==================================================== Preferences == --> <!-- ==================================================== Preferences == -->
<!-- Preferences Title: Producteev --> <!-- Preferences Title: Producteev -->

@ -19,8 +19,8 @@
*/ */
package com.todoroo.astrid.activity; package com.todoroo.astrid.activity;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -37,6 +37,7 @@ import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.text.format.DateUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
@ -735,8 +736,9 @@ public final class TaskEditActivity extends TabActivity {
Task.URGENCY_TODAY); Task.URGENCY_TODAY);
urgencyValues[2] = new UrgencyValue(labels[2], urgencyValues[2] = new UrgencyValue(labels[2],
Task.URGENCY_TOMORROW); Task.URGENCY_TOMORROW);
String dayAfterTomorrow = new SimpleDateFormat("EEEE").format( //$NON-NLS-1$ String dayAfterTomorrow = DateUtils.getDayOfWeekString(
new Date(DateUtilities.now() + 2 * DateUtilities.ONE_DAY)); new Date(DateUtilities.now() + 2 * DateUtilities.ONE_DAY).getDay() +
Calendar.SUNDAY, 0);
urgencyValues[3] = new UrgencyValue(dayAfterTomorrow, urgencyValues[3] = new UrgencyValue(dayAfterTomorrow,
Task.URGENCY_DAY_AFTER); Task.URGENCY_DAY_AFTER);
urgencyValues[4] = new UrgencyValue(labels[4], urgencyValues[4] = new UrgencyValue(labels[4],

@ -354,13 +354,13 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
ServiceConnection refreshConnection = new ServiceConnection() { ServiceConnection refreshConnection = new ServiceConnection() {
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
System.err.println("connected to service " + name); System.err.println("connected to service " + name); //$NON-NLS-1$
// //
} }
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
// service disconnected, let's refresh // service disconnected, let's refresh
System.err.println("your junk was done, refreshing"); System.err.println("your junk was done, refreshing"); //$NON-NLS-1$
loadTaskListContent(true); loadTaskListContent(true);
} }
}; };

@ -6,9 +6,11 @@
package com.todoroo.astrid.dao; package com.todoroo.astrid.dao;
import com.todoroo.andlib.data.AbstractDatabase; import com.todoroo.andlib.data.AbstractDatabase;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Table; import com.todoroo.andlib.data.Table;
import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.StoreObject;
import com.todoroo.astrid.model.Task; import com.todoroo.astrid.model.Task;
/** /**
@ -26,7 +28,7 @@ public class Database extends AbstractDatabase {
* Database version number. This variable must be updated when database * Database version number. This variable must be updated when database
* tables are updated, as it determines whether a database needs updating. * tables are updated, as it determines whether a database needs updating.
*/ */
public static final int VERSION = 3; public static final int VERSION = 4;
/** /**
* Database name (must be unique) * Database name (must be unique)
@ -40,6 +42,7 @@ public class Database extends AbstractDatabase {
public static final Table[] TABLES = new Table[] { public static final Table[] TABLES = new Table[] {
Task.TABLE, Task.TABLE,
Metadata.TABLE, Metadata.TABLE,
StoreObject.TABLE,
}; };
// --- implementation // --- implementation
@ -70,24 +73,52 @@ public class Database extends AbstractDatabase {
append(Metadata.TASK.name). append(Metadata.TASK.name).
append(')'); append(')');
database.execSQL(sql.toString()); database.execSQL(sql.toString());
sql.setLength(0);
sql.append("CREATE INDEX IF NOT EXISTS so_id ON ").
append(StoreObject.TABLE).append('(').
append(StoreObject.TYPE).append(',').
append(StoreObject.ITEM).
append(')');
database.execSQL(sql.toString());
sql.setLength(0);
} }
@Override @Override
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value="SF_SWITCH_FALLTHROUGH") @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="SF_SWITCH_FALLTHROUGH")
protected synchronized boolean onUpgrade(int oldVersion, int newVersion) { protected synchronized boolean onUpgrade(int oldVersion, int newVersion) {
SqlConstructorVisitor visitor = new SqlConstructorVisitor();
switch(oldVersion) { switch(oldVersion) {
case 1: { case 1: {
SqlConstructorVisitor visitor = new SqlConstructorVisitor();
database.execSQL("ALTER TABLE " + Task.TABLE.name + " ADD " + database.execSQL("ALTER TABLE " + Task.TABLE.name + " ADD " +
Task.RECURRENCE.accept(visitor, null)); Task.RECURRENCE.accept(visitor, null));
} }
case 2: { case 2: {
SqlConstructorVisitor visitor = new SqlConstructorVisitor();
for(Property<?> property : new Property<?>[] { Metadata.VALUE2, for(Property<?> property : new Property<?>[] { Metadata.VALUE2,
Metadata.VALUE3, Metadata.VALUE4, Metadata.VALUE5 }) Metadata.VALUE3, Metadata.VALUE4, Metadata.VALUE5 })
database.execSQL("ALTER TABLE " + Metadata.TABLE.name + " ADD " + database.execSQL("ALTER TABLE " + Metadata.TABLE.name + " ADD " +
property.accept(visitor, null)); property.accept(visitor, null));
} }
case 3: {
StringBuilder sql = new StringBuilder();
sql.append("CREATE TABLE IF NOT EXISTS ").append(StoreObject.TABLE.name).append('(').
append(AbstractModel.ID_PROPERTY).append(" INTEGER PRIMARY KEY AUTOINCREMENT");
for(Property<?> property : StoreObject.PROPERTIES) {
if(AbstractModel.ID_PROPERTY.name.equals(property.name))
continue;
sql.append(',').append(property.accept(visitor, null));
}
sql.append(')');
database.execSQL(sql.toString());
sql.setLength(0);
sql.append("CREATE INDEX IF NOT EXISTS so_id ON ").
append(StoreObject.TABLE).append('(').
append(StoreObject.TYPE).append(',').
append(StoreObject.ITEM).
append(')');
database.execSQL(sql.toString());
}
return true; return true;
} }

@ -0,0 +1,52 @@
/*
* Copyright (c) 2009, Todoroo Inc
* All Rights Reserved
* http://www.todoroo.com
*/
package com.todoroo.astrid.dao;
import com.todoroo.andlib.data.GenericDao;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.astrid.model.StoreObject;
/**
* Data Access layer for {@link StoreObject}-related operations.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class StoreObjectDao extends GenericDao<StoreObject> {
@Autowired
private Database database;
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UR_UNINIT_READ")
public StoreObjectDao() {
super(StoreObject.class);
DependencyInjectionService.getInstance().inject(this);
setDatabase(database);
}
// --- SQL clause generators
/**
* Generates SQL clauses
*/
public static class StoreObjectCriteria {
/** Returns all store objects with given type */
public static Criterion byType(String type) {
return StoreObject.TYPE.eq(type);
}
/** Returns store object with type and key */
public static Criterion byTypeAndItem(String type, String item) {
return Criterion.and(byType(type), StoreObject.ITEM.eq(item));
}
}
}

@ -8,10 +8,10 @@ import android.content.ContentValues;
import com.todoroo.andlib.data.AbstractModel; import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.data.Property.LongProperty; import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty; import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.data.TodorooCursor;
/** /**
* Data Model which represents a piece of metadata associated with a task * Data Model which represents a piece of metadata associated with a task
@ -48,15 +48,15 @@ public class Metadata extends AbstractModel {
public static final StringProperty VALUE2 = new StringProperty( public static final StringProperty VALUE2 = new StringProperty(
TABLE, "value2"); TABLE, "value2");
/** Metadata Text Value Column 1 */ /** Metadata Text Value Column 3 */
public static final StringProperty VALUE3 = new StringProperty( public static final StringProperty VALUE3 = new StringProperty(
TABLE, "value3"); TABLE, "value3");
/** Metadata Text Value Column 1 */ /** Metadata Text Value Column 4 */
public static final StringProperty VALUE4 = new StringProperty( public static final StringProperty VALUE4 = new StringProperty(
TABLE, "value4"); TABLE, "value4");
/** Metadata Text Value Column 1 */ /** Metadata Text Value Column 5 */
public static final StringProperty VALUE5 = new StringProperty( public static final StringProperty VALUE5 = new StringProperty(
TABLE, "value5"); TABLE, "value5");
@ -95,7 +95,7 @@ public class Metadata extends AbstractModel {
// --- parcelable helpers // --- parcelable helpers
private static final Creator<Task> CREATOR = new ModelCreator<Task>(Task.class); private static final Creator<Metadata> CREATOR = new ModelCreator<Metadata>(Metadata.class);
@Override @Override
protected Creator<? extends AbstractModel> getCreator() { protected Creator<? extends AbstractModel> getCreator() {

@ -0,0 +1,105 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.model;
import android.content.ContentValues;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.data.TodorooCursor;
/**
* Data Model which represents a piece of data unrelated to a task
*
* @author Tim Su <tim@todoroo.com>
*
*/
@SuppressWarnings("nls")
public class StoreObject extends AbstractModel {
// --- table
public static final Table TABLE = new Table("store", StoreObject.class);
// --- properties
/** ID */
public static final LongProperty ID = new LongProperty(
TABLE, ID_PROPERTY_NAME);
/** Store Type Key */
public static final StringProperty TYPE = new StringProperty(
TABLE, "type");
/** Store Item Key */
public static final StringProperty ITEM= new StringProperty(
TABLE, "item");
/** Store Value Column 1 */
public static final StringProperty VALUE1 = new StringProperty(
TABLE, "value");
/** Store Value Column 2 */
public static final StringProperty VALUE2 = new StringProperty(
TABLE, "value2");
/** Store Value Column 3 */
public static final StringProperty VALUE3 = new StringProperty(
TABLE, "value3");
/** Store Value Column 4 */
public static final StringProperty VALUE4 = new StringProperty(
TABLE, "value4");
/** Store Value Column 5 */
public static final StringProperty VALUE5 = new StringProperty(
TABLE, "value5");
/** List of all properties for this model */
public static final Property<?>[] PROPERTIES = generateProperties(StoreObject.class);
// --- defaults
/** Default values container */
private static final ContentValues defaultValues = new ContentValues();
@Override
public ContentValues getDefaultValues() {
return defaultValues;
}
// --- data access boilerplate
public StoreObject() {
super();
}
public StoreObject(TodorooCursor<StoreObject> cursor) {
this();
readPropertiesFromCursor(cursor);
}
public void readFromCursor(TodorooCursor<StoreObject> cursor) {
super.readPropertiesFromCursor(cursor);
}
@Override
public long getId() {
return getIdHelper(ID);
};
// --- parcelable helpers
private static final Creator<StoreObject> CREATOR = new ModelCreator<StoreObject>(StoreObject.class);
@Override
protected Creator<? extends AbstractModel> getCreator() {
return CREATOR;
}
}

@ -17,6 +17,7 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.MetadataDao; import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.StoreObjectDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
/** /**
@ -97,6 +98,7 @@ public class AstridDependencyInjector implements AbstractDependencyInjector {
injectables.put("database", Database.class); injectables.put("database", Database.class);
injectables.put("taskDao", TaskDao.class); injectables.put("taskDao", TaskDao.class);
injectables.put("metadataDao", MetadataDao.class); injectables.put("metadataDao", MetadataDao.class);
injectables.put("storeObjectDao", StoreObjectDao.class);
// com.todoroo.astrid.service // com.todoroo.astrid.service
injectables.put("taskService", TaskService.class); injectables.put("taskService", TaskService.class);

Loading…
Cancel
Save