mirror of https://github.com/tasks/tasks
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
875 lines
40 KiB
Java
875 lines
40 KiB
Java
/**
|
|
* Copyright (c) 2012 Todoroo Inc
|
|
*
|
|
* See the file "LICENSE" for the full license governing this code.
|
|
*/
|
|
package com.todoroo.astrid.adapter;
|
|
|
|
import java.io.IOException;
|
|
import java.text.ParseException;
|
|
import java.util.Arrays;
|
|
import java.util.Comparator;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
import org.json.JSONArray;
|
|
import org.json.JSONException;
|
|
import org.json.JSONObject;
|
|
|
|
import android.app.AlertDialog;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.database.Cursor;
|
|
import android.graphics.Bitmap;
|
|
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.TextPaint;
|
|
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;
|
|
import android.view.View.OnClickListener;
|
|
import android.view.ViewGroup;
|
|
import android.view.ViewGroup.LayoutParams;
|
|
import android.widget.CursorAdapter;
|
|
import android.widget.TextView;
|
|
|
|
import org.tasks.R;
|
|
import com.todoroo.andlib.data.Property;
|
|
import com.todoroo.andlib.data.Property.StringProperty;
|
|
import com.todoroo.andlib.data.TodorooCursor;
|
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
|
import com.todoroo.andlib.utility.AndroidUtilities;
|
|
import com.todoroo.andlib.utility.DateUtilities;
|
|
import com.todoroo.andlib.utility.Preferences;
|
|
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
|
|
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
|
|
import com.todoroo.astrid.activity.AstridActivity;
|
|
import com.todoroo.astrid.data.History;
|
|
import com.todoroo.astrid.data.RemoteModel;
|
|
import com.todoroo.astrid.data.Task;
|
|
import com.todoroo.astrid.data.User;
|
|
import com.todoroo.astrid.data.UserActivity;
|
|
import com.todoroo.astrid.helper.AsyncImageView;
|
|
|
|
import edu.mit.mobile.android.imagecache.ImageCache;
|
|
|
|
/**
|
|
* Adapter for displaying a user's activity
|
|
*
|
|
* @author Tim Su <tim@todoroo.com>
|
|
*
|
|
*/
|
|
public class UpdateAdapter extends CursorAdapter {
|
|
|
|
// --- instance variables
|
|
|
|
protected final Fragment fragment;
|
|
private final int resource;
|
|
private final LayoutInflater inflater;
|
|
private final ImageCache imageCache;
|
|
private final String linkColor;
|
|
private final String fromView;
|
|
|
|
public static final String USER_TABLE_ALIAS = "users_join"; //$NON-NLS-1$
|
|
|
|
public static final StringProperty USER_PICTURE = User.PICTURE.cloneAs(USER_TABLE_ALIAS, "userPicture"); //$NON-NLS-1$
|
|
private static final StringProperty USER_FIRST_NAME = User.FIRST_NAME.cloneAs(USER_TABLE_ALIAS, "userFirstName"); //$NON-NLS-1$
|
|
private static final StringProperty USER_LAST_NAME = User.LAST_NAME.cloneAs(USER_TABLE_ALIAS, "userLastName"); //$NON-NLS-1$
|
|
private static final StringProperty USER_NAME = User.NAME.cloneAs(USER_TABLE_ALIAS, "userName"); //$NON-NLS-1$
|
|
|
|
public static final StringProperty ACTIVITY_TYPE_PROPERTY = new StringProperty(null, "'" + NameMaps.TABLE_ID_USER_ACTIVITY + "' as type"); //$NON-NLS-1$//$NON-NLS-2$
|
|
public static final StringProperty HISTORY_TYPE_PROPERTY = new StringProperty(null, "'" + NameMaps.TABLE_ID_HISTORY + "'"); //$NON-NLS-1$ //$NON-NLS-2$
|
|
public static final StringProperty PADDING_PROPERTY = new StringProperty(null, "'0'"); //$NON-NLS-1$
|
|
|
|
public static final Property<?>[] USER_PROPERTIES = {
|
|
USER_PICTURE,
|
|
USER_FIRST_NAME,
|
|
USER_LAST_NAME,
|
|
USER_NAME
|
|
};
|
|
|
|
public static final Property<?>[] USER_ACTIVITY_PROPERTIES = {
|
|
UserActivity.CREATED_AT,
|
|
UserActivity.UUID,
|
|
UserActivity.ACTION,
|
|
UserActivity.MESSAGE,
|
|
UserActivity.TARGET_ID,
|
|
UserActivity.TARGET_NAME,
|
|
UserActivity.PICTURE,
|
|
UserActivity.USER_UUID,
|
|
UserActivity.ID,
|
|
ACTIVITY_TYPE_PROPERTY,
|
|
};
|
|
|
|
public static final Property<?>[] HISTORY_PROPERTIES = {
|
|
History.CREATED_AT,
|
|
History.USER_UUID,
|
|
History.COLUMN,
|
|
History.TABLE_ID,
|
|
History.OLD_VALUE,
|
|
History.NEW_VALUE,
|
|
History.TASK,
|
|
History.USER_UUID,
|
|
History.ID,
|
|
HISTORY_TYPE_PROPERTY,
|
|
};
|
|
|
|
|
|
public static final int TYPE_PROPERTY_INDEX = USER_ACTIVITY_PROPERTIES.length - 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$
|
|
|
|
public static final String FROM_TAG_VIEW = "from_tag"; //$NON-NLS-1$
|
|
public static final String FROM_TASK_VIEW = "from_task"; //$NON-NLS-1$
|
|
public static final String FROM_RECENT_ACTIVITY_VIEW = "from_recent_activity"; //$NON-NLS-1$
|
|
|
|
private final User self;
|
|
|
|
private final int color;
|
|
private final int grayColor;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param activity
|
|
* @param resource
|
|
* layout resource to inflate
|
|
* @param c
|
|
* database cursor
|
|
* @param autoRequery
|
|
* whether cursor is automatically re-queried on changes
|
|
* @param onCompletedTaskListener
|
|
* goal listener. can be null
|
|
*/
|
|
public UpdateAdapter(Fragment fragment, int resource,
|
|
Cursor c, boolean autoRequery,
|
|
String fromView) {
|
|
super(fragment.getActivity(), c, autoRequery);
|
|
DependencyInjectionService.getInstance().inject(this);
|
|
|
|
linkColor = getLinkColor(fragment);
|
|
|
|
inflater = (LayoutInflater) fragment.getActivity().getSystemService(
|
|
Context.LAYOUT_INFLATER_SERVICE);
|
|
imageCache = AsyncImageView.getImageCache();
|
|
this.fromView = fromView;
|
|
|
|
this.resource = resource;
|
|
this.fragment = fragment;
|
|
this.self = getSelfUser();
|
|
|
|
TypedValue tv = new TypedValue();
|
|
fragment.getActivity().getTheme().resolveAttribute(R.attr.asTextColor, tv, false);
|
|
color = tv.data;
|
|
|
|
fragment.getActivity().getTheme().resolveAttribute(R.attr.asDueDateColor, tv, false);
|
|
grayColor = tv.data;
|
|
}
|
|
|
|
public static User getSelfUser() {
|
|
User self = new User();
|
|
readPreferenceToUser(self, USER_FIRST_NAME, ActFmPreferenceService.PREF_FIRST_NAME);
|
|
readPreferenceToUser(self, USER_LAST_NAME, ActFmPreferenceService.PREF_LAST_NAME);
|
|
readPreferenceToUser(self, USER_NAME, ActFmPreferenceService.PREF_NAME);
|
|
readPreferenceToUser(self, USER_PICTURE, ActFmPreferenceService.PREF_PICTURE);
|
|
return self;
|
|
}
|
|
|
|
private static void readPreferenceToUser(User u, StringProperty prop, String prefKey) {
|
|
String val = Preferences.getStringValue(prefKey);
|
|
if (val == null) {
|
|
val = ""; //$NON-NLS-1$
|
|
}
|
|
u.setValue(prop, val);
|
|
}
|
|
|
|
public static String getLinkColor(Fragment f) {
|
|
TypedValue colorType = new TypedValue();
|
|
f.getActivity().getTheme().resolveAttribute(R.attr.asDetailsColor, colorType, false);
|
|
return "#" + Integer.toHexString(colorType.data).substring(2); //$NON-NLS-1$
|
|
}
|
|
|
|
/* ======================================================================
|
|
* =========================================================== view setup
|
|
* ====================================================================== */
|
|
|
|
private class ModelHolder {
|
|
public UserActivity activity = new UserActivity();
|
|
public User user = new User();
|
|
public History history = new History();
|
|
}
|
|
|
|
/** Creates a new view for use in the list view */
|
|
@Override
|
|
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
|
ViewGroup view = (ViewGroup)inflater.inflate(resource, parent, false);
|
|
|
|
view.setTag(new ModelHolder());
|
|
|
|
// populate view content
|
|
bindView(view, context, cursor);
|
|
|
|
return view;
|
|
}
|
|
|
|
/** Populates a view with content */
|
|
@Override
|
|
public void bindView(View view, Context context, Cursor c) {
|
|
TodorooCursor<UserActivity> cursor = (TodorooCursor<UserActivity>)c;
|
|
ModelHolder mh = ((ModelHolder) view.getTag());
|
|
|
|
String type = cursor.getString(TYPE_PROPERTY_INDEX);
|
|
|
|
UserActivity update = mh.activity;
|
|
update.clear();
|
|
|
|
User user = mh.user;
|
|
user.clear();
|
|
|
|
History history = mh.history;
|
|
boolean isSelf;
|
|
if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(type)) {
|
|
readUserActivityProperties(cursor, update);
|
|
isSelf = Task.USER_ID_SELF.equals(update.getValue(UserActivity.USER_UUID));
|
|
} else {
|
|
readHistoryProperties(cursor, history);
|
|
isSelf = Task.USER_ID_SELF.equals(history.getValue(History.USER_UUID));
|
|
}
|
|
readUserProperties(cursor, user, self, isSelf);
|
|
|
|
setFieldContentsAndVisibility(view, update, user, history, type);
|
|
}
|
|
|
|
public static void readUserActivityProperties(TodorooCursor<UserActivity> unionCursor, UserActivity activity) {
|
|
activity.setValue(UserActivity.CREATED_AT, unionCursor.getLong(0));
|
|
activity.setValue(UserActivity.UUID, unionCursor.getString(1));
|
|
activity.setValue(UserActivity.ACTION, unionCursor.getString(2));
|
|
activity.setValue(UserActivity.MESSAGE, unionCursor.getString(3));
|
|
activity.setValue(UserActivity.TARGET_ID, unionCursor.getString(4));
|
|
activity.setValue(UserActivity.TARGET_NAME, unionCursor.getString(5));
|
|
activity.setValue(UserActivity.PICTURE, unionCursor.getString(6));
|
|
activity.setValue(UserActivity.USER_UUID, unionCursor.getString(7));
|
|
}
|
|
|
|
public static void readHistoryProperties(TodorooCursor<UserActivity> unionCursor, History history) {
|
|
history.setValue(History.CREATED_AT, unionCursor.getLong(0));
|
|
history.setValue(History.USER_UUID, unionCursor.getString(1));
|
|
history.setValue(History.COLUMN, unionCursor.getString(2));
|
|
history.setValue(History.TABLE_ID, unionCursor.getString(3));
|
|
history.setValue(History.OLD_VALUE, unionCursor.getString(4));
|
|
history.setValue(History.NEW_VALUE, unionCursor.getString(5));
|
|
history.setValue(History.TASK, unionCursor.getString(6));
|
|
history.setValue(History.USER_UUID, unionCursor.getString(7));
|
|
}
|
|
|
|
public static void readUserProperties(TodorooCursor<UserActivity> joinCursor, User user, User self, boolean isSelf) {
|
|
if (isSelf) {
|
|
user.mergeWith(self.getSetValues());
|
|
} else {
|
|
user.setValue(USER_FIRST_NAME, joinCursor.get(USER_FIRST_NAME));
|
|
user.setValue(USER_LAST_NAME, joinCursor.get(USER_LAST_NAME));
|
|
user.setValue(USER_NAME, joinCursor.get(USER_NAME));
|
|
user.setValue(USER_PICTURE, joinCursor.get(USER_PICTURE));
|
|
}
|
|
|
|
}
|
|
|
|
/** Helper method to set the contents and visibility of each field */
|
|
public synchronized void setFieldContentsAndVisibility(View view, UserActivity activity, User user, History history, String type) {
|
|
// picture
|
|
if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(type)) {
|
|
setupUserActivityRow(view, activity, user);
|
|
} else if (NameMaps.TABLE_ID_HISTORY.equals(type)) {
|
|
setupHistoryRow(view, history, user);
|
|
}
|
|
|
|
}
|
|
|
|
private void setupUserActivityRow(View view, UserActivity activity, User user) {
|
|
final AsyncImageView pictureView = (AsyncImageView)view.findViewById(R.id.picture); {
|
|
if (user.containsNonNullValue(USER_PICTURE)) {
|
|
String pictureUrl = user.getPictureUrl(USER_PICTURE, RemoteModel.PICTURE_THUMB);
|
|
pictureView.setUrl(pictureUrl);
|
|
} else {
|
|
pictureView.setUrl(null);
|
|
}
|
|
pictureView.setVisibility(View.VISIBLE);
|
|
}
|
|
|
|
final AsyncImageView commentPictureView = (AsyncImageView)view.findViewById(R.id.comment_picture); {
|
|
String pictureThumb = activity.getPictureUrl(UserActivity.PICTURE, RemoteModel.PICTURE_MEDIUM);
|
|
String pictureFull = activity.getPictureUrl(UserActivity.PICTURE, RemoteModel.PICTURE_LARGE);
|
|
Bitmap updateBitmap = null;
|
|
if (TextUtils.isEmpty(pictureThumb)) {
|
|
updateBitmap = activity.getPictureBitmap(UserActivity.PICTURE);
|
|
}
|
|
setupImagePopupForCommentView(view, commentPictureView, pictureThumb, pictureFull, updateBitmap,
|
|
activity.getValue(UserActivity.MESSAGE), fragment, imageCache);
|
|
}
|
|
|
|
// name
|
|
final TextView nameView = (TextView)view.findViewById(R.id.title); {
|
|
nameView.setText(getUpdateComment((AstridActivity)fragment.getActivity(), activity, user, linkColor, fromView));
|
|
nameView.setMovementMethod(new LinkMovementMethod());
|
|
nameView.setTextColor(color);
|
|
}
|
|
|
|
|
|
// date
|
|
final TextView date = (TextView)view.findViewById(R.id.date); {
|
|
CharSequence dateString = DateUtils.getRelativeTimeSpanString(activity.getValue(UserActivity.CREATED_AT),
|
|
DateUtilities.now(), DateUtils.MINUTE_IN_MILLIS,
|
|
DateUtils.FORMAT_ABBREV_RELATIVE);
|
|
date.setText(dateString);
|
|
}
|
|
}
|
|
|
|
private void setupHistoryRow(View view, History history, User user) {
|
|
final AsyncImageView pictureView = (AsyncImageView)view.findViewById(R.id.picture); {
|
|
if (user.containsNonNullValue(USER_PICTURE)) {
|
|
String pictureUrl = user.getPictureUrl(USER_PICTURE, RemoteModel.PICTURE_THUMB);
|
|
pictureView.setUrl(pictureUrl);
|
|
} else {
|
|
pictureView.setUrl(null);
|
|
}
|
|
pictureView.setVisibility(View.VISIBLE);
|
|
}
|
|
|
|
final AsyncImageView commentPictureView = (AsyncImageView)view.findViewById(R.id.comment_picture);
|
|
commentPictureView.setVisibility(View.GONE);
|
|
|
|
final TextView nameView = (TextView)view.findViewById(R.id.title); {
|
|
nameView.setText(getHistoryComment((AstridActivity) fragment.getActivity(), history, user, linkColor, fromView));
|
|
nameView.setTextColor(grayColor);
|
|
}
|
|
|
|
final TextView date = (TextView)view.findViewById(R.id.date); {
|
|
CharSequence dateString = DateUtils.getRelativeTimeSpanString(history.getValue(History.CREATED_AT),
|
|
DateUtilities.now(), DateUtils.MINUTE_IN_MILLIS,
|
|
DateUtils.FORMAT_ABBREV_RELATIVE);
|
|
date.setText(dateString);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isEnabled(int position) {
|
|
return false;
|
|
}
|
|
|
|
public static void setupImagePopupForCommentView(View view, AsyncImageView commentPictureView, final String pictureThumb, final String pictureFull, final Bitmap updateBitmap,
|
|
final String message, final Fragment fragment, ImageCache imageCache) {
|
|
if ((!TextUtils.isEmpty(pictureThumb) && !"null".equals(pictureThumb)) || updateBitmap != null) { //$NON-NLS-1$
|
|
commentPictureView.setVisibility(View.VISIBLE);
|
|
if (updateBitmap != null) {
|
|
commentPictureView.setImageBitmap(updateBitmap);
|
|
} else {
|
|
commentPictureView.setUrl(pictureThumb);
|
|
}
|
|
|
|
if (pictureThumb != null && imageCache.contains(pictureThumb) && updateBitmap == null) {
|
|
try {
|
|
commentPictureView.setDefaultImageBitmap(imageCache.get(pictureThumb));
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
} else if (updateBitmap == null) {
|
|
commentPictureView.setUrl(pictureThumb);
|
|
}
|
|
|
|
view.setOnClickListener(new OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
AlertDialog image = new AlertDialog.Builder(fragment.getActivity()).create();
|
|
AsyncImageView imageView = new AsyncImageView(fragment.getActivity());
|
|
imageView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
|
|
imageView.setDefaultImageResource(android.R.drawable.ic_menu_gallery);
|
|
if (updateBitmap != null) {
|
|
imageView.setImageBitmap(updateBitmap);
|
|
} else {
|
|
imageView.setUrl(pictureFull);
|
|
}
|
|
image.setView(imageView);
|
|
|
|
image.setMessage(message);
|
|
image.setButton(fragment.getString(R.string.DLG_close), new DialogInterface.OnClickListener() {
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
return;
|
|
}
|
|
});
|
|
image.show();
|
|
}
|
|
});
|
|
} else {
|
|
commentPictureView.setVisibility(View.GONE);
|
|
}
|
|
}
|
|
|
|
public static String linkify (String string, String linkColor) {
|
|
return String.format("<font color=%s>%s</font>", linkColor, string); //$NON-NLS-1$
|
|
}
|
|
|
|
public static Spanned getUpdateComment(final AstridActivity context, UserActivity activity, User user, String linkColor, String fromView) {
|
|
String userDisplay;
|
|
if (activity.getValue(UserActivity.USER_UUID).equals(Task.USER_ID_SELF)) {
|
|
userDisplay = context.getString(R.string.update_string_user_self);
|
|
} else if (user == null) {
|
|
userDisplay = context.getString(R.string.ENA_no_user);
|
|
} else {
|
|
userDisplay = user.getDisplayName(USER_NAME, USER_FIRST_NAME, USER_LAST_NAME);
|
|
}
|
|
if (TextUtils.isEmpty(userDisplay)) {
|
|
userDisplay = context.getString(R.string.ENA_no_user);
|
|
}
|
|
String targetName = activity.getValue(UserActivity.TARGET_NAME);
|
|
String action = activity.getValue(UserActivity.ACTION);
|
|
String message = activity.getValue(UserActivity.MESSAGE);
|
|
|
|
int commentResource = 0;
|
|
if (UserActivity.ACTION_TASK_COMMENT.equals(action)) {
|
|
if (fromView.equals(FROM_TASK_VIEW) || TextUtils.isEmpty(targetName)) {
|
|
commentResource = R.string.update_string_default_comment;
|
|
} else {
|
|
commentResource = R.string.update_string_task_comment;
|
|
}
|
|
} else if (UserActivity.ACTION_TAG_COMMENT.equals(action)) {
|
|
if (fromView.equals(FROM_TAG_VIEW) || TextUtils.isEmpty(targetName)) {
|
|
commentResource = R.string.update_string_default_comment;
|
|
} else {
|
|
commentResource = R.string.update_string_tag_comment;
|
|
}
|
|
}
|
|
|
|
if (commentResource == 0) {
|
|
return Html.fromHtml(String.format("%s %s", userDisplay, message)); //$NON-NLS-1$
|
|
}
|
|
|
|
String original = context.getString(commentResource, userDisplay, targetName, message);
|
|
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(context, activity, targetName, 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;
|
|
}
|
|
|
|
public static String getHistoryComment(final AstridActivity context, History history, User user, String linkColor, String fromView) {
|
|
boolean hasTask = false;
|
|
JSONArray taskAttrs = null;
|
|
if (!TextUtils.isEmpty(history.getValue(History.TASK))) {
|
|
try {
|
|
taskAttrs = new JSONArray(history.getValue(History.TASK));
|
|
hasTask = true;
|
|
} catch (JSONException e) {
|
|
//
|
|
}
|
|
}
|
|
|
|
String item;
|
|
String itemPosessive;
|
|
if (FROM_TASK_VIEW.equals(fromView)) {
|
|
item = context.getString(R.string.history_this_task);
|
|
} else if (hasTask && taskAttrs != null) {
|
|
item = taskAttrs.optString(1);
|
|
} else {
|
|
item = context.getString(R.string.history_this_list);
|
|
}
|
|
itemPosessive = item + "'s";
|
|
|
|
String oldValue = history.getValue(History.OLD_VALUE);
|
|
String newValue = history.getValue(History.NEW_VALUE);
|
|
|
|
String result = "";
|
|
String column = history.getValue(History.COLUMN);
|
|
try {
|
|
if (History.COL_TAG_ADDED.equals(column) || History.COL_TAG_REMOVED.equals(column)) {
|
|
JSONArray tagObj = new JSONArray(newValue);
|
|
String tagName = tagObj.getString(1);
|
|
if (History.COL_TAG_ADDED.equals(column)) {
|
|
result = context.getString(R.string.history_tag_added, item, tagName);
|
|
} else {
|
|
result = context.getString(R.string.history_tag_removed, item, tagName);
|
|
}
|
|
|
|
} else if (History.COL_ATTACHMENT_ADDED.equals(column) || History.COL_ATTACHMENT_REMOVED.equals(column)) {
|
|
JSONArray attachmentArray = new JSONArray(newValue);
|
|
String attachmentName = attachmentArray.getString(0);
|
|
if (History.COL_ATTACHMENT_ADDED.equals(column)) {
|
|
result = context.getString(R.string.history_attach_added, attachmentName, item);
|
|
} else {
|
|
result = context.getString(R.string.history_attach_removed, attachmentName, item);
|
|
}
|
|
} else if (History.COL_ACKNOWLEDGED.equals(column)) {
|
|
result = context.getString(R.string.history_acknowledged, item);
|
|
} else if (History.COL_SHARED_WITH.equals(column) || History.COL_UNSHARED_WITH.equals(column)) {
|
|
JSONArray members = new JSONArray(newValue);
|
|
String userId = history.getValue(History.USER_UUID);
|
|
StringBuilder memberList = new StringBuilder();
|
|
for (int i = 0; i < members.length(); i++) {
|
|
JSONObject m = members.getJSONObject(i);
|
|
memberList.append(userDisplay(context, userId, m));
|
|
if (i != members.length() - 1) {
|
|
memberList.append(", ");
|
|
}
|
|
}
|
|
|
|
if (History.COL_SHARED_WITH.equals(column)) {
|
|
result = context.getString(R.string.history_shared_with, item, memberList);
|
|
} else {
|
|
result = context.getString(R.string.history_unshared_with, item, memberList);
|
|
}
|
|
} else if (History.COL_MEMBER_ADDED.equals(column) || History.COL_MEMBER_REMOVED.equals(column)) {
|
|
JSONObject userValue = new JSONObject(newValue);
|
|
if (history.getValue(History.USER_UUID).equals(userValue.optString("id")) && History.COL_MEMBER_REMOVED.equals(column)) {
|
|
result = context.getString(R.string.history_left_list, item);
|
|
} else {
|
|
String userDisplay = userDisplay(context, history.getValue(History.USER_UUID), userValue);
|
|
if (History.COL_MEMBER_ADDED.equals(column)) {
|
|
result = context.getString(R.string.history_added_user, userDisplay, item);
|
|
} else {
|
|
result = context.getString(R.string.history_removed_user, userDisplay, item);
|
|
}
|
|
}
|
|
} else if (History.COL_COMPLETED_AT.equals(column)) {
|
|
if (!TextUtils.isEmpty(newValue) && !"null".equals(newValue)) {
|
|
result = context.getString(R.string.history_completed, item);
|
|
} else {
|
|
result = context.getString(R.string.history_uncompleted, item);
|
|
}
|
|
} else if (History.COL_DELETED_AT.equals(column)) {
|
|
if (!TextUtils.isEmpty(newValue) && !"null".equals(newValue)) {
|
|
result = context.getString(R.string.history_deleted, item);
|
|
} else {
|
|
result = context.getString(R.string.history_undeleted, item);
|
|
}
|
|
} else if (History.COL_IMPORTANCE.equals(column)) {
|
|
int oldPriority = AndroidUtilities.tryParseInt(oldValue, 0);
|
|
int newPriority = AndroidUtilities.tryParseInt(newValue, 0);
|
|
|
|
result = context.getString(R.string.history_importance_changed, itemPosessive, priorityString(oldPriority), priorityString(newPriority));
|
|
} else if (History.COL_NOTES_LENGTH.equals(column)) {
|
|
int oldLength = AndroidUtilities.tryParseInt(oldValue, 0);
|
|
int newLength = AndroidUtilities.tryParseInt(newValue, 0);
|
|
|
|
if (oldLength > 0 && newLength > oldLength) {
|
|
result = context.getString(R.string.history_added_description_characters, (newLength - oldLength), itemPosessive);
|
|
} else if (newLength == 0) {
|
|
result = context.getString(R.string.history_removed_description, itemPosessive);
|
|
} else if (oldLength > 0 && newLength < oldLength) {
|
|
result = context.getString(R.string.history_removed_description_characters, (oldLength - newLength), itemPosessive);
|
|
} else if (oldLength > 0 && oldLength == newLength) {
|
|
result = context.getString(R.string.history_updated_description, itemPosessive);
|
|
}
|
|
} else if (History.COL_PUBLIC.equals(column)) {
|
|
int value = AndroidUtilities.tryParseInt(newValue, 0);
|
|
if (value > 0) {
|
|
result = context.getString(R.string.history_made_public, item);
|
|
} else {
|
|
result = context.getString(R.string.history_made_private, item);
|
|
}
|
|
} else if (History.COL_DUE.equals(column)) {
|
|
if (!TextUtils.isEmpty(oldValue) && !TextUtils.isEmpty(newValue)
|
|
&& !"null".equals(oldValue) && !"null".equals(newValue)) {
|
|
result = context.getString(R.string.history_changed_due_date, itemPosessive, dateString(context, oldValue, newValue), dateString(context, newValue, oldValue));
|
|
} else if (!TextUtils.isEmpty(newValue) && !"null".equals(newValue)) {
|
|
result = context.getString(R.string.history_set_due_date, itemPosessive, dateString(context, newValue, DateUtilities.timeToIso8601(DateUtilities.now(), true)));
|
|
} else {
|
|
result = context.getString(R.string.history_removed_due_date, itemPosessive);
|
|
}
|
|
} else if (History.COL_REPEAT.equals(column)) {
|
|
String repeatString = getRepeatString(context, newValue);
|
|
if (!TextUtils.isEmpty(repeatString)) {
|
|
result = context.getString(R.string.history_changed_repeat, itemPosessive, repeatString);
|
|
} else {
|
|
result = context.getString(R.string.history_removed_repeat, itemPosessive);
|
|
}
|
|
} else if (History.COL_TASK_REPEATED.equals(column)) {
|
|
result = context.getString(R.string.history_completed_repeating_task, item, dateString(context, newValue, oldValue));
|
|
} else if (History.COL_TITLE.equals(column)) {
|
|
if (!TextUtils.isEmpty(oldValue) && !"null".equals(oldValue)) {
|
|
result = context.getString(R.string.history_title_changed, itemPosessive, oldValue, newValue);
|
|
} else {
|
|
result = context.getString(R.string.history_title_set, itemPosessive, newValue);
|
|
}
|
|
} else if (History.COL_NAME.equals(column)) {
|
|
if (!TextUtils.isEmpty(oldValue) && !"null".equals(oldValue)) {
|
|
result = context.getString(R.string.history_name_changed, oldValue, newValue);
|
|
} else {
|
|
result = context.getString(R.string.history_name_set, newValue);
|
|
}
|
|
} else if (History.COL_DESCRIPTION.equals(column)) {
|
|
if (!TextUtils.isEmpty(oldValue) && !"null".equals(oldValue)) {
|
|
result = context.getString(R.string.history_description_changed, oldValue, newValue);
|
|
} else {
|
|
result = context.getString(R.string.history_description_set, newValue);
|
|
}
|
|
} else if (History.COL_PICTURE_ID.equals(column) || History.COL_DEFAULT_LIST_IMAGE_ID.equals(column)) {
|
|
result = context.getString(R.string.history_changed_list_picture);
|
|
} else if (History.COL_IS_SILENT.equals(column)) {
|
|
int value = AndroidUtilities.tryParseInt(newValue, 0);
|
|
if (value > 0) {
|
|
result = context.getString(R.string.history_silenced, item);
|
|
} else {
|
|
result = context.getString(R.string.history_unsilenced, item);
|
|
}
|
|
} else if (History.COL_IS_FAVORITE.equals(column)) {
|
|
int value = AndroidUtilities.tryParseInt(newValue, 0);
|
|
if (value > 0) {
|
|
result = context.getString(R.string.history_favorited, item);
|
|
} else {
|
|
result = context.getString(R.string.history_unfavorited, item);
|
|
}
|
|
} else if (History.COL_USER_ID.equals(column)) {
|
|
String userId = history.getValue(History.USER_UUID);
|
|
JSONObject userValue = new JSONObject(newValue);
|
|
if (FROM_TAG_VIEW.equals(fromView) && !hasTask) {
|
|
if (!TextUtils.isEmpty(oldValue) && !"null".equals(oldValue)) {
|
|
result = context.getString(R.string.history_changed_list_owner, userDisplay(context, userId, userValue));
|
|
} else {
|
|
result = context.getString(R.string.history_created_this_list);
|
|
}
|
|
} else if (!TextUtils.isEmpty(oldValue) && !"null".equals(oldValue) && Task.USER_ID_UNASSIGNED.equals(userValue)) {
|
|
result = context.getString(R.string.history_unassigned, item);
|
|
} else if (Task.USER_ID_UNASSIGNED.equals(oldValue) && userValue.optString("id").equals(ActFmPreferenceService.userId())) {
|
|
result = context.getString(R.string.history_claimed, item);
|
|
} else if (!TextUtils.isEmpty(oldValue) && !"null".equals(oldValue)) {
|
|
result = context.getString(R.string.history_assigned_to, item, userDisplay(context, userId, userValue));
|
|
} else if (!userValue.optString("id").equals(ActFmPreferenceService.userId()) && !Task.USER_ID_UNASSIGNED.equals(userValue.optString("id"))) {
|
|
result = context.getString(R.string.history_created_for, item, userDisplay(context, userId, userValue));
|
|
} else {
|
|
result = context.getString(R.string.history_created, item);
|
|
}
|
|
} else {
|
|
result = context.getString(R.string.history_default, column, newValue);
|
|
}
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
result = context.getString(R.string.history_default, column, newValue);
|
|
}
|
|
|
|
if (TextUtils.isEmpty(result)) {
|
|
result = context.getString(R.string.history_default, column, newValue);
|
|
}
|
|
|
|
String userDisplay;
|
|
if (history.getValue(History.USER_UUID).equals(Task.USER_ID_SELF) || history.getValue(History.USER_UUID).equals(ActFmPreferenceService.userId())) {
|
|
userDisplay = context.getString(R.string.update_string_user_self);
|
|
} else if (user == null) {
|
|
userDisplay = context.getString(R.string.ENA_no_user);
|
|
} else {
|
|
userDisplay = user.getDisplayName(USER_NAME, USER_FIRST_NAME, USER_LAST_NAME);
|
|
}
|
|
|
|
return userDisplay + " " + result;
|
|
}
|
|
|
|
private static String dateString(Context context, String value, String other) {
|
|
boolean includeYear = (!TextUtils.isEmpty(other) && !value.substring(0, 4).equals(other.substring(0, 4)));
|
|
boolean hasTime = DateUtilities.isoStringHasTime(value);
|
|
|
|
long time = 0;
|
|
try {
|
|
time = DateUtilities.parseIso8601(value);
|
|
Date date = new Date(time);
|
|
String result = DateUtilities.getDateString(context, date, includeYear);
|
|
if (hasTime) {
|
|
result += ", " + DateUtilities.getTimeString(context, date, false); //$NON-NLS-1$
|
|
}
|
|
return result;
|
|
} catch (ParseException e) {
|
|
return value;
|
|
}
|
|
|
|
}
|
|
|
|
private static final HashMap<String, Integer> INTERVAL_LABELS = new HashMap<String, Integer>();
|
|
static {
|
|
INTERVAL_LABELS.put("DAILY", R.string.repeat_days); //$NON-NLS-1$
|
|
INTERVAL_LABELS.put("WEEKDAYS", R.string.repeat_weekdays); //$NON-NLS-1$
|
|
INTERVAL_LABELS.put("WEEKLY", R.string.repeat_weeks); //$NON-NLS-1$
|
|
INTERVAL_LABELS.put("MONTHLY", R.string.repeat_months); //$NON-NLS-1$
|
|
INTERVAL_LABELS.put("YEARLY", R.string.repeat_years); //$NON-NLS-1$
|
|
INTERVAL_LABELS.put("HOURLY", R.string.repeat_hours); //$NON-NLS-1$
|
|
INTERVAL_LABELS.put("MINUTELY", R.string.repeat_minutes); //$NON-NLS-1$
|
|
}
|
|
|
|
private static final String[] SORTED_WEEKDAYS = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" };
|
|
|
|
private static String getRepeatString(Context context, String value) {
|
|
if (TextUtils.isEmpty(value) || "null".equals(value)) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
JSONObject repeat = new JSONObject(value);
|
|
boolean weekdays = false;
|
|
if (repeat.has("freq")) {
|
|
String freq = repeat.getString("freq");
|
|
int interval = repeat.getInt("interval");
|
|
JSONArray byDay = repeat.optJSONArray("byday");
|
|
String[] byDayStrings = null;
|
|
if (byDay != null) {
|
|
byDayStrings = new String[byDay.length()];
|
|
for (int i = 0; i < byDay.length(); i++) {
|
|
byDayStrings[i] = byDay.getString(i);
|
|
}
|
|
}
|
|
String result = "";
|
|
if ("WEEKLY".equals(freq) && byDay != null && byDayStrings != null) {
|
|
Arrays.sort(byDayStrings);
|
|
StringBuilder daysString = new StringBuilder();
|
|
daysString.append("[");
|
|
for (String s : byDayStrings) {
|
|
daysString.append("\"").append(s).append("\"").append(",");
|
|
}
|
|
daysString.deleteCharAt(daysString.length() - 1);
|
|
daysString.append("]");
|
|
|
|
if (daysString.toString().equals("[\"FR\",\"MO\",\"TH\",\"TU\",\"WE\"]")) {
|
|
result = context.getString(R.string.repeat_weekdays);
|
|
weekdays = true;
|
|
}
|
|
}
|
|
|
|
if (!weekdays) {
|
|
if (interval == 1) {
|
|
result = context.getString(INTERVAL_LABELS.get(freq));
|
|
result = result.substring(0, result.length() - 1);
|
|
} else {
|
|
result = interval + " " + context.getString(INTERVAL_LABELS.get(freq));
|
|
}
|
|
}
|
|
|
|
result = context.getString(R.string.history_repeat_every, result);
|
|
if ("WEEKLY".equals(freq) && !weekdays && byDay != null && byDay.length() > 0 && byDayStrings != null) {
|
|
Arrays.sort(byDayStrings, new Comparator<String>() {
|
|
@Override
|
|
public int compare(String lhs, String rhs) {
|
|
int lhIndex = AndroidUtilities.indexOf(SORTED_WEEKDAYS, lhs);
|
|
int rhIndex = AndroidUtilities.indexOf(SORTED_WEEKDAYS, rhs);
|
|
if (lhIndex < rhIndex) {
|
|
return -1;
|
|
} else if (lhIndex > rhIndex) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
});
|
|
|
|
StringBuilder byDayDisplay = new StringBuilder();
|
|
for (String s : byDayStrings) {
|
|
byDayDisplay.append(s).append(", ");
|
|
}
|
|
byDayDisplay.delete(byDayDisplay.length() - 2, byDayDisplay.length());
|
|
|
|
result += (" " + context.getString(R.string.history_repeat_on, byDayDisplay.toString()));
|
|
}
|
|
|
|
if ("COMPLETION".equals(repeat.optString("from"))) {
|
|
result += (" " + context.getString(R.string.history_repeat_from_completion));
|
|
}
|
|
|
|
return result;
|
|
} else {
|
|
return null;
|
|
}
|
|
} catch (JSONException e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static String userDisplay(Context context, String historyUserId, JSONObject userJson) {
|
|
try {
|
|
String id = userJson.getString("id");
|
|
String name = userJson.getString("name");
|
|
|
|
if (historyUserId.equals(id) && ActFmPreferenceService.userId().equals(id)) {
|
|
return context.getString(R.string.history_yourself);
|
|
} else if (ActFmPreferenceService.userId().equals(id)) {
|
|
return context.getString(R.string.history_you);
|
|
} else if (RemoteModel.isValidUuid(id)) {
|
|
return name;
|
|
} else {
|
|
return context.getString(R.string.history_a_deleted_user);
|
|
}
|
|
} catch (JSONException e) {
|
|
return context.getString(R.string.ENA_no_user).toLowerCase();
|
|
}
|
|
}
|
|
|
|
private static final String[] PRIORITY_STRINGS = { "!!!", "!!", "!", "o" };
|
|
private static String priorityString(int priority) {
|
|
return PRIORITY_STRINGS[priority];
|
|
}
|
|
|
|
private static CharSequence getLinkSpan(final AstridActivity activity, UserActivity update, String targetName, String linkColor, String linkType) {
|
|
if (TASK_LINK_TYPE.equals(linkType)) {
|
|
final String taskId = update.getValue(UserActivity.TARGET_ID);
|
|
if (RemoteModel.isValidUuid(taskId)) {
|
|
SpannableString taskSpan = new SpannableString(targetName);
|
|
taskSpan.setSpan(new ClickableSpan() {
|
|
@Override
|
|
public void onClick(View widget) {
|
|
if (activity != null) // TODO: This shouldn't happen, but sometimes does
|
|
{
|
|
activity.onTaskListItemClicked(taskId);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void updateDrawState(TextPaint ds) {
|
|
super.updateDrawState(ds);
|
|
ds.setUnderlineText(false);
|
|
}
|
|
}, 0, targetName.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
return taskSpan;
|
|
} else {
|
|
return Html.fromHtml(linkify(targetName, linkColor));
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|