Pushing queued updates and enabling commenting while offline

pull/14/head
Andrew Shaw 13 years ago
parent f7b2405e8a
commit f1595129c7

@ -47,10 +47,18 @@ public class Update extends RemoteModel {
public static final LongProperty TASK = new LongProperty(
TABLE, "task");
/** Associated Task local-id (if any) */
public static final LongProperty TASK_LOCAL = new LongProperty(
TABLE, "taskLocal");
/** Associated Tag remote-ids (comma separated list with leading and trailing commas) */
public static final StringProperty TAGS = new StringProperty(
TABLE, "tag");
/** Associated Tag local-ids (comma separated list with leading and trailing commas) */
public static final StringProperty TAGS_LOCAL = new StringProperty(
TABLE, "tagsLocal");
/** From user id */
public static final LongProperty USER_ID = new LongProperty(
TABLE, USER_ID_PROPERTY_NAME);
@ -103,7 +111,9 @@ public class Update extends RemoteModel {
static {
defaultValues.put(REMOTE_ID.name, 0);
defaultValues.put(TASK.name, 0);
defaultValues.put(TASK_LOCAL.name, 0);
defaultValues.put(TAGS.name, "");
defaultValues.put(TAGS_LOCAL.name, 0);
defaultValues.put(USER_ID.name, 0);
defaultValues.put(USER.name, "");
defaultValues.put(ACTION.name, "");

@ -10,6 +10,7 @@ import android.support.v4.view.Menu;
import android.support.v4.view.MenuItem;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuInflater;
@ -40,6 +41,7 @@ import com.todoroo.astrid.dao.UpdateDao;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.Update;
import com.todoroo.astrid.helper.ImageDiskCache;
import com.todoroo.astrid.helper.ProgressBarSyncResultCallback;
import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService;
@ -63,6 +65,8 @@ public class TagUpdatesFragment extends ListFragment {
private static final int MENU_REFRESH_ID = Menu.FIRST;
private final ImageDiskCache imageCache;
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired TagDataService tagDataService;
@Autowired UpdateDao updateDao;
@ -70,6 +74,7 @@ public class TagUpdatesFragment extends ListFragment {
public TagUpdatesFragment() {
DependencyInjectionService.getInstance().inject(this);
imageCache = ImageDiskCache.getInstance();
}
public TagUpdatesFragment(TagData tagData) {
@ -181,9 +186,6 @@ public class TagUpdatesFragment extends ListFragment {
private void refreshUpdatesList() {
if(tagData != null && tagData.getValue(Task.REMOTE_ID) <= 0)
return;
if(updateAdapter == null) {
TodorooCursor<Update> currentCursor = tagDataService.getUpdates(tagData);
getActivity().startManagingCursor(currentCursor);
@ -197,7 +199,7 @@ public class TagUpdatesFragment extends ListFragment {
getActivity().startManagingCursor(cursor);
}
if (tagData != null) {
if(tagData != null && tagData.getValue(Task.REMOTE_ID) <= 0) {
Preferences.setLong(UPDATES_LAST_VIEWED + tagData.getValue(TagData.REMOTE_ID), DateUtilities.now());
}
}
@ -258,19 +260,31 @@ public class TagUpdatesFragment extends ListFragment {
}
}
private String getPictureHashForUpdate(Update u) {
String s = u.getValue(Update.TASK) + "" + u.getValue(Update.CREATION_DATE);
return s;
}
@SuppressWarnings("nls")
private void addComment() {
if(tagData.getValue(TagData.REMOTE_ID) == 0L)
return;
Update update = new Update();
update.setValue(Update.MESSAGE, addCommentField.getText().toString());
update.setValue(Update.ACTION_CODE, "tag_comment");
update.setValue(Update.USER_ID, 0L);
update.setValue(Update.TAGS, "," + tagData.getValue(TagData.REMOTE_ID) + ",");
update.setValue(Update.TAGS_LOCAL, "," + tagData.getId() + ",");
update.setValue(Update.CREATION_DATE, DateUtilities.now());
if (picture != null) {
update.setValue(Update.PICTURE, Update.PICTURE_LOADING);
try {
String updateString = getPictureHashForUpdate(update);
imageCache.put(updateString, picture);
update.setValue(Update.PICTURE, updateString);
}
catch (Exception e) {
Log.e("EditNoteActivity", "Failed to put image to disk...");
}
}
Flags.set(Flags.ACTFM_SUPPRESS_SYNC);
updateDao.createNew(update);

@ -55,6 +55,7 @@ import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskApiDao;
import com.todoroo.astrid.data.Update;
import com.todoroo.astrid.helper.ImageDiskCache;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService;
@ -268,9 +269,14 @@ public final class ActFmSyncService {
else
result = actFmInvoker.post("comment_add", picture, params.toArray(new Object[params.size()]));
update.setValue(Update.REMOTE_ID, result.optLong("id"));
// ImageCache imageCache = ImageCache.getInstance(getContext());
ImageDiskCache imageCache = ImageDiskCache.getInstance();
//TODO figure out a way to replace local image files with the url
if (TextUtils.isEmpty(update.getValue(Update.PICTURE)) || update.getValue(Update.PICTURE).equals(Update.PICTURE_LOADING)) {
String commentPicture = result.optString("picture");
if (!TextUtils.isEmpty(commentPicture)) {
String cachedPicture = update.getValue(Update.PICTURE);
if (!TextUtils.isEmpty(cachedPicture) && imageCache.contains(cachedPicture)) {
imageCache.move(update.getValue(Update.PICTURE), commentPicture);
}
update.setValue(Update.PICTURE, result.optString("picture"));
}
@ -650,7 +656,7 @@ public final class ActFmSyncService {
if(task.getValue(TagData.REMOTE_ID) == 0)
return;
result = actFmInvoker.invoke("task_show", "id", task.getValue(Task.REMOTE_ID),
"token", token);
"token", token);
ArrayList<Metadata> metadata = new ArrayList<Metadata>();
JsonHelper.taskFromJson(result, task, metadata);
@ -780,6 +786,8 @@ public final class ActFmSyncService {
}, done, "tasks:" + tagData.getId(), "tag_id", tagData.getValue(TagData.REMOTE_ID));
}
/**
* Fetch updates for the given tagData asynchronously
* @param tagData
@ -789,6 +797,8 @@ public final class ActFmSyncService {
public void fetchUpdatesForTag(final TagData tagData, final boolean manual, Runnable done) {
invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done,
"updates:" + tagData.getId(), "tag_id", tagData.getValue(TagData.REMOTE_ID));
pushQueuedUpdates(tagData);
}
/**
@ -800,6 +810,8 @@ public final class ActFmSyncService {
public void fetchUpdatesForTask(final Task task, boolean manual, Runnable done) {
invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done,
"comments:" + task.getId(), "task_id", task.getValue(Task.REMOTE_ID));
pushQueuedUpdates(task);
}
/**
@ -809,8 +821,93 @@ public final class ActFmSyncService {
*/
public void fetchPersonalUpdates(boolean manual, Runnable done) {
invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done, "personal");
}
private void pushQueuedUpdates(TagData tagData) {
Criterion criterion = null;
if (tagData.getValue(TagData.REMOTE_ID) < 1) {
criterion = Criterion.and(Update.REMOTE_ID.eq(0),
Update.TAGS_LOCAL.like("%," + tagData.getId() + ",%"));
}
else {
criterion = Criterion.and(Update.REMOTE_ID.eq(0),
Criterion.or(Update.TAGS.like("%," + tagData.getValue(TagData.REMOTE_ID) + ",%"),
Update.TAGS_LOCAL.like("%," + tagData.getId() + ",%")));
}
Update template = new Update();
template.setValue(Update.TAGS, "," + tagData.getValue(TagData.REMOTE_ID) + ",");
updateDao.update(criterion, template);
TodorooCursor<Update> cursor = updateDao.query(Query.select(Update.ID, Update.PICTURE).where(criterion));
pushQueuedUpdates(cursor);
Log.d("ActFmSyncService", "Push queued updates for tag");
}
private void pushQueuedUpdates(Task task) {
Criterion criterion = null;
if (task.getValue(Task.REMOTE_ID) < 1) {
criterion = Criterion.and(Update.REMOTE_ID.eq(0),
Update.TASK_LOCAL.eq(task.getId()));
}
else {
criterion = Criterion.and(Update.REMOTE_ID.eq(0),
Criterion.or(Update.TASK.eq(task.getValue(Task.REMOTE_ID)), Update.TASK_LOCAL.eq(task.getId())));
}
Update template = new Update();
template.setValue(Update.TASK, task.getValue(Task.REMOTE_ID)); //$NON-NLS-1$
updateDao.update(criterion, template);
TodorooCursor<Update> cursor = updateDao.query(Query.select(Update.ID, Update.PICTURE).where(criterion));
pushQueuedUpdates(cursor);
Log.d("ActFmSyncService", "Push queued updates for task");
}
private void pushQueuedUpdates( TodorooCursor<Update> cursor) {
try {
final ImageDiskCache imageCache = ImageDiskCache.getInstance();
for(int i = 0; i < cursor.getCount(); i++) {
cursor.moveToNext();
final Update update = new Update(cursor);
new Thread(new Runnable() {
public void run() {
try {
Bitmap picture = null;
if(imageCache != null && imageCache.contains(update.getValue(update.PICTURE))) {
try {
picture = imageCache.get(update.getValue(update.PICTURE));
} catch (IOException e) {
e.printStackTrace();
}
}
pushUpdate(update.getId(), picture);
} finally {
}
}
}).start();
}
} finally {
cursor.close();
}
}
private class UpdateListItemProcessor extends ListItemProcessor<Update> {
@Override
protected void mergeAndSave(JSONArray list, HashMap<Long,Long> locals) throws JSONException {
@ -871,7 +968,7 @@ public final class ActFmSyncService {
/** invoke authenticated method against the server */
public JSONObject invoke(String method, Object... getParameters) throws IOException,
ActFmServiceException {
ActFmServiceException {
if(!checkForToken())
throw new ActFmServiceException("not logged in");
Object[] parameters = new Object[getParameters.length + 2];
@ -935,6 +1032,8 @@ public final class ActFmSyncService {
}
/** Call sync method */
private void invokeFetchList(final String model, final boolean manual, final SyncExceptionHandler handler,
final ListItemProcessor<?> processor, final Runnable done, final String lastSyncKey,

@ -11,6 +11,8 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.json.JSONException;
import android.graphics.Bitmap;
import com.timsu.astrid.C2DMReceiver;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
@ -23,6 +25,8 @@ import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.Update;
import com.todoroo.astrid.helper.ImageDiskCache;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.service.TaskService;
@ -287,7 +291,7 @@ public class ActFmSyncV2Provider extends SyncV2Provider {
}).start();
}
private void fetchUpdatesForTag(TagData tagData, boolean manual, final SyncResultCallback callback,
private void fetchUpdatesForTag(final TagData tagData, boolean manual, final SyncResultCallback callback,
final AtomicInteger finisher) {
actFmSyncService.fetchUpdatesForTag(tagData, manual, new Runnable() {
@Override
@ -299,7 +303,7 @@ public class ActFmSyncV2Provider extends SyncV2Provider {
});
}
private void fetchTasksForTag(TagData tagData, boolean manual, final SyncResultCallback callback,
private void fetchTasksForTag(final TagData tagData, boolean manual, final SyncResultCallback callback,
final AtomicInteger finisher) {
actFmSyncService.fetchTasksForTag(tagData, manual, new Runnable() {
@Override

@ -40,6 +40,7 @@ import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
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.Preferences;
@ -54,7 +55,7 @@ import com.todoroo.astrid.dao.UpdateDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.Update;
import com.todoroo.astrid.helper.ImageCache;
import com.todoroo.astrid.helper.ImageDiskCache;
import com.todoroo.astrid.helper.ProgressBarSyncResultCallback;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.StatisticsConstants;
@ -88,7 +89,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
private ImageButton pictureButton;
private Bitmap pendingCommentPicture = null;
private final Fragment fragment;
private final ImageCache imageCache;
private final ImageDiskCache imageCache;
private final int cameraButton;
private final List<UpdatesChangedListener> listeners = new LinkedList<UpdatesChangedListener>();
@ -101,7 +102,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
public EditNoteActivity(Fragment fragment, View parent, long t) {
super(fragment.getActivity());
imageCache = ImageCache.getInstance(fragment.getActivity());
imageCache = ImageDiskCache.getInstance();
this.fragment = fragment;
cameraButton = getDefaultCameraButton();
@ -254,20 +255,25 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
notes.close();
}
if(task.getValue(Task.REMOTE_ID) > 0) {
TodorooCursor<Update> updates = updateDao.query(Query.select(Update.PROPERTIES).where(
Update.TASK.eq(task.getValue(Task.REMOTE_ID))));
try {
Update update = new Update();
for(updates.moveToFirst(); !updates.isAfterLast(); updates.moveToNext()) {
update.readFromCursor(updates);
NoteOrUpdate noa = NoteOrUpdate.fromUpdate(update);
if(noa != null)
items.add(noa);
}
} finally {
updates.close();
TodorooCursor<Update> updates;
if (task.getValue(Task.REMOTE_ID) < 1) {
updates = updateDao.query(Query.select(Update.PROPERTIES).where(Update.TASK_LOCAL.eq(task.getId())));
}
else {
updates = updateDao.query(Query.select(Update.PROPERTIES).where(Criterion.or(
Update.TASK.eq(task.getValue(Task.REMOTE_ID)), Update.TASK_LOCAL.eq(task.getId()))));
}
try {
Update update = new Update();
for(updates.moveToFirst(); !updates.isAfterLast(); updates.moveToNext()) {
update.readFromCursor(updates);
NoteOrUpdate noa = NoteOrUpdate.fromUpdate(update);
if(noa != null)
items.add(noa);
}
} finally {
updates.close();
}
Collections.sort(items, new Comparator<NoteOrUpdate>() {
@ -331,17 +337,19 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
public synchronized void bindView(View view, NoteOrUpdate item) {
// picture
final AsyncImageView pictureView = (AsyncImageView)view.findViewById(R.id.picture); {
if(TextUtils.isEmpty(item.picture))
pictureView.setVisibility(View.GONE);
else {
pictureView.setVisibility(View.VISIBLE);
pictureView.setUrl(item.picture);
}
pictureView.setDefaultImageResource(R.drawable.icn_default_person_image);
pictureView.setUrl(item.picture);
}
// name
final TextView nameView = (TextView)view.findViewById(R.id.title); {
nameView.setText(item.title);
if (TextUtils.isEmpty(item.title)) {
nameView.setText(fragment.getActivity().getString(R.string.ENA_no_user));
}
else {
nameView.setText(item.title);
}
}
// description
@ -438,6 +446,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
update.setValue(Update.ACTION_CODE, actionCode);
update.setValue(Update.USER_ID, 0L);
update.setValue(Update.TASK, task.getValue(Task.REMOTE_ID));
update.setValue(Update.TASK_LOCAL, task.getId());
update.setValue(Update.CREATION_DATE, DateUtilities.now());
if (usePicture && pendingCommentPicture != null) {

@ -64,24 +64,6 @@
android:orientation="vertical" >
</LinearLayout>
<LinearLayout
android:id="@+id/more_header"
style="@style/EditRow"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:visibility="gone">
-
<TextView
style="@style/TextAppearance.EditRowDisplay"
android:layout_width="fill_parent"
android:layout_height="50dip"
android:layout_gravity="center_vertical"
android:gravity="center"
android:text="@string/TEA_more"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="@+id/more_container"

@ -86,6 +86,9 @@
<!-- EditNoteActivity - no comments -->
<string name="ENA_no_comments">Nothing To Show</string>
<!-- EditNoteActivity - no username for comment -->
<string name="ENA_no_user">You</string>
<!-- EditNoteActivity - refresh comments -->
<string name="ENA_refresh_comments">Refresh Comments</string>

@ -51,8 +51,6 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewParent;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
@ -140,10 +138,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
*/
private static final String TASK_REMOTE_ID = "task_remote_id"; //$NON-NLS-1$
/**
* Task remote id (during orientation change)
*/
private static final String MORE_EXPANDED = "more_expanded"; //$NON-NLS-1$
/**
* Tab to start on
@ -248,7 +242,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
private long remoteId = 0;
private boolean moreExpanded = false;
private WebServicesView webServices = null;
@ -304,9 +297,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
if (savedInstanceState.containsKey(TASK_REMOTE_ID)) {
remoteId = savedInstanceState.getLong(TASK_REMOTE_ID);
}
if (savedInstanceState.containsKey(MORE_EXPANDED)) {
moreExpanded = savedInstanceState.getBoolean(MORE_EXPANDED);
}
}
@ -361,51 +351,43 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
overrideFinishAnim = false;
if (activity != null) {
if (activity.getIntent() != null)
overrideFinishAnim = activity.getIntent().getBooleanExtra(
OVERRIDE_FINISH_ANIM, true);
overrideFinishAnim = activity.getIntent().getBooleanExtra(
OVERRIDE_FINISH_ANIM, true);
}
}
private void loadMoreContainer() {
View moreSection = (View) getView().findViewById(R.id.more_header);
View moreTab = (View) getView().findViewById(R.id.more_container);
View commentsBar = (View) getView().findViewById(R.id.updatesFooter);
long idParam = getActivity().getIntent().getLongExtra(TOKEN_ID, -1L);
boolean hasTitle = !TextUtils.isEmpty(model.getValue(Task.TITLE));
boolean hasRemoteId = remoteId > 0 && idParam > -1L;
if(hasTitle && hasRemoteId)
if(hasTitle)
tabStyle = TAB_STYLE_ACTIVITY_WEB;
else if(hasTitle)
tabStyle = TAB_STYLE_WEB;
else if(hasRemoteId)
tabStyle = TAB_STYLE_ACTIVITY;
else
tabStyle = TAB_STYLE_NONE;
tabStyle = TAB_STYLE_ACTIVITY;
if (hasRemoteId) {
if (editNotes == null) {
editNotes = new EditNoteActivity(this, getView(),
idParam);
editNotes.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
if (editNotes == null) {
editNotes = new EditNoteActivity(this, getView(),
idParam);
editNotes.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
editNotes.addListener(this);
if (timerAction != null) {
timerAction.addListener(editNotes);
}
}
else {
editNotes.loadViewForTaskID(idParam);
editNotes.addListener(this);
if (timerAction != null) {
timerAction.addListener(editNotes);
}
}
else {
editNotes.loadViewForTaskID(idParam);
}
editNotes.addListener(this);
editNotes.addListener(this);
Handler refreshHandler = new Handler();
refreshHandler.postDelayed(refreshActivity, 1000);
}
Handler refreshHandler = new Handler();
refreshHandler.postDelayed(refreshActivity, 1000);
if(hasTitle) {
if(webServices == null) {
@ -420,7 +402,7 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
}
}
if(tabStyle != TAB_STYLE_NONE) {
mAdapter = new TaskEditViewPager(getActivity(), tabStyle);
mAdapter.parent = this;
@ -437,24 +419,7 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
}
commentsBar.setVisibility(View.VISIBLE);
moreSection.setVisibility(View.GONE);
moreTab.setVisibility(View.VISIBLE);
} else {
moreSection.setVisibility(View.VISIBLE);
commentsBar.setVisibility(View.GONE);
if (moreControls.getParent() != null) {
if (moreControls.getParent() == moreSection) {
setPagerHeightForPosition(TAB_VIEW_MORE);
}
else {
((ViewGroup) moreControls.getParent()).removeView(moreControls);
}
}
if (moreExpanded)
autoExpandMore();
}
}
private void setCurrentTab(int position) {
@ -658,40 +623,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
}
}
/** Set up button listeners */
private void setUpListeners() {
final View.OnClickListener mExpandMoreListener = new View.OnClickListener() {
final Animation fadeIn = AnimationUtils.loadAnimation(
getActivity(), android.R.anim.fade_in);
final Animation fadeOut = AnimationUtils.loadAnimation(
getActivity(), android.R.anim.fade_out);
@Override
public void onClick(View v) {
fadeIn.setDuration(300);
fadeOut.setDuration(300);
autoExpandMore();
}
};
// set up save, cancel, and delete buttons
try {
getView().findViewById(R.id.more_header).setOnClickListener(
mExpandMoreListener);
} catch (Exception e) {
// error loading the proper activity
}
}
private void autoExpandMore() {
moreExpanded = true;
LinearLayout moreHeader = (LinearLayout) getView().findViewById(
R.id.more_header);
moreHeader.removeAllViews();
moreHeader.addView(moreControls);
moreHeader.setOnClickListener(null);
}
private void constructWhenDialog(View whenDialogView) {
int theme = ThemeService.getEditDialogTheme();
whenDialog = new Dialog(getActivity(), theme);
@ -760,8 +691,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
}
});
// set up listeners
setUpListeners();
}
}
@ -835,7 +764,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
public void repopulateFromScratch(Intent intent) {
model = null;
remoteId = 0;
moreExpanded = false;
populateFields(intent);
}
@ -1041,7 +969,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
return true;
case MENU_COMMENTS_REFRESH_ID: {
if (editNotes != null)
editNotes.refreshData(true, null);
return true;
}
@ -1110,7 +1037,7 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
if (taskRabbitControl != null && taskRabbitControl.activityResult(requestCode, resultCode, data)) {
return;
}
else if (editNotes != null && editNotes.activityResult(requestCode, resultCode, data)) {
else if (editNotes.activityResult(requestCode, resultCode, data)) {
return;
}
else if (requestCode == REQUEST_VOICE_RECOG
@ -1139,7 +1066,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
// stick our task into the outState
outState.putParcelable(TASK_IN_PROGRESS, model);
outState.putLong(TASK_REMOTE_ID, remoteId);
outState.putBoolean(MORE_EXPANDED, moreExpanded);
}
@Override

@ -2,6 +2,8 @@ package com.todoroo.astrid.adapter;
import greendroid.widget.AsyncImageView;
import java.io.IOException;
import org.json.JSONObject;
import android.app.AlertDialog;
@ -27,6 +29,7 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.adapter.TaskAdapter.OnCompletedTaskListener;
import com.todoroo.astrid.data.Update;
import com.todoroo.astrid.helper.ImageDiskCache;
/**
* Adapter for displaying a user's goals as a list
@ -41,6 +44,7 @@ public class UpdateAdapter extends CursorAdapter {
protected final Fragment fragment;
private final int resource;
private final LayoutInflater inflater;
private final ImageDiskCache imageCache;
/**
* Constructor
@ -63,6 +67,7 @@ public class UpdateAdapter extends CursorAdapter {
inflater = (LayoutInflater) fragment.getActivity().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
imageCache = ImageDiskCache.getInstance();
this.resource = resource;
this.fragment = fragment;
@ -114,6 +119,17 @@ public class UpdateAdapter extends CursorAdapter {
commentPictureView.setVisibility(View.VISIBLE);
commentPictureView.setUrl(updatePicture);
if(imageCache.contains(updatePicture)) {
try {
commentPictureView.setDefaultImageBitmap(imageCache.get(updatePicture));
} catch (IOException e) {
e.printStackTrace();
}
}
else {
commentPictureView.setUrl(updatePicture);
}
final String message = update.getValue(Update.MESSAGE);
view.setOnClickListener(new OnClickListener() {
@Override
@ -146,7 +162,12 @@ public class UpdateAdapter extends CursorAdapter {
if(update.getValue(Update.ACTION_CODE).equals("task_comment"))
nameValue = r.getString(R.string.UAd_title_comment, nameValue,
update.getValue(Update.TARGET_NAME));
nameView.setText(nameValue);
if(TextUtils.isEmpty(nameValue)){
nameView.setText(fragment.getActivity().getString(R.string.ENA_no_user));
}
else {
nameView.setText(nameValue);
}
}
// description

@ -37,7 +37,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 = 19;
public static final int VERSION = 20;
/**
* Database name (must be unique)
@ -94,39 +94,53 @@ public class Database extends AbstractDatabase {
protected synchronized void onCreateTables() {
StringBuilder sql = new StringBuilder();
sql.append("CREATE INDEX IF NOT EXISTS md_tid ON ").
append(Metadata.TABLE).append('(').
append(Metadata.TASK.name).
append(')');
append(Metadata.TABLE).append('(').
append(Metadata.TASK.name).
append(')');
database.execSQL(sql.toString());
sql.setLength(0);
sql.append("CREATE INDEX IF NOT EXISTS md_tkid ON ").
append(Metadata.TABLE).append('(').
append(Metadata.TASK.name).append(',').
append(Metadata.KEY.name).
append(')');
append(Metadata.TABLE).append('(').
append(Metadata.TASK.name).append(',').
append(Metadata.KEY.name).
append(')');
database.execSQL(sql.toString());
sql.setLength(0);
sql.append("CREATE INDEX IF NOT EXISTS so_id ON ").
append(StoreObject.TABLE).append('(').
append(StoreObject.TYPE.name).append(',').
append(StoreObject.ITEM.name).
append(')');
append(StoreObject.TABLE).append('(').
append(StoreObject.TYPE.name).append(',').
append(StoreObject.ITEM.name).
append(')');
database.execSQL(sql.toString());
sql.setLength(0);
sql.append("CREATE INDEX IF NOT EXISTS up_tid ON ").
append(Update.TABLE).append('(').
append(Update.TASK.name).
append(')');
append(Update.TABLE).append('(').
append(Update.TASK.name).
append(')');
database.execSQL(sql.toString());
sql.setLength(0);
sql.append("CREATE INDEX IF NOT EXISTS up_pid ON ").
append(Update.TABLE).append('(').
append(Update.TAGS.name).
append(')');
append(Update.TABLE).append('(').
append(Update.TAGS.name).
append(')');
database.execSQL(sql.toString());
sql.setLength(0);
sql.append("CREATE INDEX IF NOT EXISTS up_tid ON ").
append(Update.TABLE).append('(').
append(Update.TASK_LOCAL.name).
append(')');
database.execSQL(sql.toString());
sql.setLength(0);
sql.append("CREATE INDEX IF NOT EXISTS up_pid ON ").
append(Update.TABLE).append('(').
append(Update.TAGS_LOCAL.name).
append(')');
database.execSQL(sql.toString());
sql.setLength(0);
}
@ -138,7 +152,7 @@ public class Database extends AbstractDatabase {
switch(oldVersion) {
case 1: {
database.execSQL("ALTER TABLE " + Task.TABLE.name + " ADD " +
Task.RECURRENCE.accept(visitor, null));
Task.RECURRENCE.accept(visitor, null));
}
case 2: {
for(Property<?> property : new Property<?>[] { Metadata.VALUE2,
@ -153,19 +167,19 @@ public class Database extends AbstractDatabase {
}
case 4: {
database.execSQL("ALTER TABLE " + Task.TABLE.name + " ADD " +
Task.DETAILS.accept(visitor, null));
Task.DETAILS.accept(visitor, null));
}
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));
Metadata.CREATION_DATE.accept(visitor, null));
}
case 8: {
// not needed anymore
@ -240,6 +254,18 @@ public class Database extends AbstractDatabase {
} catch (SQLiteException e) {
Log.e("astrid", "db-upgrade-" + oldVersion + "-" + newVersion, e);
}
case 19: try {
for(Property<?> property : new Property<?>[] { Update.TASK_LOCAL, Update.TAGS_LOCAL })
database.execSQL("ALTER TABLE " + Update.TABLE.name + " ADD " +
property.accept(visitor, null));
database.execSQL("CREATE INDEX IF NOT EXISTS up_tid ON " +
Update.TABLE + "(" + Update.TASK_LOCAL.name + ")");
database.execSQL("CREATE INDEX IF NOT EXISTS up_tid ON " +
Update.TABLE + "(" + Update.TAGS_LOCAL.name + ")");
} catch (SQLiteException e) {
Log.e("astrid", "db-upgrade-" + oldVersion + "-" + newVersion, e);
}
return true;
}
@ -258,7 +284,7 @@ public class Database extends AbstractDatabase {
String tableName, Property<?>[] properties) {
StringBuilder sql = new StringBuilder();
sql.append("CREATE TABLE IF NOT EXISTS ").append(tableName).append('(').
append(AbstractModel.ID_PROPERTY).append(" INTEGER PRIMARY KEY AUTOINCREMENT");
append(AbstractModel.ID_PROPERTY).append(" INTEGER PRIMARY KEY AUTOINCREMENT");
for(Property<?> property : properties) {
if(AbstractModel.ID_PROPERTY.name.equals(property.name))
continue;

@ -147,6 +147,13 @@ public abstract class DiskCache<K, V> {
}
}
public boolean move(K from, K to) {
final File moveFrom = getFile(from);
final File moveTo = getFile(to);
moveFrom.renameTo(moveTo);
return true;
}
/**
* Reads the value from disk using {@link #fromDisk(Object, InputStream)}.

@ -16,16 +16,18 @@ package com.todoroo.astrid.helper;
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;
import com.todoroo.andlib.service.ContextManager;
/**
* <p>
* An image download-and-cacher that also knows how to efficiently generate
@ -43,36 +45,29 @@ import android.util.Log;
*
*/
@SuppressWarnings("nls")
public class ImageCache extends DiskCache<String, Bitmap> {
private static final String TAG = ImageCache.class.getSimpleName();
public class ImageDiskCache extends DiskCache<String, Bitmap> {
private static final String TAG = ImageDiskCache.class.getSimpleName();
static final boolean DEBUG = false;
private long mIDCounter = 0;
private static ImageCache mInstance;
private static ImageDiskCache mInstance;
private final CompressFormat mCompressFormat;
private final int mQuality;
// TODO make it so this is customizable on the instance level.
/**
* Gets an instance of the cache.
*
* @param context
* @return an instance of the cache
*/
public static ImageCache getInstance(Context context) {
if (mInstance == null) {
mInstance = new ImageCache(context, CompressFormat.JPEG, 85);
}
return mInstance;
}
public static ImageDiskCache getInstance() {
if (mInstance == null) {
mInstance = new ImageDiskCache(ContextManager.getContext().getCacheDir(), CompressFormat.JPEG, 85);
}
return mInstance;
}
private ImageCache(Context context, CompressFormat format, int quality) {
super(context.getCacheDir(), null, getExtension(format));
private ImageDiskCache(File file, CompressFormat format, int quality) {
super(file, null, getExtension(format));
mCompressFormat = format;
mQuality = quality;

@ -142,9 +142,10 @@ public class TagDataService {
criterion).
orderBy(Order.desc(Update.CREATION_DATE)));
if(tagData.getValue(Task.REMOTE_ID) < 1)
return updateDao.query(Query.select(Update.PROPERTIES).where(Criterion.none));
return updateDao.query(Query.select(Update.PROPERTIES).where(Update.TAGS_LOCAL.like("%," + tagData.getId() + ",%")));
return updateDao.query(Query.select(Update.PROPERTIES).where(Criterion.and(criterion,
Update.TAGS.like("%," + tagData.getValue(Task.REMOTE_ID) + ",%"))).
Criterion.or(Update.TAGS.like("%," + tagData.getValue(Task.REMOTE_ID) + ",%"),
Update.TAGS_LOCAL.like("%," + tagData.getId() + ",%")))).
orderBy(Order.desc(Update.CREATION_DATE)));
}

Loading…
Cancel
Save