mirror of https://github.com/tasks/tasks
Producteev Shared Desktop initial work. what's here: synchronizing multiple workspaces, displaying this information, displaying task responsiblity info, switching things into multiple workspaces
parent
8b4b79db88
commit
aa2fe7db1b
@ -1,95 +1,118 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 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.model.StoreObject;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevDashboard;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevNote;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevTask;
|
||||
import com.todoroo.astrid.utility.Preferences;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
long responsibleId = metadata.getValue(ProducteevTask.RESPONSIBLE_ID);
|
||||
|
||||
// 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,
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,86 +1,30 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.andlib.data.Property.StringProperty;
|
||||
import com.todoroo.astrid.model.StoreObject;
|
||||
|
||||
/**
|
||||
* {@link StoreObject} entries for a Producteev Dashboard
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class ProducteevDashboard {
|
||||
|
||||
/** type*/
|
||||
public static final String TYPE = "pdv-dash"; //$NON-NLS-1$
|
||||
|
||||
/** dashboard id in producteev */
|
||||
public static final LongProperty REMOTE_ID = new LongProperty(StoreObject.TABLE,
|
||||
StoreObject.ITEM.name);
|
||||
|
||||
/** dashboard name */
|
||||
public static final StringProperty NAME = new StringProperty(StoreObject.TABLE,
|
||||
StoreObject.VALUE1.name);
|
||||
|
||||
/** users (list in the format "id_user,name;id_user,name;") */
|
||||
public static final StringProperty USERS = new StringProperty(StoreObject.TABLE,
|
||||
StoreObject.VALUE2.name);
|
||||
|
||||
}
|
||||
|
||||
@ -1,235 +1,284 @@
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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 org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
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.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.model.Metadata;
|
||||
import com.todoroo.astrid.model.StoreObject;
|
||||
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;
|
||||
|
||||
@Autowired
|
||||
private StoreObjectDao storeObjectDao;
|
||||
|
||||
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), // to sync rmilk notes
|
||||
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;
|
||||
}
|
||||
|
||||
// --- dashboard methods
|
||||
|
||||
private StoreObject[] dashboards = null;
|
||||
|
||||
/**
|
||||
* Reads dashboards
|
||||
*/
|
||||
private void readDashboards() {
|
||||
if(dashboards != null)
|
||||
return;
|
||||
|
||||
TodorooCursor<StoreObject> cursor = storeObjectDao.query(Query.select(StoreObject.PROPERTIES).
|
||||
where(StoreObjectCriteria.byType(ProducteevDashboard.TYPE)));
|
||||
try {
|
||||
dashboards = new StoreObject[cursor.getCount()];
|
||||
for(int i = 0; i < dashboards.length; i++) {
|
||||
cursor.moveToNext();
|
||||
StoreObject dashboard = new StoreObject(cursor);
|
||||
dashboards[i] = dashboard;
|
||||
}
|
||||
} finally {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,32 @@
|
||||
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);
|
||||
|
||||
}
|
||||
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);
|
||||
|
||||
/** 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);
|
||||
|
||||
}
|
||||
|
||||
@ -1,88 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:background="@android:drawable/list_selector_background"
|
||||
android:paddingTop="4dip"
|
||||
android:paddingBottom="4dip"
|
||||
android:paddingLeft="4dip"
|
||||
android:paddingRight="4dip">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5dip"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- icon -->
|
||||
<ImageView android:id="@+id/icon"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:gravity="center"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<!-- free -->
|
||||
<TextView android:id="@+id/free"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textSize="10sp"
|
||||
android:textColor="#00ff00"
|
||||
android:text="@string/AOA_free" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="100"
|
||||
android:paddingLeft="8dip"
|
||||
android:paddingRight="3dip"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- add-on name -->
|
||||
<TextView android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:singleLine="true"
|
||||
style="@style/TextAppearance.TAd_ItemTitle"/>
|
||||
|
||||
<!-- description -->
|
||||
<TextView android:id="@+id/description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/title"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:singleLine="false"
|
||||
android:textSize="11sp"
|
||||
style="@style/TextAppearance.TAd_ItemDetails"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- buttons -->
|
||||
|
||||
<ImageButton android:id="@+id/button_web"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ImageButton android:id="@+id/button_market"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ImageView android:id="@+id/check"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="center"
|
||||
android:layout_gravity="center"
|
||||
android:src="@android:drawable/checkbox_on_background"/>
|
||||
|
||||
</LinearLayout>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:background="@android:drawable/list_selector_background"
|
||||
android:paddingTop="4dip"
|
||||
android:paddingBottom="4dip"
|
||||
android:paddingLeft="4dip"
|
||||
android:paddingRight="4dip">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5dip"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- icon -->
|
||||
<ImageView android:id="@+id/icon"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:gravity="center"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<!-- free -->
|
||||
<TextView android:id="@+id/free"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textSize="10sp"
|
||||
android:textColor="#00ff00"
|
||||
android:text="@string/AOA_free" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="100"
|
||||
android:paddingLeft="8dip"
|
||||
android:paddingRight="3dip"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- add-on name -->
|
||||
<TextView android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:singleLine="true"
|
||||
style="@style/TextAppearance.TAd_ItemTitle"/>
|
||||
|
||||
<!-- description -->
|
||||
<TextView android:id="@+id/description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/title"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:singleLine="false"
|
||||
android:textSize="11sp"
|
||||
style="@style/TextAppearance.TAd_ItemDetails"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- buttons -->
|
||||
|
||||
<ImageButton android:id="@+id/button_web"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ImageButton android:id="@+id/button_market"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ImageView android:id="@+id/check"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="center"
|
||||
android:layout_gravity="center"
|
||||
android:src="@android:drawable/checkbox_on_background"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -1,84 +1,87 @@
|
||||
<?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">Workspace: %s</string>
|
||||
|
||||
<!-- ==================================================== Preferences == -->
|
||||
|
||||
<!-- Preferences Title: Producteev -->
|
||||
<string name="producteev_PPr_header">Producteev</string>
|
||||
|
||||
<!-- dashboard title for producteev default dashboard -->
|
||||
<string name="producteev_default_dashboard">Default Workspace</string>
|
||||
|
||||
<!-- dashboard title for tasks that are not synchronized -->
|
||||
<string name="producteev_no_dashboard">Do Not Synchronize</string>
|
||||
|
||||
<!-- preference title for default dashboard -->
|
||||
<string name="producteev_PPr_defaultdash_title">Default Workspace</string>
|
||||
|
||||
<!-- preference description for default dashboard (%s -> setting) -->
|
||||
<string name="producteev_PPr_defaultdash_summary">New tasks will be added to: %s</string>
|
||||
|
||||
<!-- preference description for default dashboard (when set to 'not synchronized') -->
|
||||
<string name="producteev_PPr_defaultdash_summary_none">New tasks will not be synchronized by default</string>
|
||||
|
||||
<!-- ================================================= Login Activity == -->
|
||||
|
||||
<!-- Activity Title: Producteev Login -->
|
||||
<string name="producteev_PLA_title">Log In to Producteev</string>
|
||||
|
||||
<!-- Instructions: Producteev login -->
|
||||
<string name="producteev_PLA_body">Sign in with your existing
|
||||
Producteev account, or create a new account!</string>
|
||||
|
||||
<!-- Producteev Terms Link -->
|
||||
<string name="producteev_PLA_terms">Terms & Conditions</string>
|
||||
|
||||
<!-- Sign In Button -->
|
||||
<string name="producteev_PLA_signIn">Sign In</string>
|
||||
|
||||
<!-- Create New User Button -->
|
||||
<string name="producteev_PLA_createNew">Create New User</string>
|
||||
|
||||
<!-- E-mail Address Label -->
|
||||
<string name="producteev_PLA_email">E-mail</string>
|
||||
|
||||
<!-- Password Label -->
|
||||
<string name="producteev_PLA_password">Password</string>
|
||||
|
||||
<!-- Confirm Password Label -->
|
||||
<string name="producteev_PLA_confirmPassword">Confirm Password</string>
|
||||
|
||||
<!-- First Name Label -->
|
||||
<string name="producteev_PLA_firstName">First Name</string>
|
||||
|
||||
<!-- Last Name Label -->
|
||||
<string name="producteev_PLA_lastName">Last Name</string>
|
||||
|
||||
<!-- Error Message when fields aren't filled out -->
|
||||
<string name="producteev_PLA_errorEmpty">Error: fill out all fields!</string>
|
||||
|
||||
<!-- Error Message when passwords don't match -->
|
||||
<string name="producteev_PLA_errorMatch">Error: passwords don\'t match!</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 (%s => workspace name) -->
|
||||
<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 Title: Producteev -->
|
||||
<string name="producteev_PPr_header">Producteev</string>
|
||||
|
||||
<!-- dashboard title for producteev default dashboard -->
|
||||
<string name="producteev_default_dashboard">Default Workspace</string>
|
||||
|
||||
<!-- dashboard title for tasks that are not synchronized -->
|
||||
<string name="producteev_no_dashboard">Do Not Synchronize</string>
|
||||
|
||||
<!-- preference title for default dashboard -->
|
||||
<string name="producteev_PPr_defaultdash_title">Default Workspace</string>
|
||||
|
||||
<!-- preference description for default dashboard (%s -> setting) -->
|
||||
<string name="producteev_PPr_defaultdash_summary">New tasks will be added to: %s</string>
|
||||
|
||||
<!-- preference description for default dashboard (when set to 'not synchronized') -->
|
||||
<string name="producteev_PPr_defaultdash_summary_none">New tasks will not be synchronized by default</string>
|
||||
|
||||
<!-- ================================================= Login Activity == -->
|
||||
|
||||
<!-- Activity Title: Producteev Login -->
|
||||
<string name="producteev_PLA_title">Log In to Producteev</string>
|
||||
|
||||
<!-- Instructions: Producteev login -->
|
||||
<string name="producteev_PLA_body">Sign in with your existing
|
||||
Producteev account, or create a new account!</string>
|
||||
|
||||
<!-- Producteev Terms Link -->
|
||||
<string name="producteev_PLA_terms">Terms & Conditions</string>
|
||||
|
||||
<!-- Sign In Button -->
|
||||
<string name="producteev_PLA_signIn">Sign In</string>
|
||||
|
||||
<!-- Create New User Button -->
|
||||
<string name="producteev_PLA_createNew">Create New User</string>
|
||||
|
||||
<!-- E-mail Address Label -->
|
||||
<string name="producteev_PLA_email">E-mail</string>
|
||||
|
||||
<!-- Password Label -->
|
||||
<string name="producteev_PLA_password">Password</string>
|
||||
|
||||
<!-- Confirm Password Label -->
|
||||
<string name="producteev_PLA_confirmPassword">Confirm Password</string>
|
||||
|
||||
<!-- First Name Label -->
|
||||
<string name="producteev_PLA_firstName">First Name</string>
|
||||
|
||||
<!-- Last Name Label -->
|
||||
<string name="producteev_PLA_lastName">Last Name</string>
|
||||
|
||||
<!-- Error Message when fields aren't filled out -->
|
||||
<string name="producteev_PLA_errorEmpty">Error: fill out all fields!</string>
|
||||
|
||||
<!-- Error Message when passwords don't match -->
|
||||
<string name="producteev_PLA_errorMatch">Error: passwords don\'t match!</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>
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue