Killed extended details. Created NoteMetadata for displaying notes created from plugins.

- migrated PDV and RTM notes to new format
pull/14/head
Tim Su 15 years ago
parent b99850134e
commit f161294848

@ -36,4 +36,8 @@ public final class Functions {
return new Field("MAX(" + field.toString() + ")");
}
public static Field count() {
return new Field("COUNT(1)");
}
}

@ -60,11 +60,6 @@ public class AstridApiConstants {
*/
public static final String EXTRAS_ADDON = "addon";
/**
* Extras name for whether task detail request is extended
*/
public static final String EXTRAS_EXTENDED = "extended";
/**
* Extras name for old task due date
*/

@ -9,10 +9,10 @@ import android.net.Uri;
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.andlib.data.Table;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.astrid.api.AstridApiConstants;
/**
@ -67,6 +67,10 @@ public class Metadata extends AbstractModel {
public static final StringProperty VALUE5 = new StringProperty(
TABLE, "value5");
/** Unixtime Metadata was created */
public static final LongProperty CREATION_DATE = new LongProperty(
TABLE, "created");
/** List of all properties for this model */
public static final Property<?>[] PROPERTIES = generateProperties(Metadata.class);

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.timsu.astrid"
android:versionName="3.7.0-prerelease"
android:versionCode="171">
android:versionName="3.7.0"
android:versionCode="172">
<!-- widgets, alarms, and services will break if Astrid is installed on SD card -->
<!-- android:installLocation="internalOnly"> -->
@ -128,7 +128,8 @@
android:windowSoftInputMode="stateHidden"
android:theme="@style/Theme" />
<!-- Activity for preferences -->
<activity android:name="com.todoroo.astrid.activity.EditPreferences" />
<activity android:name="com.todoroo.astrid.activity.EditPreferences"
android:theme="@android:style/Theme" />
<!-- Activity that configures widget -->
<activity android:name="com.todoroo.astrid.widget.TasksWidget$ConfigActivity"
android:theme="@style/Theme">
@ -197,7 +198,8 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<activity android:name="com.todoroo.astrid.core.DefaultsPreferences"
<activity android:name="com.todoroo.astrid.core.DefaultsPreferences"
android:theme="@android:style/Theme"
android:label="@string/EPr_defaults_header">
<intent-filter>
<action android:name="com.todoroo.astrid.SETTINGS" />
@ -255,6 +257,7 @@
</intent-filter>
</receiver>
<activity android:name="com.todoroo.astrid.gtasks.GtasksPreferences"
android:theme="@android:style/Theme"
android:label="@string/gtasks_GPr_header">
<meta-data android:name="category"
android:resource="@string/SyP_label" />
@ -347,7 +350,8 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="com.todoroo.astrid.backup.BackupPreferences"
<activity android:name="com.todoroo.astrid.backup.BackupPreferences"
android:theme="@android:style/Theme"
android:label="@string/backup_BPr_header">
<intent-filter>
<action android:name="com.todoroo.astrid.SETTINGS" />
@ -398,7 +402,7 @@
</receiver>
<!-- notes -->
<receiver android:name="com.todoroo.astrid.notes.NoteDetailExposer">
<receiver android:name="com.todoroo.astrid.notes.NotesDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
@ -408,7 +412,8 @@
android:theme="@style/Theme.Dialog" />
<!-- reminders -->
<activity android:name="com.todoroo.astrid.reminders.ReminderPreferences"
<activity android:name="com.todoroo.astrid.reminders.ReminderPreferences"
android:theme="@android:style/Theme"
android:label="@string/rmd_EPr_alerts_header">
<intent-filter>
<action android:name="com.todoroo.astrid.SETTINGS" />
@ -444,6 +449,7 @@
</intent-filter>
</receiver>
<activity android:name="com.todoroo.astrid.producteev.ProducteevPreferences"
android:theme="@android:style/Theme"
android:label="@string/producteev_PPr_header">
<meta-data android:name="category"
android:resource="@string/SyP_label" />
@ -494,6 +500,7 @@
</receiver>
<activity android:name="org.weloveastrid.rmilk.MilkLoginActivity" />
<activity android:name="org.weloveastrid.rmilk.MilkPreferences"
android:theme="@android:style/Theme"
android:icon="@drawable/icon"
android:label="@string/rmilk_MPr_header">
<meta-data android:name="category"
@ -521,6 +528,7 @@
</intent-filter>
</receiver>
<!-- other task actions -->
<receiver android:name="com.todoroo.astrid.core.LinkActionExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_ACTIONS" />

@ -32,8 +32,7 @@ public class AlarmDetailExposer extends BroadcastReceiver {
if(taskId == -1)
return;
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
String taskDetail = getTaskDetails(context, taskId, extended);
String taskDetail = getTaskDetails(context, taskId);
if(taskDetail == null)
return;
@ -41,15 +40,11 @@ public class AlarmDetailExposer extends BroadcastReceiver {
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, AlarmService.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
public String getTaskDetails(Context context, long id, boolean extended) {
if(extended)
return null;
public String getTaskDetails(Context context, long id) {
TodorooCursor<Metadata> cursor = AlarmService.getInstance().getAlarms(id);
long nextTime = -1;
try {

@ -86,6 +86,9 @@ public class LinkActionExposer extends BroadcastReceiver {
Drawable icon = resolveInfoList.get(0).loadIcon(pm);
Bitmap bitmap = ((BitmapDrawable)icon).getBitmap();
if(text.length() > 15)
text = text.substring(0, 12) + "..."; //$NON-NLS-1$
TaskAction action = new TaskAction(text,
PendingIntent.getActivity(context, 0, actionIntent, 0), bitmap);

@ -50,23 +50,18 @@ public class GtasksDetailExposer extends BroadcastReceiver {
if(taskId == -1)
return;
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
String taskDetail = getTaskDetails(taskId, extended);
String taskDetail = getTaskDetails(taskId);
if(taskDetail == null)
return;
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, GtasksPreferenceService.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);
}
public String getTaskDetails(long id, boolean extended) {
if(extended)
return null;
public String getTaskDetails(long id) {
Metadata metadata = gtasksMetadataService.getTaskMetadata(id);
if(metadata == null)
return null;

@ -1,51 +0,0 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.notes;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.data.Task;
/**
* Exposes Task Detail for notes
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class NoteDetailExposer extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// get tags associated with this task
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
if(taskId == -1)
return;
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
String taskDetail = getTaskDetails(taskId, extended);
if(taskDetail == null)
return;
// transmit
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, NotesPlugin.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
public String getTaskDetails(long id, boolean extended) {
Task task = PluginServices.getTaskService().fetchById(id, Task.NOTES);
if(task == null)
return null;
return null;
}
}

@ -0,0 +1,32 @@
package com.todoroo.astrid.notes;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.astrid.data.Metadata;
/**
* Metadata entry for a note displayed by the Notes plugin.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class NoteMetadata {
/** metadata key */
public static final String METADATA_KEY = "note"; //$NON-NLS-1$
/** note body */
public static final StringProperty BODY = Metadata.VALUE1;
/** note description (title, date, from, etc) */
public static final StringProperty TITLE = Metadata.VALUE2;
/** note thumbnail URL */
public static final StringProperty THUMBNAIL = Metadata.VALUE3;
/** note external provider (use for your own purposes) */
public static final StringProperty EXT_PROVIDER = Metadata.VALUE4;
/** note external id (use for your own purposes) */
public static final StringProperty EXT_ID = Metadata.VALUE5;
}

@ -1,7 +1,9 @@
package com.todoroo.astrid.notes;
import android.app.Activity;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.util.Linkify;
import android.view.View;
import android.view.View.OnClickListener;
@ -12,6 +14,11 @@ import android.widget.ScrollView;
import android.widget.TextView;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
public class NoteViewingActivity extends Activity {
@ -33,13 +40,42 @@ public class NoteViewingActivity extends Activity {
setTitle(task.getValue(Task.TITLE));
ScrollView scrollView = new ScrollView(this);
LinearLayout scrollViewBody = new LinearLayout(this);
scrollViewBody.setOrientation(LinearLayout.VERTICAL);
scrollView.addView(scrollViewBody);
body.addView(scrollView);
TextView linkifiedTextView = new TextView(this);
linkifiedTextView.setText(task.getValue(Task.NOTES) + "\n"); //$NON-NLS-1$
Linkify.addLinks(linkifiedTextView, Linkify.ALL);
if(!TextUtils.isEmpty(task.getValue(Task.NOTES))) {
TextView note = new TextView(this);
note.setText(task.getValue(Task.NOTES));
Linkify.addLinks(note, Linkify.ALL);
note.setPadding(0, 0, 0, 10);
scrollViewBody.addView(note);
}
scrollView.addView(linkifiedTextView);
body.addView(scrollView);
TodorooCursor<Metadata> cursor = PluginServices.getMetadataService().query(
Query.select(Metadata.PROPERTIES).where(
MetadataCriteria.byTaskAndwithKey(task.getId(),
NoteMetadata.METADATA_KEY)));
Metadata metadata = new Metadata();
try {
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
metadata.readFromCursor(cursor);
TextView title = new TextView(this);
title.setTypeface(Typeface.DEFAULT_BOLD);
title.setText(metadata.getValue(NoteMetadata.TITLE));
scrollViewBody.addView(title);
TextView note = new TextView(this);
note.setText(metadata.getValue(NoteMetadata.BODY));
Linkify.addLinks(note, Linkify.ALL);
note.setPadding(0, 0, 0, 10);
scrollViewBody.addView(note);
}
} finally {
cursor.close();
}
Button ok = new Button(this);
ok.setText(android.R.string.ok);

@ -5,7 +5,6 @@ package com.todoroo.astrid.notes;
import android.app.PendingIntent;
import android.content.Intent;
import android.text.TextUtils;
import android.widget.RemoteViews;
import com.timsu.astrid.R;
@ -24,7 +23,7 @@ public class NotesDecorationExposer implements TaskDecorationExposer {
@Override
public TaskDecoration expose(Task task) {
if(task == null || TextUtils.isEmpty(task.getValue(Task.NOTES)))
if(task == null || !NotesPlugin.hasNotes(task))
return null;
TaskDecoration decoration;

@ -0,0 +1,88 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.notes;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
/**
* Exposes Task Detail for notes
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class NotesDetailExposer extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// get tags associated with this task
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
if(taskId == -1)
return;
String taskDetail = getTaskDetails(taskId);
if(taskDetail == null)
return;
// transmit
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, NotesPlugin.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
@SuppressWarnings("nls")
public String getTaskDetails(long id) {
if(!Preferences.getBoolean(R.string.p_showNotes, false))
return null;
Task task = PluginServices.getTaskService().fetchById(id, Task.NOTES);
if(task == null)
return null;
StringBuilder notesBuilder = new StringBuilder();
String notes = task.getValue(Task.NOTES);
if(!TextUtils.isEmpty(notes))
notesBuilder.append(notesBuilder);
TodorooCursor<Metadata> cursor = PluginServices.getMetadataService().query(
Query.select(Metadata.PROPERTIES).where(
MetadataCriteria.byTaskAndwithKey(task.getId(),
NoteMetadata.METADATA_KEY)));
Metadata metadata = new Metadata();
try {
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
metadata.readFromCursor(cursor);
if(notesBuilder.length() > 0)
notesBuilder.append("\n");
notesBuilder.append("<b>").append(metadata.getValue(NoteMetadata.TITLE)).append("</b>\n");
notesBuilder.append(metadata.getValue(NoteMetadata.BODY));
}
} finally {
cursor.close();
}
if(notesBuilder.length() == 0)
return null;
return "<img src='silk_note'/> " + notesBuilder; //$NON-NLS-1$
}
}

@ -3,9 +3,12 @@ package com.todoroo.astrid.notes;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import com.todoroo.astrid.api.Addon;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.data.Task;
public class NotesPlugin extends BroadcastReceiver {
@ -22,4 +25,20 @@ public class NotesPlugin extends BroadcastReceiver {
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
/**
* Does this task have notes to display?
*
* @param task
* @return
*/
public static boolean hasNotes(Task task) {
if(task.containsNonNullValue(Task.NOTES) && !TextUtils.isEmpty(task.getValue(Task.NOTES)))
return true;
if(PluginServices.getMetadataService().hasMetadata(task.getId(), NoteMetadata.METADATA_KEY))
return true;
return false;
}
}

@ -11,7 +11,6 @@ import android.content.Context;
import android.content.Intent;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.adapter.TaskAdapter;
@ -20,7 +19,6 @@ import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.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;
/**
@ -39,10 +37,9 @@ public class ProducteevDetailExposer extends BroadcastReceiver {
if(taskId == -1)
return;
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
String taskDetail;
try {
taskDetail = getTaskDetails(context, taskId, extended);
taskDetail = getTaskDetails(context, taskId);
} catch (Exception e) {
return;
}
@ -52,141 +49,125 @@ public class ProducteevDetailExposer extends BroadcastReceiver {
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);
}
@SuppressWarnings("nls")
public String getTaskDetails(Context context, long id, boolean extended) {
public String getTaskDetails(Context context, long id) {
Metadata metadata = ProducteevDataService.getInstance().getTaskMetadata(id);
if(metadata == null)
return null;
StringBuilder builder = new StringBuilder();
// we always expose pdv notes. but, if we aren't logged in, don't expose other details
if(!extended && !ProducteevUtilities.INSTANCE.isLoggedIn())
if(!ProducteevUtilities.INSTANCE.isLoggedIn())
return null;
if(!extended) {
long dashboardId = -1;
if(metadata.containsNonNullValue(ProducteevTask.DASHBOARD_ID))
dashboardId = metadata.getValue(ProducteevTask.DASHBOARD_ID);
long responsibleId = -1;
if(metadata.containsNonNullValue(ProducteevTask.RESPONSIBLE_ID))
responsibleId = metadata.getValue(ProducteevTask.RESPONSIBLE_ID);
long creatorId = -1;
if(metadata.containsNonNullValue(ProducteevTask.CREATOR_ID))
creatorId = metadata.getValue(ProducteevTask.CREATOR_ID);
String repeatSetting = null;
if(metadata.containsNonNullValue(ProducteevTask.REPEATING_SETTING))
repeatSetting = metadata.getValue(ProducteevTask.REPEATING_SETTING);
// display dashboard if not "no sync" or "default"
StoreObject ownerDashboard = null;
for(StoreObject dashboard : ProducteevDataService.getInstance().getDashboards()) {
if(dashboard == null || !dashboard.containsNonNullValue(ProducteevDashboard.REMOTE_ID))
continue;
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("<img src='silk_folder'/> ").append(dashboardName).append(TaskAdapter.DETAIL_SEPARATOR); //$NON-NLS-1$
}
// display responsible user if not current one
if(responsibleId > 0 && ownerDashboard != null && responsibleId !=
Preferences.getLong(ProducteevUtilities.PREF_USER_ID, 0L)) {
String user = getUserFromDashboard(ownerDashboard, responsibleId);
if(user != null)
builder.append("<img src='silk_user_gray'/> ").append(user).append(TaskAdapter.DETAIL_SEPARATOR); //$NON-NLS-1$
long dashboardId = -1;
if(metadata.containsNonNullValue(ProducteevTask.DASHBOARD_ID))
dashboardId = metadata.getValue(ProducteevTask.DASHBOARD_ID);
long responsibleId = -1;
if(metadata.containsNonNullValue(ProducteevTask.RESPONSIBLE_ID))
responsibleId = metadata.getValue(ProducteevTask.RESPONSIBLE_ID);
long creatorId = -1;
if(metadata.containsNonNullValue(ProducteevTask.CREATOR_ID))
creatorId = metadata.getValue(ProducteevTask.CREATOR_ID);
String repeatSetting = null;
if(metadata.containsNonNullValue(ProducteevTask.REPEATING_SETTING))
repeatSetting = metadata.getValue(ProducteevTask.REPEATING_SETTING);
// display dashboard if not "no sync" or "default"
StoreObject ownerDashboard = null;
for(StoreObject dashboard : ProducteevDataService.getInstance().getDashboards()) {
if(dashboard == null || !dashboard.containsNonNullValue(ProducteevDashboard.REMOTE_ID))
continue;
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("<img src='silk_folder'/> ").append(dashboardName).append(TaskAdapter.DETAIL_SEPARATOR); //$NON-NLS-1$
}
// display creator user if not the current one
if(creatorId > 0 && ownerDashboard != null && creatorId !=
Preferences.getLong(ProducteevUtilities.PREF_USER_ID, 0L)) {
String user = getUserFromDashboard(ownerDashboard, creatorId);
if(user != null)
builder.append("<img src='silk_user_orange'/> ").append( //$NON-NLS-1$
context.getString(R.string.producteev_PDE_task_from, user)).
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 user = getUserFromDashboard(ownerDashboard, responsibleId);
if(user != null)
builder.append("<img src='silk_user_gray'/> ").append(user).append(TaskAdapter.DETAIL_SEPARATOR); //$NON-NLS-1$
}
// display repeating task information
if (repeatSetting != null && repeatSetting.length() > 0) {
String interval = null;
String[] pdvRepeating = repeatSetting.split(",");
int pdvRepeatingValue = 0;
String pdvRepeatingDay = null;
try {
pdvRepeatingValue = Integer.parseInt(pdvRepeating[0]);
} catch (Exception e) {
pdvRepeatingDay = pdvRepeating[0];
pdvRepeatingValue = 1;
}
String pdvRepeatingInterval = pdvRepeating[1];
if (pdvRepeatingInterval.startsWith("day")) {
interval = context.getResources().getQuantityString(R.plurals.DUt_days, pdvRepeatingValue,
pdvRepeatingValue);
} else if (pdvRepeatingInterval.startsWith("weekday")) {
interval = context.getResources().getQuantityString(R.plurals.DUt_weekdays, pdvRepeatingValue,
pdvRepeatingValue);
} else if (pdvRepeatingInterval.startsWith("week")) {
interval = context.getResources().getQuantityString(R.plurals.DUt_weeks, pdvRepeatingValue,
pdvRepeatingValue);
} else if (pdvRepeatingInterval.startsWith("month")) {
interval = context.getResources().getQuantityString(R.plurals.DUt_months, pdvRepeatingValue,
pdvRepeatingValue);
} else if (pdvRepeatingInterval.startsWith("year")) {
interval = context.getResources().getQuantityString(R.plurals.DUt_years, pdvRepeatingValue,
pdvRepeatingValue);
}
interval = "<b>" + interval + "</b>"; //$NON-NLS-1$//$NON-NLS-2$
if (pdvRepeatingDay != null) {
DateFormatSymbols dfs = new DateFormatSymbols();
String[] weekdays = dfs.getShortWeekdays();
if (pdvRepeatingDay.equals("monday")) {
pdvRepeatingDay = weekdays[Calendar.MONDAY];
} else if (pdvRepeatingDay.equals("tuesday")) {
pdvRepeatingDay = weekdays[Calendar.TUESDAY];
} else if (pdvRepeatingDay.equals("wednesday")) {
pdvRepeatingDay = weekdays[Calendar.WEDNESDAY];
} else if (pdvRepeatingDay.equals("thursday")) {
pdvRepeatingDay = weekdays[Calendar.THURSDAY];
} else if (pdvRepeatingDay.equals("friday")) {
pdvRepeatingDay = weekdays[Calendar.FRIDAY];
} else if (pdvRepeatingDay.equals("saturday")) {
pdvRepeatingDay = weekdays[Calendar.SATURDAY];
} else if (pdvRepeatingDay.equals("sunday")) {
pdvRepeatingDay = weekdays[Calendar.SUNDAY];
}
interval = context.getResources().getString(R.string.repeat_detail_byday).replace("$I", //$NON-NLS-1$
interval).replace("$D", pdvRepeatingDay); //$NON-NLS-1$
}
String detail = context.getString(R.string.repeat_detail_duedate, interval);
builder.append("<img src='repeating_deadline'/> ").append(detail). //$NON-NLS-1$
// display creator user if not the current one
if(creatorId > 0 && ownerDashboard != null && creatorId !=
Preferences.getLong(ProducteevUtilities.PREF_USER_ID, 0L)) {
String user = getUserFromDashboard(ownerDashboard, creatorId);
if(user != null)
builder.append("<img src='silk_user_orange'/> ").append( //$NON-NLS-1$
context.getString(R.string.producteev_PDE_task_from, user)).
append(TaskAdapter.DETAIL_SEPARATOR);
}
}
if(Preferences.getBoolean(R.string.p_showNotes, false) == !extended) {
TodorooCursor<Metadata> notesCursor = ProducteevDataService.getInstance().getTaskNotesCursor(id);
// display repeating task information
if (repeatSetting != null && repeatSetting.length() > 0) {
String interval = null;
String[] pdvRepeating = repeatSetting.split(",");
int pdvRepeatingValue = 0;
String pdvRepeatingDay = null;
try {
for(notesCursor.moveToFirst(); !notesCursor.isAfterLast(); notesCursor.moveToNext()) {
metadata.readFromCursor(notesCursor);
builder.append(metadata.getValue(ProducteevNote.MESSAGE)).append(TaskAdapter.DETAIL_SEPARATOR);
pdvRepeatingValue = Integer.parseInt(pdvRepeating[0]);
} catch (Exception e) {
pdvRepeatingDay = pdvRepeating[0];
pdvRepeatingValue = 1;
}
String pdvRepeatingInterval = pdvRepeating[1];
if (pdvRepeatingInterval.startsWith("day")) {
interval = context.getResources().getQuantityString(R.plurals.DUt_days, pdvRepeatingValue,
pdvRepeatingValue);
} else if (pdvRepeatingInterval.startsWith("weekday")) {
interval = context.getResources().getQuantityString(R.plurals.DUt_weekdays, pdvRepeatingValue,
pdvRepeatingValue);
} else if (pdvRepeatingInterval.startsWith("week")) {
interval = context.getResources().getQuantityString(R.plurals.DUt_weeks, pdvRepeatingValue,
pdvRepeatingValue);
} else if (pdvRepeatingInterval.startsWith("month")) {
interval = context.getResources().getQuantityString(R.plurals.DUt_months, pdvRepeatingValue,
pdvRepeatingValue);
} else if (pdvRepeatingInterval.startsWith("year")) {
interval = context.getResources().getQuantityString(R.plurals.DUt_years, pdvRepeatingValue,
pdvRepeatingValue);
}
interval = "<b>" + interval + "</b>"; //$NON-NLS-1$//$NON-NLS-2$
if (pdvRepeatingDay != null) {
DateFormatSymbols dfs = new DateFormatSymbols();
String[] weekdays = dfs.getShortWeekdays();
if (pdvRepeatingDay.equals("monday")) {
pdvRepeatingDay = weekdays[Calendar.MONDAY];
} else if (pdvRepeatingDay.equals("tuesday")) {
pdvRepeatingDay = weekdays[Calendar.TUESDAY];
} else if (pdvRepeatingDay.equals("wednesday")) {
pdvRepeatingDay = weekdays[Calendar.WEDNESDAY];
} else if (pdvRepeatingDay.equals("thursday")) {
pdvRepeatingDay = weekdays[Calendar.THURSDAY];
} else if (pdvRepeatingDay.equals("friday")) {
pdvRepeatingDay = weekdays[Calendar.FRIDAY];
} else if (pdvRepeatingDay.equals("saturday")) {
pdvRepeatingDay = weekdays[Calendar.SATURDAY];
} else if (pdvRepeatingDay.equals("sunday")) {
pdvRepeatingDay = weekdays[Calendar.SUNDAY];
}
} finally {
notesCursor.close();
interval = context.getResources().getString(R.string.repeat_detail_byday).replace("$I", //$NON-NLS-1$
interval).replace("$D", pdvRepeatingDay); //$NON-NLS-1$
}
String detail = context.getString(R.string.repeat_detail_duedate, interval);
builder.append("<img src='repeating_deadline'/> ").append(detail). //$NON-NLS-1$
append(TaskAdapter.DETAIL_SEPARATOR);
}
if(builder.length() == 0)

@ -2,11 +2,18 @@ package com.todoroo.astrid.producteev.api;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import org.json.JSONObject;
import android.text.Html;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.notes.NoteMetadata;
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
/**
* Utilities for working with API responses and JSON objects
@ -65,11 +72,34 @@ public final class ApiUtilities {
}
/**
* Unescape a Producteev string
* Un-escape a Producteev string
* @param string
* @return
*/
public static String decode(String string) {
string = string.replace("\n", "<br/>"); //$NON-NLS-1$ //$NON-NLS-2$
return Html.fromHtml(string).toString();
}
/**
* Create metadata from json object
* @param note JSON object with params id_note and message
* @return
*/
@SuppressWarnings("nls")
public static Metadata createNoteMetadata(JSONObject note) {
Metadata metadata = new Metadata();
metadata.setValue(Metadata.KEY, NoteMetadata.METADATA_KEY);
metadata.setValue(NoteMetadata.EXT_ID, note.optString("id_note"));
metadata.setValue(NoteMetadata.EXT_PROVIDER, ProducteevDataService.NOTE_PROVIDER);
metadata.setValue(NoteMetadata.BODY, ApiUtilities.decode(note.optString("message")));
long created = ApiUtilities.producteevToUnixTime(note.optString("time_create"), 0);
metadata.setValue(Metadata.CREATION_DATE, created);
// TODO if id_creator != yourself, update the title
metadata.setValue(NoteMetadata.TITLE, DateUtilities.getDateStringWithWeekday(ContextManager.getContext(),
new Date(created)));
return metadata;
}
}

@ -29,6 +29,7 @@ import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.StoreObject;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.notes.NoteMetadata;
import com.todoroo.astrid.producteev.ProducteevUtilities;
import com.todoroo.astrid.producteev.api.ApiUtilities;
import com.todoroo.astrid.service.MetadataService;
@ -41,7 +42,8 @@ public final class ProducteevDataService {
/** Utility for joining tasks with metadata */
public static final Join METADATA_JOIN = Join.left(Metadata.TABLE, Task.ID.eq(Metadata.TASK));
public static final String MILK_NOTE_KEY = "rmilk-note"; //$NON-NLS-1$
/** NoteMetadata provider string */
public static final String NOTE_PROVIDER = "producteev"; //$NON-NLS-1$
// --- singleton
@ -82,7 +84,6 @@ public final class ProducteevDataService {
*/
public void clearMetadata() {
metadataService.deleteWhere(Metadata.KEY.eq(ProducteevTask.METADATA_KEY));
metadataService.deleteWhere(Metadata.KEY.eq(ProducteevNote.METADATA_KEY));
storeObjectDao.deleteWhere(StoreObject.TYPE.eq(ProducteevDashboard.TYPE));
PluginServices.getTaskService().clearDetails(Task.ID.in(Query.select(Metadata.TASK).from(Metadata.TABLE).
where(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY))));
@ -148,7 +149,8 @@ public final class ProducteevDataService {
task.metadata.add(task.pdvTask);
metadataService.synchronizeMetadata(task.task.getId(), task.metadata,
Criterion.or(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY),
Criterion.and(MetadataCriteria.withKey(NoteMetadata.METADATA_KEY),
NoteMetadata.EXT_PROVIDER.eq(NOTE_PROVIDER)),
MetadataCriteria.withKey(TagService.KEY)));
}
@ -166,8 +168,7 @@ public final class ProducteevDataService {
where(Criterion.and(MetadataCriteria.byTask(task.getId()),
Criterion.or(MetadataCriteria.withKey(TagService.KEY),
MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
MetadataCriteria.withKey(MILK_NOTE_KEY), // to sync rmilk notes
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY)))));
MetadataCriteria.withKey(NoteMetadata.METADATA_KEY)))));
try {
for(metadataCursor.moveToFirst(); !metadataCursor.isAfterLast(); metadataCursor.moveToNext()) {
metadata.add(new Metadata(metadataCursor));
@ -202,7 +203,7 @@ public final class ProducteevDataService {
*/
public TodorooCursor<Metadata> getTaskNotesCursor(long taskId) {
TodorooCursor<Metadata> cursor = metadataService.query(Query.select(Metadata.PROPERTIES).
where(MetadataCriteria.byTaskAndwithKey(taskId, ProducteevNote.METADATA_KEY)));
where(MetadataCriteria.byTaskAndwithKey(taskId, NoteMetadata.METADATA_KEY)));
return cursor;
}

@ -1,50 +0,0 @@
package com.todoroo.astrid.producteev.sync;
import org.json.JSONObject;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.producteev.api.ApiUtilities;
/**
* Metadata entries for a Producteev note. The first Producteev note becomes
* Astrid's note field, subsequent notes are stored in metadata in this
* format.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class ProducteevNote {
/** metadata key */
public static final String METADATA_KEY = "producteev-note"; //$NON-NLS-1$
/** note id */
public static final LongProperty ID = new LongProperty(Metadata.TABLE,
Metadata.VALUE1.name);
/** note message */
public static final StringProperty MESSAGE = Metadata.VALUE2;
/** note creation date */
public static final LongProperty CREATED = new LongProperty(Metadata.TABLE,
Metadata.VALUE3.name);
/**
* Create metadata from json object
* @param note JSON object with params id_note and message
* @return
*/
@SuppressWarnings("nls")
public static Metadata create(JSONObject note) {
Metadata metadata = new Metadata();
metadata.setValue(Metadata.KEY, METADATA_KEY);
metadata.setValue(ID, note.optLong("id_note"));
metadata.setValue(MESSAGE, ApiUtilities.decode(note.optString("message")));
metadata.setValue(CREATED, ApiUtilities.producteevToUnixTime(
note.optString("time_create"), 0));
return metadata;
}
}

@ -458,7 +458,7 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
JSONArray notes = remoteTask.getJSONArray("notes");
for(int i = notes.length() - 1; i >= 0; i--) {
JSONObject note = notes.getJSONObject(i).getJSONObject("note");
metadata.add(ProducteevNote.create(note));
metadata.add(ApiUtilities.createNoteMetadata(note));
}
ProducteevTaskContainer container = new ProducteevTaskContainer(task, metadata, remoteTask);
@ -572,29 +572,10 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
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.metadata.add(ApiUtilities.createNoteMetadata(result.getJSONObject("note")));
local.task.setValue(Task.NOTES, "");
}
// milk note => producteev note
if(local.findMetadata(ProducteevDataService.MILK_NOTE_KEY) != null && (remote == null ||
(remote.findMetadata(ProducteevNote.METADATA_KEY) == null))) {
for(Metadata item : local.metadata) {
if(ProducteevDataService.MILK_NOTE_KEY.equals(item.getValue(Metadata.KEY))) {
String title = item.getValue(Metadata.VALUE2);
String text = item.getValue(Metadata.VALUE3);
String message;
if(!TextUtils.isEmpty(title))
message = title + "\n" + text;
else
message = text;
JSONObject result = invoker.tasksNoteCreate(idTask, message);
local.metadata.add(ProducteevNote.create(result.getJSONObject("note")));
}
}
}
if(remerge) {
remote = pull(local);
remote.task.setId(local.task.getId());

@ -35,8 +35,7 @@ public class RepeatDetailExposer extends BroadcastReceiver {
if(taskId == -1)
return;
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
String taskDetail = getTaskDetails(context, taskId, extended);
String taskDetail = getTaskDetails(context, taskId);
if(taskDetail == null)
return;
@ -44,15 +43,11 @@ public class RepeatDetailExposer extends BroadcastReceiver {
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, RepeatsPlugin.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
public String getTaskDetails(Context context, long id, boolean extended) {
if(extended)
return null;
public String getTaskDetails(Context context, long id) {
Task task = PluginServices.getTaskService().fetchById(id, Task.FLAGS, Task.RECURRENCE);
if(task == null)
return null;

@ -26,22 +26,20 @@ public class SharingDetailExposer extends BroadcastReceiver {
if(taskId == -1)
return;
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
String taskDetail = getTaskDetails(taskId, extended);
String taskDetail = getTaskDetails(taskId);
if(taskDetail == null)
return;
// transmit
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
public String getTaskDetails(long id, boolean extended) {
public String getTaskDetails(long id) {
Metadata metadata = PluginServices.getMetadataByTaskAndWithKey(id, SharingFields.METADATA_KEY);
if(metadata == null || extended)
if(metadata == null)
return null;
if(metadata.getValue(SharingFields.PRIVACY) == SharingFields.PRIVACY_PUBLIC)

@ -24,8 +24,7 @@ public class TagDetailExposer extends BroadcastReceiver {
if(taskId == -1)
return;
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
String taskDetail = getTaskDetails(taskId, extended);
String taskDetail = getTaskDetails(taskId);
if(taskDetail == null)
return;
@ -33,15 +32,11 @@ public class TagDetailExposer extends BroadcastReceiver {
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, TagsPlugin.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
public String getTaskDetails(long id, boolean extended) {
if(extended)
return null;
public String getTaskDetails(long id) {
String tagList = TagService.getInstance().getTagsAsString(id);
if(tagList.length() == 0)
return null;

@ -9,8 +9,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="5"
android:paddingLeft="5px"
android:paddingRight="5px"
android:paddingLeft="8px"
android:paddingRight="8px"
android:gravity="center_horizontal"
android:background="#00000000"
android:scaleType="center"

@ -5,7 +5,6 @@ package org.weloveastrid.rmilk;
import org.weloveastrid.rmilk.data.MilkListService;
import org.weloveastrid.rmilk.data.MilkMetadataService;
import org.weloveastrid.rmilk.data.MilkNoteFields;
import org.weloveastrid.rmilk.data.MilkTaskFields;
import android.content.BroadcastReceiver;
@ -13,13 +12,11 @@ import android.content.Context;
import android.content.Intent;
import com.timsu.astrid.R;
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.astrid.api.AstridApiConstants;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.andlib.utility.Preferences;
/**
* Exposes Task Details for Remember the Milk:
@ -54,53 +51,37 @@ public class MilkDetailExposer extends BroadcastReceiver {
if(taskId == -1)
return;
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
String taskDetail = getTaskDetails(context, taskId, extended);
String taskDetail = getTaskDetails(context, taskId);
if(taskDetail == null)
return;
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, MilkUtilities.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);
}
public String getTaskDetails(Context context, long id, boolean extended) {
public String getTaskDetails(Context context, long id) {
Metadata metadata = milkMetadataService.getTaskMetadata(id);
if(metadata == null)
return null;
StringBuilder builder = new StringBuilder();
if(!extended) {
long listId = metadata.getValue(MilkTaskFields.LIST_ID);
String listName = milkListService.getListName(listId);
// RTM list is out of date. don't display RTM stuff
if(listName == null)
return null;
if(listId > 0 && !"Inbox".equals(listName)) { //$NON-NLS-1$
builder.append("<img src='silk_folder'/> ").append(listName).append(DETAIL_SEPARATOR); //$NON-NLS-1$
}
int repeat = metadata.getValue(MilkTaskFields.REPEATING);
if(repeat != 0) {
builder.append(context.getString(R.string.rmilk_TLA_repeat)).append(DETAIL_SEPARATOR);
}
long listId = metadata.getValue(MilkTaskFields.LIST_ID);
String listName = milkListService.getListName(listId);
// RTM list is out of date. don't display RTM stuff
if(listName == null)
return null;
if(listId > 0 && !"Inbox".equals(listName)) { //$NON-NLS-1$
builder.append("<img src='silk_folder'/> ").append(listName).append(DETAIL_SEPARATOR); //$NON-NLS-1$
}
if(Preferences.getBoolean(R.string.p_showNotes, false) == !extended) {
TodorooCursor<Metadata> notesCursor = milkMetadataService.getTaskNotesCursor(id);
try {
for(notesCursor.moveToFirst(); !notesCursor.isAfterLast(); notesCursor.moveToNext()) {
metadata.readFromCursor(notesCursor);
builder.append(MilkNoteFields.toTaskDetail(metadata)).append(DETAIL_SEPARATOR);
}
} finally {
notesCursor.close();
}
int repeat = metadata.getValue(MilkTaskFields.REPEATING);
if(repeat != 0) {
builder.append(context.getString(R.string.rmilk_TLA_repeat)).append(DETAIL_SEPARATOR);
}
if(builder.length() == 0)

@ -16,6 +16,7 @@ import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.MetadataApiDao.MetadataCriteria;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.notes.NoteMetadata;
import com.todoroo.astrid.sync.SyncMetadataService;
import com.todoroo.astrid.sync.SyncProviderUtilities;
@ -45,7 +46,8 @@ public final class MilkMetadataService extends SyncMetadataService<MilkTaskConta
public Criterion getMetadataCriteria() {
return Criterion.or(MetadataCriteria.withKey(TAG_KEY),
MetadataCriteria.withKey(MilkTaskFields.METADATA_KEY),
MetadataCriteria.withKey(MilkNoteFields.METADATA_KEY));
Criterion.and(MetadataCriteria.withKey(NoteMetadata.METADATA_KEY),
NoteMetadata.EXT_PROVIDER.eq(MilkNoteHelper.PROVIDER)));
}
@Override
@ -63,7 +65,7 @@ public final class MilkMetadataService extends SyncMetadataService<MilkTaskConta
*/
public TodorooCursor<Metadata> getTaskNotesCursor(long taskId) {
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
where(MetadataCriteria.byTaskAndwithKey(taskId, MilkNoteFields.METADATA_KEY)));
where(MetadataCriteria.byTaskAndwithKey(taskId, NoteMetadata.METADATA_KEY)));
return cursor;
}

@ -4,9 +4,8 @@ import org.weloveastrid.rmilk.api.data.RtmTaskNote;
import android.text.TextUtils;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.notes.NoteMetadata;
/**
* Metadata entries for a Remember the Milk note. The first RMilk note becomes
@ -16,31 +15,19 @@ import com.todoroo.astrid.data.Metadata;
* @author Tim Su <tim@todoroo.com>
*
*/
public class MilkNoteFields {
public class MilkNoteHelper {
/** metadata key */
public static final String METADATA_KEY = "rmilk-note"; //$NON-NLS-1$
/** note id */
public static final StringProperty ID = Metadata.VALUE1;
/** note title */
public static final StringProperty TITLE = Metadata.VALUE2;
/** note text */
public static final StringProperty TEXT = Metadata.VALUE3;
/** note creation date */
public static final LongProperty CREATED = new LongProperty(Metadata.TABLE,
Metadata.VALUE4.name);
public static final String PROVIDER = "rmilk"; //$NON-NLS-1$
public static Metadata create(RtmTaskNote note) {
Metadata metadata = new Metadata();
metadata.setValue(Metadata.KEY, METADATA_KEY);
metadata.setValue(ID, note.getId());
metadata.setValue(TITLE, note.getTitle());
metadata.setValue(TEXT, note.getText());
metadata.setValue(CREATED, note.getCreated().getTime());
metadata.setValue(Metadata.KEY, NoteMetadata.METADATA_KEY);
metadata.setValue(NoteMetadata.EXT_ID, note.getId());
metadata.setValue(NoteMetadata.EXT_PROVIDER, PROVIDER);
metadata.setValue(NoteMetadata.TITLE, note.getTitle());
metadata.setValue(NoteMetadata.BODY, note.getText());
metadata.setValue(Metadata.CREATION_DATE, note.getCreated().getTime());
return metadata;
}
@ -87,23 +74,4 @@ public class MilkNoteFields {
return result;
}
/**
* Turn a note's title and text into an HTML string for notes
* @param metadata
* @return
*/
@SuppressWarnings("nls")
public static String toTaskDetail(Metadata metadata) {
String title = metadata.getValue(TITLE);
String text = metadata.getValue(TEXT);
String result;
if(!TextUtils.isEmpty(title))
result = "<b>" + title + "</b> " + text;
else
result = text;
return result;
}
}

@ -30,7 +30,7 @@ import org.weloveastrid.rmilk.api.data.RtmAuth.Perms;
import org.weloveastrid.rmilk.api.data.RtmTask.Priority;
import org.weloveastrid.rmilk.data.MilkListService;
import org.weloveastrid.rmilk.data.MilkMetadataService;
import org.weloveastrid.rmilk.data.MilkNoteFields;
import org.weloveastrid.rmilk.data.MilkNoteHelper;
import android.app.Activity;
import android.app.Notification;
@ -478,7 +478,7 @@ public class MilkSyncProvider extends SyncProvider<MilkTaskContainer> {
// notes
if(shouldTransmit(local, Task.NOTES, remote)) {
String[] titleAndText = MilkNoteFields.fromNoteField(local.task.getValue(Task.NOTES));
String[] titleAndText = MilkNoteHelper.fromNoteField(local.task.getValue(Task.NOTES));
List<RtmTaskNote> notes = null;
if(remote != null && remote.remote.getNotes() != null)
notes = remote.remote.getNotes().getNotes();
@ -540,9 +540,9 @@ public class MilkSyncProvider extends SyncProvider<MilkTaskContainer> {
for(RtmTaskNote note : rtmTaskSeries.getNotes().getNotes()) {
if(firstNote) {
firstNote = false;
task.setValue(Task.NOTES, MilkNoteFields.toNoteField(note));
task.setValue(Task.NOTES, MilkNoteHelper.toNoteField(note));
} else
metadata.add(MilkNoteFields.create(note));
metadata.add(MilkNoteHelper.create(note));
}
}

@ -4,11 +4,14 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicReference;
import org.weloveastrid.rmilk.MilkPreferences;
import org.weloveastrid.rmilk.MilkUtilities;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.PendingIntent.CanceledException;
@ -30,28 +33,28 @@ import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.inputmethod.EditorInfo;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.Property;
@ -543,10 +546,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
taskAdapter.decorationManager.addNew(taskId, addOn, deco);
} else if(AstridApiConstants.BROADCAST_SEND_DETAILS.equals(intent.getAction())) {
String detail = extras.getString(AstridApiConstants.EXTRAS_RESPONSE);
if(extras.getBoolean(AstridApiConstants.EXTRAS_EXTENDED))
taskAdapter.extendedDetailManager.addNew(taskId, addOn, detail);
else
taskAdapter.addDetails(taskId, detail);
taskAdapter.addDetails(taskId, detail);
} else if(AstridApiConstants.BROADCAST_SEND_ACTIONS.equals(intent.getAction())) {
TaskAction action = extras.getParcelable(AstridApiConstants.EXTRAS_RESPONSE);
taskAdapter.taskActionManager.addNew(taskId, addOn, action);
@ -880,6 +880,9 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
resolveInfo.activityInfo.name);
String category = MetadataHelper.resolveActivityCategoryName(resolveInfo, pm);
if(MilkPreferences.class.getName().equals(resolveInfo.activityInfo.name) &&
!MilkUtilities.INSTANCE.isLoggedIn())
continue;
if (category.equals(desiredCategory)) {
syncIntents.add(new IntentWithLabel(intent,

@ -9,7 +9,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicReference;
@ -28,7 +27,6 @@ import android.text.Html.ImageGetter;
import android.text.Html.TagHandler;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.util.Linkify;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
@ -130,7 +128,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
// --- task detail and decoration soft caches
public final ExtendedDetailManager extendedDetailManager;
public final DecorationManager decorationManager;
public final TaskActionManager taskActionManager;
@ -171,7 +168,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
detailLoader = new DetailLoaderThread();
detailLoader.start();
extendedDetailManager = new ExtendedDetailManager();
decorationManager = new DecorationManager();
taskActionManager = new TaskActionManager();
}
@ -352,15 +348,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
// details and decorations, expanded
decorationManager.request(viewHolder);
if(!isFling && expanded == task.getId()) {
if(viewHolder.extendedDetails != null)
extendedDetailManager.request(viewHolder);
taskActionManager.request(viewHolder);
} else {
if(viewHolder.extendedDetails != null)
viewHolder.extendedDetails.setVisibility(View.GONE);
viewHolder.actions.setVisibility(View.GONE);
}
}
protected TaskRowListener listener = new TaskRowListener();
@ -478,7 +465,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
private void requestNewDetails(Task task) {
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
}
@ -542,7 +528,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
*/
public void flushCaches() {
completedItems.clear();
extendedDetailManager.clearCache();
decorationManager.clearCache();
taskActionManager.clearCache();
taskDetailLoader.clear();
@ -555,76 +540,11 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
*/
public void flushSpecific(long taskId) {
completedItems.put(taskId, null);
extendedDetailManager.clearCache(taskId);
decorationManager.clearCache(taskId);
taskActionManager.clearCache(taskId);
taskDetailLoader.remove(taskId);
}
/**
* AddOnManager for Details
* @author Tim Su <tim@todoroo.com>
*
*/
public class ExtendedDetailManager extends TaskAdapterAddOnManager<String> {
private final Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS);
public ExtendedDetailManager() {
super(activity);
}
@Override
protected
Intent createBroadcastIntent(Task task) {
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, true);
return broadcastIntent;
}
@Override
public void addNew(long taskId, String addOn, String item) {
super.addNew(taskId, addOn, item);
}
private final StringBuilder detailText = new StringBuilder();
@SuppressWarnings("nls")
@Override
protected
void draw(ViewHolder viewHolder, long taskId, Collection<String> details) {
if(details == null || viewHolder.task.getId() != taskId)
return;
TextView view = viewHolder.extendedDetails;
if(details.isEmpty() || (expanded != taskId)) {
reset(viewHolder, taskId);
return;
}
view.setVisibility(View.VISIBLE);
detailText.setLength(0);
for(Iterator<String> iterator = details.iterator(); iterator.hasNext(); ) {
detailText.append(iterator.next());
if(iterator.hasNext())
detailText.append(DETAIL_SEPARATOR);
}
String string = detailText.toString();
if(string.contains("<"))
view.setText(convertToHtml(string.trim().replace("\n", "<br>"),
detailImageGetter, null));
else
view.setText(string.trim());
if(string.contains(".") || string.contains("-"))
Linkify.addLinks(view, Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS |
Linkify.WEB_URLS);
}
@Override
protected void reset(ViewHolder viewHolder, long taskId) {
TextView view = viewHolder.extendedDetails;
if(view != null)
view.setVisibility(View.GONE);
}
}
/**
* AddOnManager for TaskDecorations
*

@ -28,7 +28,7 @@ public class Database extends AbstractDatabase {
* 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 = 7;
public static final int VERSION = 8;
/**
* Database name (must be unique)
@ -125,11 +125,15 @@ public class Database extends AbstractDatabase {
}
case 5: {
database.execSQL("ALTER TABLE " + Task.TABLE.name + " ADD " +
Task.REMINDER_SNOOZE.accept(visitor, null));
Task.REMINDER_SNOOZE.accept(visitor, null));
}
case 6: {
database.execSQL("ALTER TABLE " + Task.TABLE.name + " ADD " +
Task.DETAILS_DATE.accept(visitor, null));
Task.DETAILS_DATE.accept(visitor, null));
}
case 7: {
database.execSQL("ALTER TABLE " + Metadata.TABLE.name + " ADD " +
Metadata.CREATION_DATE.accept(visitor, null));
}
return true;

@ -15,6 +15,7 @@ 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.DateUtilities;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.provider.Astrid2TaskProvider;
@ -63,6 +64,9 @@ public class MetadataDao extends DatabaseDao<Metadata> {
@Override
public boolean persist(Metadata item) {
if(!item.containsValue(Metadata.CREATION_DATE))
item.setValue(Metadata.CREATION_DATE, DateUtilities.now());
boolean state = super.persist(item);
Astrid2TaskProvider.notifyDatabaseModification();
return state;

@ -5,6 +5,7 @@ import java.util.HashSet;
import android.content.ContentValues;
import com.todoroo.andlib.data.Property.CountProperty;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
@ -137,4 +138,19 @@ public class MetadataService {
return written;
}
/**
* Does metadata with this key and task exist?
*/
public boolean hasMetadata(long id, String key) {
CountProperty count = new CountProperty();
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(
count).where(MetadataCriteria.byTaskAndwithKey(id, key)));
try {
cursor.moveToFirst();
return cursor.get(count) > 0;
} finally {
cursor.close();
}
}
}

@ -1,5 +1,9 @@
package com.todoroo.astrid.service;
import java.util.Date;
import org.weloveastrid.rmilk.data.MilkNoteHelper;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
@ -7,22 +11,30 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty;
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.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.core.SortHelper;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.notes.NoteMetadata;
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
import com.todoroo.astrid.utility.AstridPreferences;
public final class UpgradeService {
public static final int V3_7_0 = 171;
public static final int V3_7_0 = 172;
public static final int V3_6_4 = 170;
public static final int V3_6_3 = 169;
public static final int V3_6_2 = 168;
@ -35,10 +47,11 @@ public final class UpgradeService {
public static final int V3_0_0 = 136;
public static final int V2_14_4 = 135;
@Autowired
private Database database;
@Autowired Database database;
@Autowired private TaskService taskService;
@Autowired TaskService taskService;
@Autowired MetadataService metadataService;
public UpgradeService() {
DependencyInjectionService.getInstance().inject(this);
@ -120,6 +133,15 @@ public final class UpgradeService {
} else {
// current message
if(from < V3_7_0) {
newVersionString(changeLog, "3.7.0 (2/7/10)", new String[] {
"Improved UI for displaying task actions. Tap a task to " +
"bring up an action bar, tap anywhere to dismiss.",
"Task notes can be viewed by tapping the note icon to " +
"the right of the task.",
"Added Astrid to 'Send-To' menu of Android Browser and " +
"other apps for easy task creation.",
"Fixed bug with custom filters & tasks being hidden",
});
upgrade3To3_7();
}
@ -221,8 +243,9 @@ public final class UpgradeService {
// --- upgrade functions
/**
* Fixes task filter missing tasks bug
* Fixes task filter missing tasks bug, migrate PDV/RTM notes
*/
@SuppressWarnings("nls")
private void upgrade3To3_7() {
TodorooCursor<Task> t = taskService.query(Query.select(Task.ID, Task.DUE_DATE).where(Task.DUE_DATE.gt(0)));
Task task = new Task();
@ -233,6 +256,54 @@ public final class UpgradeService {
taskService.save(task);
}
}
t.close();
TodorooCursor<Metadata> m = metadataService.query(Query.select(Metadata.PROPERTIES).
where(Criterion.or(Metadata.KEY.eq("producteev-note"),
Metadata.KEY.eq("rmilk-note"))));
StringProperty PDV_NOTE_ID = Metadata.VALUE1;
StringProperty PDV_NOTE_MESSAGE = Metadata.VALUE2;
LongProperty PDV_NOTE_CREATED = new LongProperty(Metadata.TABLE, Metadata.VALUE3.name);
StringProperty RTM_NOTE_ID = Metadata.VALUE1;
StringProperty RTM_NOTE_TITLE = Metadata.VALUE2;
StringProperty RTM_NOTE_TEXT = Metadata.VALUE3;
LongProperty RTM_NOTE_CREATED = new LongProperty(Metadata.TABLE, Metadata.VALUE4.name);
Metadata metadata = new Metadata();
for(m.moveToFirst(); !m.isAfterLast(); m.moveToNext()) {
metadata.readFromCursor(m);
String id, body, title, provider;
long created;
if("rmilk-note".equals(metadata.getValue(Metadata.KEY))) {
id = metadata.getValue(RTM_NOTE_ID);
body = metadata.getValue(RTM_NOTE_TEXT);
title = metadata.getValue(RTM_NOTE_TITLE);
created = metadata.getValue(RTM_NOTE_CREATED);
provider = MilkNoteHelper.PROVIDER;
} else {
id = metadata.getValue(PDV_NOTE_ID);
body = metadata.getValue(PDV_NOTE_MESSAGE);
created = metadata.getValue(PDV_NOTE_CREATED);
title = DateUtilities.getDateStringWithWeekday(ContextManager.getContext(),
new Date(created));
provider = ProducteevDataService.NOTE_PROVIDER;
}
metadata.setValue(Metadata.KEY, NoteMetadata.METADATA_KEY);
metadata.setValue(Metadata.CREATION_DATE, created);
metadata.setValue(NoteMetadata.BODY, body);
metadata.setValue(NoteMetadata.TITLE, title);
metadata.setValue(NoteMetadata.THUMBNAIL, null);
metadata.setValue(NoteMetadata.EXT_PROVIDER, provider);
metadata.setValue(NoteMetadata.EXT_ID, id);
metadata.clearValue(Metadata.ID);
metadataService.save(metadata);
}
m.close();
}
/**

@ -112,7 +112,6 @@ public class GtasksDetailExposerTest extends DatabaseTestCase {
private void whenRequestingDetails() {
Intent intent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS);
intent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
intent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
detail = null;
new GtasksDetailExposer().onReceive(getContext(), intent);

Loading…
Cancel
Save