From 6701e46bfb5122d6bf6edad11c1798712c85028f Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Fri, 13 Apr 2012 19:17:55 -0700 Subject: [PATCH 1/4] Good progress on linkifying task titles in comments --- astrid/res/values/strings-updates.xml | 14 ++-- .../todoroo/astrid/adapter/UpdateAdapter.java | 73 ++++++++++++++++++- .../todoroo/astrid/service/TaskService.java | 19 +++++ 3 files changed, 96 insertions(+), 10 deletions(-) diff --git a/astrid/res/values/strings-updates.xml b/astrid/res/values/strings-updates.xml index e60a3c2e9..1f52a0181 100644 --- a/astrid/res/values/strings-updates.xml +++ b/astrid/res/values/strings-updates.xml @@ -8,13 +8,13 @@ %1$s wants to be friends with you %1$s has confirmed your friendship request %1$s created this task - %1$s created %2$s - %1$s added %2$s to this list - %1$s completed %2$s. Huzzah! - %1$s un-completed %2$s. - %1$s added %2$s to %4$s - %1$s added %2$s to this list - %1$s assigned %2$s to %4$s + %1$s created @task + %1$s added @task to this list + %1$s completed @task. Huzzah! + %1$s un-completed @task. + %1$s added @task to %4$s + %1$s added @task to this list + %1$s assigned @task to %4$s %1$s commented: %3$s %1$s Re: %2$s: %3$s %1$s Re: %2$s: %3$s diff --git a/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java b/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java index ccde95303..45eb4adce 100644 --- a/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java +++ b/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java @@ -1,6 +1,7 @@ package com.todoroo.astrid.adapter; import java.io.IOException; +import java.util.regex.PatternSyntaxException; import org.json.JSONException; import org.json.JSONObject; @@ -11,9 +12,13 @@ import android.content.DialogInterface; import android.database.Cursor; import android.support.v4.app.Fragment; import android.text.Html; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.format.DateUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; @@ -29,6 +34,8 @@ import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; +import com.todoroo.astrid.core.PluginServices; +import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Update; import com.todoroo.astrid.helper.AsyncImageView; import com.todoroo.astrid.helper.ImageDiskCache; @@ -50,6 +57,7 @@ public class UpdateAdapter extends CursorAdapter { private final String linkColor; private final String fromView; + private static final String TASK_LINK_TOKEN = "@task"; //$NON-NLS-1$ private static final String UPDATE_FRIENDS = "friends"; //$NON-NLS-1$ private static final String UPDATE_REQUEST_FRIENDSHIP = "request_friendship"; //$NON-NLS-1$ @@ -151,6 +159,7 @@ public class UpdateAdapter extends CursorAdapter { // name final TextView nameView = (TextView)view.findViewById(R.id.title); { nameView.setText(getUpdateComment(update, user, linkColor, fromView)); + nameView.setMovementMethod(new LinkMovementMethod()); } @@ -164,6 +173,11 @@ public class UpdateAdapter extends CursorAdapter { } + @Override + public boolean isEnabled(int position) { + return false; + } + public static void setupImagePopupForCommentView(View view, AsyncImageView commentPictureView, final String updatePicture, final String message, final Fragment fragment, ImageDiskCache imageCache) { if (!TextUtils.isEmpty(updatePicture) && !"null".equals(updatePicture)) { //$NON-NLS-1$ @@ -222,13 +236,20 @@ public class UpdateAdapter extends CursorAdapter { otherUser = new JSONObject(); } + long taskId = update.getValue(Update.TASK_LOCAL); + if (taskId <= 0) { + Task local = PluginServices.getTaskService().fetchByRemoteId(update.getValue(Update.TASK), Task.ID); + if (local != null) + taskId = local.getId(); + } + return getUpdateComment(update.getValue(Update.ACTION_CODE), user.optString("name"), update.getValue(Update.TARGET_NAME), update.getValue(Update.MESSAGE), otherUser.optString("name"), - update.getValue(Update.ACTION), linkColor, fromView); + update.getValue(Update.ACTION), linkColor, fromView, taskId); } - public static Spanned getUpdateComment (String actionCode, String user, String targetName, String message, String otherUser, String action, String linkColor, String fromView) { + public static Spanned getUpdateComment (String actionCode, String user, String targetName, String message, String otherUser, String action, String linkColor, String fromView, final long taskId) { if (TextUtils.isEmpty(user)) { user = ContextManager.getString(R.string.ENA_no_user); } @@ -294,6 +315,52 @@ public class UpdateAdapter extends CursorAdapter { return Html.fromHtml(String.format("%s %s", userLink, action)); //$NON-NLS-1$ } - return Html.fromHtml(ContextManager.getString(commentResource, userLink, targetNameLink, message, otherUserLink)); + String original = ContextManager.getString(commentResource, userLink, targetNameLink, message, otherUserLink); + int taskLinkIndex = original.indexOf(TASK_LINK_TOKEN); + + if (taskLinkIndex < 0) + return Html.fromHtml(original); + + if (taskId <= 0) { + original = original.replace(TASK_LINK_TOKEN, targetNameLink); + return Html.fromHtml(original); + } + + try { + SpannableStringBuilder builder = new SpannableStringBuilder(); + SpannableString taskSpan = new SpannableString(targetName); + taskSpan.setSpan(new ClickableSpan() { + @Override + public void onClick(View widget) { + System.err.println("Click " + taskId); + } + }, 0, targetName.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + + String[] components = original.split(TASK_LINK_TOKEN); + if (components.length > 1) { + Spanned comp1 = Html.fromHtml(components[0]); + Spanned comp2 = Html.fromHtml(components[1]); + + builder.append(comp1) + .append(taskSpan) + .append(' ') + .append(comp2); + } else if (original.endsWith(TASK_LINK_TOKEN)) { + Spanned startComp = Html.fromHtml(components[0]); + builder.append(startComp) + .append(taskSpan); + } else { + Spanned endComp = Html.fromHtml(components[0]); + builder.append(taskSpan) + .append(' ') + .append(endComp); + + } + + return builder; + } catch (PatternSyntaxException e) { + original = original.replace(TASK_LINK_TOKEN, targetNameLink); + return Html.fromHtml(original); + } } } diff --git a/astrid/src/com/todoroo/astrid/service/TaskService.java b/astrid/src/com/todoroo/astrid/service/TaskService.java index ae00dedc9..e44a72e37 100644 --- a/astrid/src/com/todoroo/astrid/service/TaskService.java +++ b/astrid/src/com/todoroo/astrid/service/TaskService.java @@ -88,6 +88,25 @@ public class TaskService { return taskDao.fetch(id, properties); } + /** + * + * @param remoteId + * @param properties + * @return item, or null if it doesn't exist + */ + public Task fetchByRemoteId(long remoteId, Property... properties) { + TodorooCursor task = query(Query.select(properties).where(Task.REMOTE_ID.eq(remoteId))); + try { + if (task.getCount() > 0) { + task.moveToFirst(); + return new Task(task); + } + return null; + } finally { + task.close(); + } + } + /** * Mark the given task as completed and save it. * From be6b1310e196d50f5a8073d7f60f2d9ff3668f84 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 16 Apr 2012 13:35:33 -0700 Subject: [PATCH 2/4] Make clicking on task links in comments edit task --- .../todoroo/astrid/notes/EditNoteActivity.java | 2 +- astrid/res/values/strings-updates.xml | 2 +- .../todoroo/astrid/adapter/UpdateAdapter.java | 17 ++++++++++------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java b/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java index c99c3072d..1be082b5d 100644 --- a/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java @@ -499,7 +499,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene String commentPicture = u.getValue(Update.PICTURE); - Spanned title = UpdateAdapter.getUpdateComment(u, user, linkColor, UpdateAdapter.FROM_TASK_VIEW); + Spanned title = UpdateAdapter.getUpdateComment(null, u, user, linkColor, UpdateAdapter.FROM_TASK_VIEW); return new NoteOrUpdate(user.optString("picture"), title, commentPicture, diff --git a/astrid/res/values/strings-updates.xml b/astrid/res/values/strings-updates.xml index 1f52a0181..91795ed85 100644 --- a/astrid/res/values/strings-updates.xml +++ b/astrid/res/values/strings-updates.xml @@ -16,7 +16,7 @@ %1$s added @task to this list %1$s assigned @task to %4$s %1$s commented: %3$s - %1$s Re: %2$s: %3$s + %1$s Re: @task: %3$s %1$s Re: %2$s: %3$s %1$s created this list %1$s created the list %2$s diff --git a/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java b/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java index 45eb4adce..342ea361b 100644 --- a/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java +++ b/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java @@ -34,6 +34,7 @@ import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; +import com.todoroo.astrid.activity.AstridActivity; import com.todoroo.astrid.core.PluginServices; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Update; @@ -51,6 +52,7 @@ public class UpdateAdapter extends CursorAdapter { // --- instance variables protected final Fragment fragment; + protected final AstridActivity activity; private final int resource; private final LayoutInflater inflater; private final ImageDiskCache imageCache; @@ -102,7 +104,7 @@ public class UpdateAdapter extends CursorAdapter { this.resource = resource; this.fragment = fragment; - + this.activity = (AstridActivity) fragment.getActivity(); } public static String getLinkColor(Fragment f) { @@ -158,7 +160,7 @@ public class UpdateAdapter extends CursorAdapter { // name final TextView nameView = (TextView)view.findViewById(R.id.title); { - nameView.setText(getUpdateComment(update, user, linkColor, fromView)); + nameView.setText(getUpdateComment(activity, update, user, linkColor, fromView)); nameView.setMovementMethod(new LinkMovementMethod()); } @@ -225,7 +227,7 @@ public class UpdateAdapter extends CursorAdapter { } @SuppressWarnings("nls") - public static Spanned getUpdateComment (Update update, JSONObject user, String linkColor, String fromView) { + public static Spanned getUpdateComment (final AstridActivity activity, Update update, JSONObject user, String linkColor, String fromView) { if (user == null) { user = ActFmPreferenceService.userFromModel(update); } @@ -243,13 +245,14 @@ public class UpdateAdapter extends CursorAdapter { taskId = local.getId(); } - return getUpdateComment(update.getValue(Update.ACTION_CODE), + return getUpdateComment(activity, update.getValue(Update.ACTION_CODE), user.optString("name"), update.getValue(Update.TARGET_NAME), update.getValue(Update.MESSAGE), otherUser.optString("name"), update.getValue(Update.ACTION), linkColor, fromView, taskId); } - public static Spanned getUpdateComment (String actionCode, String user, String targetName, String message, String otherUser, String action, String linkColor, String fromView, final long taskId) { + public static Spanned getUpdateComment (final AstridActivity activity, String actionCode, String user, String targetName, + String message, String otherUser, String action, String linkColor, String fromView, final long taskId) { if (TextUtils.isEmpty(user)) { user = ContextManager.getString(R.string.ENA_no_user); } @@ -321,7 +324,7 @@ public class UpdateAdapter extends CursorAdapter { if (taskLinkIndex < 0) return Html.fromHtml(original); - if (taskId <= 0) { + if (taskId <= 0 || activity == null) { original = original.replace(TASK_LINK_TOKEN, targetNameLink); return Html.fromHtml(original); } @@ -332,7 +335,7 @@ public class UpdateAdapter extends CursorAdapter { taskSpan.setSpan(new ClickableSpan() { @Override public void onClick(View widget) { - System.err.println("Click " + taskId); + activity.onTaskListItemClicked(taskId); } }, 0, targetName.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); From 27450795999730d2890501856b40c4c2aec7dbb0 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 16 Apr 2012 14:56:15 -0700 Subject: [PATCH 3/4] Awesome new stuff for putting links in comments. Works for tasks, can adapt to things like tags/users in the future --- astrid/res/values/strings-updates.xml | 16 +-- .../todoroo/astrid/adapter/UpdateAdapter.java | 113 ++++++++++-------- 2 files changed, 72 insertions(+), 57 deletions(-) diff --git a/astrid/res/values/strings-updates.xml b/astrid/res/values/strings-updates.xml index 91795ed85..eff8ea55f 100644 --- a/astrid/res/values/strings-updates.xml +++ b/astrid/res/values/strings-updates.xml @@ -8,15 +8,15 @@ %1$s wants to be friends with you %1$s has confirmed your friendship request %1$s created this task - %1$s created @task - %1$s added @task to this list - %1$s completed @task. Huzzah! - %1$s un-completed @task. - %1$s added @task to %4$s - %1$s added @task to this list - %1$s assigned @task to %4$s + %1$s created @link_task + %1$s added @link_task to this list + %1$s completed @link_task. Huzzah! + %1$s un-completed @link_task. + %1$s added @link_task to %4$s + %1$s added @link_task to this list + %1$s assigned @link_task to %4$s %1$s commented: %3$s - %1$s Re: @task: %3$s + %1$s Re: @link_task: %3$s %1$s Re: %2$s: %3$s %1$s created this list %1$s created the list %2$s diff --git a/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java b/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java index 342ea361b..65f69286b 100644 --- a/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java +++ b/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java @@ -1,7 +1,8 @@ package com.todoroo.astrid.adapter; import java.io.IOException; -import java.util.regex.PatternSyntaxException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.json.JSONException; import org.json.JSONObject; @@ -59,7 +60,11 @@ public class UpdateAdapter extends CursorAdapter { private final String linkColor; private final String fromView; - private static final String TASK_LINK_TOKEN = "@task"; //$NON-NLS-1$ + private static final String TARGET_LINK_PREFIX = "@link_"; //$NON-NLS-1$ + private static final String TARGET_LINK_EXPR = TARGET_LINK_PREFIX + "(\\w*)"; //$NON-NLS-1$ + private static final String TASK_LINK_TYPE = "task"; //$NON-NLS-1$ + + private static final Pattern TARGET_LINK_PATTERN = Pattern.compile(TARGET_LINK_EXPR); private static final String UPDATE_FRIENDS = "friends"; //$NON-NLS-1$ private static final String UPDATE_REQUEST_FRIENDSHIP = "request_friendship"; //$NON-NLS-1$ @@ -238,21 +243,14 @@ public class UpdateAdapter extends CursorAdapter { otherUser = new JSONObject(); } - long taskId = update.getValue(Update.TASK_LOCAL); - if (taskId <= 0) { - Task local = PluginServices.getTaskService().fetchByRemoteId(update.getValue(Update.TASK), Task.ID); - if (local != null) - taskId = local.getId(); - } - - return getUpdateComment(activity, update.getValue(Update.ACTION_CODE), + return getUpdateComment(activity, update, update.getValue(Update.ACTION_CODE), user.optString("name"), update.getValue(Update.TARGET_NAME), update.getValue(Update.MESSAGE), otherUser.optString("name"), - update.getValue(Update.ACTION), linkColor, fromView, taskId); + update.getValue(Update.ACTION), linkColor, fromView); } - public static Spanned getUpdateComment (final AstridActivity activity, String actionCode, String user, String targetName, - String message, String otherUser, String action, String linkColor, String fromView, final long taskId) { + public static Spanned getUpdateComment (final AstridActivity activity, Update update, String actionCode, String user, String targetName, + String message, String otherUser, String action, String linkColor, String fromView) { if (TextUtils.isEmpty(user)) { user = ContextManager.getString(R.string.ENA_no_user); } @@ -319,51 +317,68 @@ public class UpdateAdapter extends CursorAdapter { } String original = ContextManager.getString(commentResource, userLink, targetNameLink, message, otherUserLink); - int taskLinkIndex = original.indexOf(TASK_LINK_TOKEN); + int taskLinkIndex = original.indexOf(TARGET_LINK_PREFIX); if (taskLinkIndex < 0) return Html.fromHtml(original); - if (taskId <= 0 || activity == null) { - original = original.replace(TASK_LINK_TOKEN, targetNameLink); - return Html.fromHtml(original); - } - - try { - SpannableStringBuilder builder = new SpannableStringBuilder(); - SpannableString taskSpan = new SpannableString(targetName); - taskSpan.setSpan(new ClickableSpan() { - @Override - public void onClick(View widget) { - activity.onTaskListItemClicked(taskId); + String[] components = original.split(" "); //$NON-NLS-1$ + SpannableStringBuilder builder = new SpannableStringBuilder(); + StringBuilder htmlStringBuilder = new StringBuilder(); + + for (String comp : components) { + Matcher m = TARGET_LINK_PATTERN.matcher(comp); + if (m.find()) { + builder.append(Html.fromHtml(htmlStringBuilder.toString())); + htmlStringBuilder.setLength(0); + + String linkType = m.group(1); + CharSequence link = getLinkSpan(activity, update, actionCode, user, + targetName, message, otherUser, action, linkColor, linkType); + if (link != null) { + builder.append(link); + if (!m.hitEnd()) { + builder.append(comp.substring(m.end())); + } + builder.append(' '); } - }, 0, targetName.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - - String[] components = original.split(TASK_LINK_TOKEN); - if (components.length > 1) { - Spanned comp1 = Html.fromHtml(components[0]); - Spanned comp2 = Html.fromHtml(components[1]); - - builder.append(comp1) - .append(taskSpan) - .append(' ') - .append(comp2); - } else if (original.endsWith(TASK_LINK_TOKEN)) { - Spanned startComp = Html.fromHtml(components[0]); - builder.append(startComp) - .append(taskSpan); } else { - Spanned endComp = Html.fromHtml(components[0]); - builder.append(taskSpan) - .append(' ') - .append(endComp); + htmlStringBuilder.append(comp); + htmlStringBuilder.append(' '); + } + } + + if (htmlStringBuilder.length() > 0) + builder.append(Html.fromHtml(htmlStringBuilder.toString())); + + return builder; + } + private static CharSequence getLinkSpan(final AstridActivity activity, Update update, String actionCode, String user, String targetName, + String message, String otherUser, String action, String linkColor, String linkType) { + if (TASK_LINK_TYPE.equals(linkType)) { + long taskId = update.getValue(Update.TASK_LOCAL); + if (taskId <= 0) { + Task local = PluginServices.getTaskService().fetchByRemoteId(update.getValue(Update.TASK), Task.ID); + if (local != null) + taskId = local.getId(); } - return builder; - } catch (PatternSyntaxException e) { - original = original.replace(TASK_LINK_TOKEN, targetNameLink); - return Html.fromHtml(original); + final long taskIdToUse = taskId; + + if (taskId > 0) { + SpannableString taskSpan = new SpannableString(targetName); + taskSpan.setSpan(new ClickableSpan() { + @Override + public void onClick(View widget) { + activity.onTaskListItemClicked(taskIdToUse); + } + }, 0, targetName.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return taskSpan; + } else { + return Html.fromHtml(linkify(targetName, linkColor)); + } } + return null; } } From 279713cf48b6fe5e77c953912ff9a59e539d8889 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 16 Apr 2012 15:46:31 -0700 Subject: [PATCH 4/4] Added comment for translators, use $ for special token --- astrid/res/values/strings-updates.xml | 19 +++++++++++-------- .../todoroo/astrid/adapter/UpdateAdapter.java | 6 ++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/astrid/res/values/strings-updates.xml b/astrid/res/values/strings-updates.xml index eff8ea55f..0e83d4b71 100644 --- a/astrid/res/values/strings-updates.xml +++ b/astrid/res/values/strings-updates.xml @@ -4,19 +4,22 @@ + + %1$s is now friends with %2$s %1$s wants to be friends with you %1$s has confirmed your friendship request %1$s created this task - %1$s created @link_task - %1$s added @link_task to this list - %1$s completed @link_task. Huzzah! - %1$s un-completed @link_task. - %1$s added @link_task to %4$s - %1$s added @link_task to this list - %1$s assigned @link_task to %4$s + %1$s created $link_task + %1$s added $link_task to this list + %1$s completed $link_task. Huzzah! + %1$s un-completed $link_task. + %1$s added $link_task to %4$s + %1$s added $link_task to this list + %1$s assigned $link_task to %4$s %1$s commented: %3$s - %1$s Re: @link_task: %3$s + %1$s Re: $link_task: %3$s %1$s Re: %2$s: %3$s %1$s created this list %1$s created the list %2$s diff --git a/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java b/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java index 65f69286b..6a80afe14 100644 --- a/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java +++ b/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java @@ -60,12 +60,10 @@ public class UpdateAdapter extends CursorAdapter { private final String linkColor; private final String fromView; - private static final String TARGET_LINK_PREFIX = "@link_"; //$NON-NLS-1$ - private static final String TARGET_LINK_EXPR = TARGET_LINK_PREFIX + "(\\w*)"; //$NON-NLS-1$ + private static final String TARGET_LINK_PREFIX = "$link_"; //$NON-NLS-1$ + private static final Pattern TARGET_LINK_PATTERN = Pattern.compile("\\" + TARGET_LINK_PREFIX + "(\\w*)"); //$NON-NLS-1$//$NON-NLS-2$ private static final String TASK_LINK_TYPE = "task"; //$NON-NLS-1$ - private static final Pattern TARGET_LINK_PATTERN = Pattern.compile(TARGET_LINK_EXPR); - private static final String UPDATE_FRIENDS = "friends"; //$NON-NLS-1$ private static final String UPDATE_REQUEST_FRIENDSHIP = "request_friendship"; //$NON-NLS-1$ private static final String UPDATE_CONFIRMED_FRIENDSHIP = "confirmed_friendship"; //$NON-NLS-1$