mirror of https://github.com/tasks/tasks
done reading/display-side of producteev-dashboard in the TaskDetailExposer
at least the reading/displaying part is ready for testing, the part where dashboard-infos are written into metadata-db and dataservice-cache is missing and should be done by tim, i think.pull/14/head
parent
9110b3f544
commit
d1ccce4e68
@ -1,79 +1,95 @@
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.producteev;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.astrid.adapter.TaskAdapter;
|
||||
import com.todoroo.astrid.api.AstridApiConstants;
|
||||
import com.todoroo.astrid.api.DetailExposer;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevNote;
|
||||
|
||||
/**
|
||||
* Exposes Task Details for Producteev:
|
||||
* - notes
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class ProducteevDetailExposer extends BroadcastReceiver implements DetailExposer{
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// if we aren't logged in, don't expose features
|
||||
if(!ProducteevUtilities.INSTANCE.isLoggedIn())
|
||||
return;
|
||||
|
||||
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
|
||||
if(taskId == -1)
|
||||
return;
|
||||
|
||||
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
|
||||
String taskDetail = getTaskDetails(context, taskId, extended);
|
||||
if(taskDetail == null)
|
||||
return;
|
||||
|
||||
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, ProducteevUtilities.IDENTIFIER);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
|
||||
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTaskDetails(Context context, long id, boolean extended) {
|
||||
|
||||
if(!extended)
|
||||
return null;
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
TodorooCursor<Metadata> notesCursor = ProducteevDataService.getInstance().getTaskNotesCursor(id);
|
||||
try {
|
||||
Metadata metadata = new Metadata();
|
||||
for(notesCursor.moveToFirst(); !notesCursor.isAfterLast(); notesCursor.moveToNext()) {
|
||||
metadata.readFromCursor(notesCursor);
|
||||
builder.append(metadata.getValue(ProducteevNote.MESSAGE)).append(TaskAdapter.DETAIL_SEPARATOR);
|
||||
}
|
||||
} finally {
|
||||
notesCursor.close();
|
||||
}
|
||||
|
||||
if(builder.length() == 0)
|
||||
return null;
|
||||
String result = builder.toString();
|
||||
return result.substring(0, result.length() - TaskAdapter.DETAIL_SEPARATOR.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginIdentifier() {
|
||||
return ProducteevUtilities.IDENTIFIER;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.producteev;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.astrid.adapter.TaskAdapter;
|
||||
import com.todoroo.astrid.api.AstridApiConstants;
|
||||
import com.todoroo.astrid.api.DetailExposer;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevNote;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevTask;
|
||||
|
||||
/**
|
||||
* Exposes Task Details for Producteev:
|
||||
* - notes
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class ProducteevDetailExposer extends BroadcastReceiver implements DetailExposer{
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// if we aren't logged in, don't expose features
|
||||
if(!ProducteevUtilities.INSTANCE.isLoggedIn())
|
||||
return;
|
||||
|
||||
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
|
||||
if(taskId == -1)
|
||||
return;
|
||||
|
||||
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
|
||||
String taskDetail = getTaskDetails(context, taskId, extended);
|
||||
if(taskDetail == null)
|
||||
return;
|
||||
|
||||
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, ProducteevUtilities.IDENTIFIER);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
|
||||
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTaskDetails(Context context, long id, boolean extended) {
|
||||
Metadata metadata = ProducteevDataService.getInstance().getTaskMetadata(id);
|
||||
if(metadata == null)
|
||||
return null;
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if(!extended) {
|
||||
long dashboardId = metadata.getValue(ProducteevTask.DASHBOARD_ID);
|
||||
String dashboardName = ProducteevDataService.getInstance().getDashboardName(dashboardId);
|
||||
// Prod dashboard is out of date. don't display Producteev stuff
|
||||
if(dashboardName == null)
|
||||
return null;
|
||||
|
||||
if(dashboardId > 0) {
|
||||
builder.append(context.getString(R.string.producteev_TLA_dashboard,
|
||||
dashboardId)).append(TaskAdapter.DETAIL_SEPARATOR);
|
||||
}
|
||||
|
||||
} else {
|
||||
TodorooCursor<Metadata> notesCursor = ProducteevDataService.getInstance().getTaskNotesCursor(id);
|
||||
try {
|
||||
for(notesCursor.moveToFirst(); !notesCursor.isAfterLast(); notesCursor.moveToNext()) {
|
||||
metadata.readFromCursor(notesCursor);
|
||||
builder.append(metadata.getValue(ProducteevNote.MESSAGE)).append(TaskAdapter.DETAIL_SEPARATOR);
|
||||
}
|
||||
} finally {
|
||||
notesCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
if(builder.length() == 0)
|
||||
return null;
|
||||
String result = builder.toString();
|
||||
return result.substring(0, result.length() - TaskAdapter.DETAIL_SEPARATOR.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginIdentifier() {
|
||||
return ProducteevUtilities.IDENTIFIER;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
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.StringProperty;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
|
||||
/**
|
||||
* Data Model which represents a dashboard in Producteev
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
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 */
|
||||
private static final ContentValues defaultValues = new ContentValues();
|
||||
|
||||
// static {
|
||||
// defaultValues.put(POSITION.name, 0);
|
||||
// defaultValues.put(ARCHIVED.name, 0);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public ContentValues getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
// --- data access boilerplate
|
||||
|
||||
public ProducteevDashboard() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ProducteevDashboard(TodorooCursor<ProducteevDashboard> cursor) {
|
||||
this();
|
||||
readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,196 +1,235 @@
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.andlib.sql.Criterion;
|
||||
import com.todoroo.andlib.sql.Join;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.astrid.dao.MetadataDao;
|
||||
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
import com.todoroo.astrid.producteev.ProducteevUtilities;
|
||||
import com.todoroo.astrid.rmilk.data.MilkNote;
|
||||
import com.todoroo.astrid.tags.TagService;
|
||||
|
||||
public final class ProducteevDataService {
|
||||
|
||||
// --- constants
|
||||
|
||||
/** Utility for joining tasks with metadata */
|
||||
public static final Join METADATA_JOIN = Join.left(Metadata.TABLE, Task.ID.eq(Metadata.TASK));
|
||||
|
||||
// --- singleton
|
||||
|
||||
private static ProducteevDataService instance = null;
|
||||
|
||||
public static synchronized ProducteevDataService getInstance() {
|
||||
if(instance == null)
|
||||
instance = new ProducteevDataService(ContextManager.getContext());
|
||||
return instance;
|
||||
}
|
||||
|
||||
// --- instance variables
|
||||
|
||||
protected final Context context;
|
||||
|
||||
@Autowired
|
||||
private TaskDao taskDao;
|
||||
|
||||
@Autowired
|
||||
private MetadataDao metadataDao;
|
||||
|
||||
private final ProducteevUtilities preferences = ProducteevUtilities.INSTANCE;
|
||||
|
||||
static final Random random = new Random();
|
||||
|
||||
private ProducteevDataService(Context context) {
|
||||
this.context = context;
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
}
|
||||
|
||||
// --- task and metadata methods
|
||||
|
||||
/**
|
||||
* Clears RTM metadata information. Used when user logs out of RTM
|
||||
*/
|
||||
public void clearMetadata() {
|
||||
metadataDao.deleteWhere(Metadata.KEY.eq(ProducteevTask.METADATA_KEY));
|
||||
metadataDao.deleteWhere(Metadata.KEY.eq(ProducteevNote.METADATA_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tasks that were created since last sync
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
public TodorooCursor<Task> getLocallyCreated(Property<?>[] properties) {
|
||||
return
|
||||
taskDao.query(Query.select(properties).join(ProducteevDataService.METADATA_JOIN).where(Criterion.and(
|
||||
Criterion.not(Task.ID.in(Query.select(Metadata.TASK).from(Metadata.TABLE).
|
||||
where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY), ProducteevTask.ID.gt(0))))),
|
||||
TaskCriteria.isActive())).groupBy(Task.ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tasks that were modified since last sync
|
||||
* @param properties
|
||||
* @return null if never sync'd
|
||||
*/
|
||||
public TodorooCursor<Task> getLocallyUpdated(Property<?>[] properties) {
|
||||
long lastSyncDate = preferences.getLastSyncDate();
|
||||
if(lastSyncDate == 0)
|
||||
return taskDao.query(Query.select(Task.ID).where(Criterion.none));
|
||||
return
|
||||
taskDao.query(Query.select(properties).join(ProducteevDataService.METADATA_JOIN).
|
||||
where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
Task.MODIFICATION_DATE.gt(lastSyncDate))).groupBy(Task.ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a local task with same remote id, updates this task's id
|
||||
* @param remoteTask
|
||||
*/
|
||||
public void findLocalMatch(ProducteevTaskContainer remoteTask) {
|
||||
if(remoteTask.task.getId() != Task.NO_ID)
|
||||
return;
|
||||
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.ID).
|
||||
join(ProducteevDataService.METADATA_JOIN).where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
ProducteevTask.ID.eq(remoteTask.pdvTask.getValue(ProducteevTask.ID)))));
|
||||
try {
|
||||
if(cursor.getCount() == 0)
|
||||
return;
|
||||
cursor.moveToFirst();
|
||||
remoteTask.task.setId(cursor.get(Task.ID));
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a task and its metadata
|
||||
* @param task
|
||||
*/
|
||||
public void saveTaskAndMetadata(ProducteevTaskContainer task) {
|
||||
taskDao.save(task.task, true);
|
||||
|
||||
metadataDao.deleteWhere(Criterion.and(MetadataCriteria.byTask(task.task.getId()),
|
||||
Criterion.or(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY),
|
||||
MetadataCriteria.withKey(TagService.KEY))));
|
||||
task.metadata.add(task.pdvTask);
|
||||
task.pdvTask.setValue(Metadata.KEY, ProducteevTask.METADATA_KEY);
|
||||
for(Metadata metadata : task.metadata) {
|
||||
metadata.setValue(Metadata.TASK, task.task.getId());
|
||||
metadataDao.createNew(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a task and its metadata
|
||||
* @param task
|
||||
* @return
|
||||
*/
|
||||
public ProducteevTaskContainer readTaskAndMetadata(TodorooCursor<Task> taskCursor) {
|
||||
Task task = new Task(taskCursor);
|
||||
|
||||
// read tags, notes, etc
|
||||
ArrayList<Metadata> metadata = new ArrayList<Metadata>();
|
||||
TodorooCursor<Metadata> metadataCursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
|
||||
where(Criterion.and(MetadataCriteria.byTask(task.getId()),
|
||||
Criterion.or(MetadataCriteria.withKey(TagService.KEY),
|
||||
MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
MetadataCriteria.withKey(MilkNote.METADATA_KEY),
|
||||
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY)))));
|
||||
try {
|
||||
for(metadataCursor.moveToFirst(); !metadataCursor.isAfterLast(); metadataCursor.moveToNext()) {
|
||||
metadata.add(new Metadata(metadataCursor));
|
||||
}
|
||||
} finally {
|
||||
metadataCursor.close();
|
||||
}
|
||||
|
||||
return new ProducteevTaskContainer(task, metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads metadata out of a task
|
||||
* @return null if no metadata found
|
||||
*/
|
||||
public Metadata getTaskMetadata(long taskId) {
|
||||
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(
|
||||
ProducteevTask.ID, ProducteevTask.DASHBOARD_ID).where(
|
||||
MetadataCriteria.byTaskAndwithKey(taskId, ProducteevTask.METADATA_KEY)));
|
||||
try {
|
||||
if(cursor.getCount() == 0)
|
||||
return null;
|
||||
cursor.moveToFirst();
|
||||
return new Metadata(cursor);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads task notes out of a task
|
||||
*/
|
||||
public TodorooCursor<Metadata> getTaskNotesCursor(long taskId) {
|
||||
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
|
||||
where(MetadataCriteria.byTaskAndwithKey(taskId, ProducteevNote.METADATA_KEY)));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.todoroo.andlib.data.GenericDao;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.andlib.sql.Criterion;
|
||||
import com.todoroo.andlib.sql.Join;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.andlib.utility.SoftHashMap;
|
||||
import com.todoroo.astrid.dao.MetadataDao;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
|
||||
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
import com.todoroo.astrid.producteev.ProducteevUtilities;
|
||||
import com.todoroo.astrid.rmilk.data.MilkNote;
|
||||
import com.todoroo.astrid.tags.TagService;
|
||||
|
||||
public final class ProducteevDataService {
|
||||
|
||||
// --- constants
|
||||
|
||||
/** Utility for joining tasks with metadata */
|
||||
public static final Join METADATA_JOIN = Join.left(Metadata.TABLE, Task.ID.eq(Metadata.TASK));
|
||||
|
||||
// --- singleton
|
||||
|
||||
private static ProducteevDataService instance = null;
|
||||
|
||||
public static synchronized ProducteevDataService getInstance() {
|
||||
if(instance == null)
|
||||
instance = new ProducteevDataService(ContextManager.getContext());
|
||||
return instance;
|
||||
}
|
||||
|
||||
// --- instance variables
|
||||
|
||||
protected final Context context;
|
||||
|
||||
private final ProducteevDatabase prodDatabase = new ProducteevDatabase();
|
||||
|
||||
private final GenericDao<ProducteevDashboard> prodDashboardDao;
|
||||
|
||||
@Autowired
|
||||
private TaskDao taskDao;
|
||||
|
||||
@Autowired
|
||||
private MetadataDao metadataDao;
|
||||
|
||||
private final ProducteevUtilities preferences = ProducteevUtilities.INSTANCE;
|
||||
|
||||
static final Random random = new Random();
|
||||
|
||||
private ProducteevDataService(Context context) {
|
||||
this.context = context;
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
prodDashboardDao = new GenericDao<ProducteevDashboard>(ProducteevDashboard.class, prodDatabase);
|
||||
}
|
||||
|
||||
// --- task and metadata methods
|
||||
|
||||
/**
|
||||
* Clears RTM metadata information. Used when user logs out of RTM
|
||||
*/
|
||||
public void clearMetadata() {
|
||||
metadataDao.deleteWhere(Metadata.KEY.eq(ProducteevTask.METADATA_KEY));
|
||||
metadataDao.deleteWhere(Metadata.KEY.eq(ProducteevNote.METADATA_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tasks that were created since last sync
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
public TodorooCursor<Task> getLocallyCreated(Property<?>[] properties) {
|
||||
return
|
||||
taskDao.query(Query.select(properties).join(ProducteevDataService.METADATA_JOIN).where(Criterion.and(
|
||||
Criterion.not(Task.ID.in(Query.select(Metadata.TASK).from(Metadata.TABLE).
|
||||
where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY), ProducteevTask.ID.gt(0))))),
|
||||
TaskCriteria.isActive())).groupBy(Task.ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tasks that were modified since last sync
|
||||
* @param properties
|
||||
* @return null if never sync'd
|
||||
*/
|
||||
public TodorooCursor<Task> getLocallyUpdated(Property<?>[] properties) {
|
||||
long lastSyncDate = preferences.getLastSyncDate();
|
||||
if(lastSyncDate == 0)
|
||||
return taskDao.query(Query.select(Task.ID).where(Criterion.none));
|
||||
return
|
||||
taskDao.query(Query.select(properties).join(ProducteevDataService.METADATA_JOIN).
|
||||
where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
Task.MODIFICATION_DATE.gt(lastSyncDate))).groupBy(Task.ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a local task with same remote id, updates this task's id
|
||||
* @param remoteTask
|
||||
*/
|
||||
public void findLocalMatch(ProducteevTaskContainer remoteTask) {
|
||||
if(remoteTask.task.getId() != Task.NO_ID)
|
||||
return;
|
||||
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.ID).
|
||||
join(ProducteevDataService.METADATA_JOIN).where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
ProducteevTask.ID.eq(remoteTask.pdvTask.getValue(ProducteevTask.ID)))));
|
||||
try {
|
||||
if(cursor.getCount() == 0)
|
||||
return;
|
||||
cursor.moveToFirst();
|
||||
remoteTask.task.setId(cursor.get(Task.ID));
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a task and its metadata
|
||||
* @param task
|
||||
*/
|
||||
public void saveTaskAndMetadata(ProducteevTaskContainer task) {
|
||||
taskDao.save(task.task, true);
|
||||
|
||||
metadataDao.deleteWhere(Criterion.and(MetadataCriteria.byTask(task.task.getId()),
|
||||
Criterion.or(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY),
|
||||
MetadataCriteria.withKey(TagService.KEY))));
|
||||
task.metadata.add(task.pdvTask);
|
||||
task.pdvTask.setValue(Metadata.KEY, ProducteevTask.METADATA_KEY);
|
||||
for(Metadata metadata : task.metadata) {
|
||||
metadata.setValue(Metadata.TASK, task.task.getId());
|
||||
metadataDao.createNew(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a task and its metadata
|
||||
* @param task
|
||||
* @return
|
||||
*/
|
||||
public ProducteevTaskContainer readTaskAndMetadata(TodorooCursor<Task> taskCursor) {
|
||||
Task task = new Task(taskCursor);
|
||||
|
||||
// read tags, notes, etc
|
||||
ArrayList<Metadata> metadata = new ArrayList<Metadata>();
|
||||
TodorooCursor<Metadata> metadataCursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
|
||||
where(Criterion.and(MetadataCriteria.byTask(task.getId()),
|
||||
Criterion.or(MetadataCriteria.withKey(TagService.KEY),
|
||||
MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
// FIXME: Constant from other plugin shouldnt be used
|
||||
MetadataCriteria.withKey(MilkNote.METADATA_KEY),
|
||||
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY)))));
|
||||
try {
|
||||
for(metadataCursor.moveToFirst(); !metadataCursor.isAfterLast(); metadataCursor.moveToNext()) {
|
||||
metadata.add(new Metadata(metadataCursor));
|
||||
}
|
||||
} finally {
|
||||
metadataCursor.close();
|
||||
}
|
||||
|
||||
return new ProducteevTaskContainer(task, metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads metadata out of a task
|
||||
* @return null if no metadata found
|
||||
*/
|
||||
public Metadata getTaskMetadata(long taskId) {
|
||||
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(
|
||||
ProducteevTask.ID, ProducteevTask.DASHBOARD_ID).where(
|
||||
MetadataCriteria.byTaskAndwithKey(taskId, ProducteevTask.METADATA_KEY)));
|
||||
try {
|
||||
if(cursor.getCount() == 0)
|
||||
return null;
|
||||
cursor.moveToFirst();
|
||||
return new Metadata(cursor);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads task notes out of a task
|
||||
*/
|
||||
public TodorooCursor<Metadata> getTaskNotesCursor(long taskId) {
|
||||
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
|
||||
where(MetadataCriteria.byTaskAndwithKey(taskId, ProducteevNote.METADATA_KEY)));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
// --- list methods
|
||||
|
||||
private final Map<Long, String> dashboardCache =
|
||||
Collections.synchronizedMap(new SoftHashMap<Long, String>());
|
||||
|
||||
/**
|
||||
* Get dashboard name by dashboard id
|
||||
* @param dashboardId
|
||||
* @return null if no dashboard by this id exists, otherwise dashboard name
|
||||
*/
|
||||
public String getDashboardName(long dashboardId) {
|
||||
if(dashboardCache.containsKey(dashboardId))
|
||||
return dashboardCache.get(dashboardId);
|
||||
|
||||
TodorooCursor<ProducteevDashboard> cursor = prodDashboardDao.query(Query.select(
|
||||
ProducteevDashboard.NAME).where(ProducteevDashboard.ID.eq(dashboardId)));
|
||||
try {
|
||||
if(cursor.getCount() == 0) {
|
||||
dashboardCache.put(dashboardId, null);
|
||||
return null;
|
||||
}
|
||||
cursor.moveToFirst();
|
||||
String name = cursor.get(ProducteevDashboard.NAME);
|
||||
dashboardCache.put(dashboardId, name);
|
||||
return name;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,24 @@
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
|
||||
/**
|
||||
* Metadata entries for a Remember The Milk Task
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class ProducteevTask {
|
||||
|
||||
/** metadata key */
|
||||
public static final String METADATA_KEY = "producteev"; //$NON-NLS-1$
|
||||
|
||||
/** task id in producteev */
|
||||
public static final LongProperty ID = new LongProperty(Metadata.TABLE,
|
||||
Metadata.VALUE1.name);
|
||||
|
||||
/** dashboard id */
|
||||
public static final LongProperty DASHBOARD_ID = new LongProperty(Metadata.TABLE,
|
||||
Metadata.VALUE2.name);
|
||||
|
||||
}
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
|
||||
/**
|
||||
* Metadata entries for a Producteev Task
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class ProducteevTask {
|
||||
|
||||
/** metadata key */
|
||||
public static final String METADATA_KEY = "producteev"; //$NON-NLS-1$
|
||||
|
||||
/** task id in producteev */
|
||||
public static final LongProperty ID = new LongProperty(Metadata.TABLE,
|
||||
Metadata.VALUE1.name);
|
||||
|
||||
/** dashboard id */
|
||||
public static final LongProperty DASHBOARD_ID = new LongProperty(Metadata.TABLE,
|
||||
Metadata.VALUE2.name);
|
||||
|
||||
}
|
||||
|
@ -1,25 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- ==================================================== Preferences == -->
|
||||
|
||||
<!-- Preferences Title: Producteev -->
|
||||
<string name="producteev_PPr_header">Producteev</string>
|
||||
|
||||
<!-- ================================================ Synchronization == -->
|
||||
|
||||
<!-- title for notification tray when synchronizing -->
|
||||
<string name="producteev_notification_title">Astrid: Producteev</string>
|
||||
|
||||
<!-- Error msg when io exception -->
|
||||
<string name="producteev_ioerror">Connection Error! Check your Internet connection.</string>
|
||||
|
||||
<!-- Prod Login email not specified-->
|
||||
<string name="producteev_MLA_email_empty">E-Mail was not specified!</string>
|
||||
|
||||
<!-- Prod Login password not specified-->
|
||||
<string name="producteev_MLA_password_empty">Password was not specified!</string>
|
||||
|
||||
</resources>
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- ====================== Plugin Boilerplate ========================= -->
|
||||
|
||||
<!-- task detail showing Producteev dashboard information -->
|
||||
<string name="producteev_TLA_dashboard">Producteev dashboard: %s</string>
|
||||
|
||||
<!-- ==================================================== Preferences == -->
|
||||
|
||||
<!-- Preferences Title: Producteev -->
|
||||
<string name="producteev_PPr_header">Producteev</string>
|
||||
|
||||
<!-- ================================================ Synchronization == -->
|
||||
|
||||
<!-- title for notification tray when synchronizing -->
|
||||
<string name="producteev_notification_title">Astrid: Producteev</string>
|
||||
|
||||
<!-- Error msg when io exception -->
|
||||
<string name="producteev_ioerror">Connection Error! Check your Internet connection.</string>
|
||||
|
||||
<!-- Prod Login email not specified-->
|
||||
<string name="producteev_MLA_email_empty">E-Mail was not specified!</string>
|
||||
|
||||
<!-- Prod Login password not specified-->
|
||||
<string name="producteev_MLA_password_empty">Password was not specified!</string>
|
||||
|
||||
</resources>
|
||||
|
||||
|
Loading…
Reference in New Issue