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 e60a3c2e9..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 %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 $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: %2$s: %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 ccde95303..6a80afe14 100644 --- a/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java +++ b/astrid/src/com/todoroo/astrid/adapter/UpdateAdapter.java @@ -1,6 +1,8 @@ package com.todoroo.astrid.adapter; import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.json.JSONException; import org.json.JSONObject; @@ -11,9 +13,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 +35,9 @@ 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; import com.todoroo.astrid.helper.AsyncImageView; import com.todoroo.astrid.helper.ImageDiskCache; @@ -44,12 +53,16 @@ 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; private final String linkColor; private final String fromView; + 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 String UPDATE_FRIENDS = "friends"; //$NON-NLS-1$ private static final String UPDATE_REQUEST_FRIENDSHIP = "request_friendship"; //$NON-NLS-1$ @@ -94,7 +107,7 @@ public class UpdateAdapter extends CursorAdapter { this.resource = resource; this.fragment = fragment; - + this.activity = (AstridActivity) fragment.getActivity(); } public static String getLinkColor(Fragment f) { @@ -150,7 +163,8 @@ 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()); } @@ -164,6 +178,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$ @@ -211,7 +230,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); } @@ -222,13 +241,14 @@ public class UpdateAdapter extends CursorAdapter { otherUser = new JSONObject(); } - return getUpdateComment(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); } - public static Spanned getUpdateComment (String actionCode, String user, String targetName, String message, String otherUser, String action, String linkColor, String fromView) { + 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); } @@ -294,6 +314,69 @@ 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(TARGET_LINK_PREFIX); + + if (taskLinkIndex < 0) + return Html.fromHtml(original); + + 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(' '); + } + } else { + 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(); + } + + 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; } } 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. *