Pushing queued updates and enabling commenting while offline

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

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

@ -10,6 +10,7 @@ import android.support.v4.view.Menu;
import android.support.v4.view.MenuItem; import android.support.v4.view.MenuItem;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuInflater; 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.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.Update; import com.todoroo.astrid.data.Update;
import com.todoroo.astrid.helper.ImageDiskCache;
import com.todoroo.astrid.helper.ProgressBarSyncResultCallback; import com.todoroo.astrid.helper.ProgressBarSyncResultCallback;
import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService; 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 static final int MENU_REFRESH_ID = Menu.FIRST;
private final ImageDiskCache imageCache;
@Autowired ActFmPreferenceService actFmPreferenceService; @Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired TagDataService tagDataService; @Autowired TagDataService tagDataService;
@Autowired UpdateDao updateDao; @Autowired UpdateDao updateDao;
@ -70,6 +74,7 @@ public class TagUpdatesFragment extends ListFragment {
public TagUpdatesFragment() { public TagUpdatesFragment() {
DependencyInjectionService.getInstance().inject(this); DependencyInjectionService.getInstance().inject(this);
imageCache = ImageDiskCache.getInstance();
} }
public TagUpdatesFragment(TagData tagData) { public TagUpdatesFragment(TagData tagData) {
@ -181,9 +186,6 @@ public class TagUpdatesFragment extends ListFragment {
private void refreshUpdatesList() { private void refreshUpdatesList() {
if(tagData != null && tagData.getValue(Task.REMOTE_ID) <= 0)
return;
if(updateAdapter == null) { if(updateAdapter == null) {
TodorooCursor<Update> currentCursor = tagDataService.getUpdates(tagData); TodorooCursor<Update> currentCursor = tagDataService.getUpdates(tagData);
getActivity().startManagingCursor(currentCursor); getActivity().startManagingCursor(currentCursor);
@ -197,7 +199,7 @@ public class TagUpdatesFragment extends ListFragment {
getActivity().startManagingCursor(cursor); 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()); 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") @SuppressWarnings("nls")
private void addComment() { private void addComment() {
if(tagData.getValue(TagData.REMOTE_ID) == 0L)
return;
Update update = new Update(); Update update = new Update();
update.setValue(Update.MESSAGE, addCommentField.getText().toString()); update.setValue(Update.MESSAGE, addCommentField.getText().toString());
update.setValue(Update.ACTION_CODE, "tag_comment"); update.setValue(Update.ACTION_CODE, "tag_comment");
update.setValue(Update.USER_ID, 0L); update.setValue(Update.USER_ID, 0L);
update.setValue(Update.TAGS, "," + tagData.getValue(TagData.REMOTE_ID) + ","); update.setValue(Update.TAGS, "," + tagData.getValue(TagData.REMOTE_ID) + ",");
update.setValue(Update.TAGS_LOCAL, "," + tagData.getId() + ",");
update.setValue(Update.CREATION_DATE, DateUtilities.now()); update.setValue(Update.CREATION_DATE, DateUtilities.now());
if (picture != null) { if (picture != null) {
update.setValue(Update.PICTURE, Update.PICTURE_LOADING); 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); Flags.set(Flags.ACTFM_SUPPRESS_SYNC);
updateDao.createNew(update); updateDao.createNew(update);

@ -55,6 +55,7 @@ import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskApiDao; import com.todoroo.astrid.data.TaskApiDao;
import com.todoroo.astrid.data.Update; import com.todoroo.astrid.data.Update;
import com.todoroo.astrid.helper.ImageDiskCache;
import com.todoroo.astrid.service.MetadataService; import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService; import com.todoroo.astrid.service.StatisticsService;
@ -268,9 +269,14 @@ public final class ActFmSyncService {
else else
result = actFmInvoker.post("comment_add", picture, params.toArray(new Object[params.size()])); result = actFmInvoker.post("comment_add", picture, params.toArray(new Object[params.size()]));
update.setValue(Update.REMOTE_ID, result.optLong("id")); 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 //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")); update.setValue(Update.PICTURE, result.optString("picture"));
} }
@ -780,6 +786,8 @@ public final class ActFmSyncService {
}, done, "tasks:" + tagData.getId(), "tag_id", tagData.getValue(TagData.REMOTE_ID)); }, done, "tasks:" + tagData.getId(), "tag_id", tagData.getValue(TagData.REMOTE_ID));
} }
/** /**
* Fetch updates for the given tagData asynchronously * Fetch updates for the given tagData asynchronously
* @param tagData * @param tagData
@ -789,6 +797,8 @@ public final class ActFmSyncService {
public void fetchUpdatesForTag(final TagData tagData, final boolean manual, Runnable done) { public void fetchUpdatesForTag(final TagData tagData, final boolean manual, Runnable done) {
invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done, invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done,
"updates:" + tagData.getId(), "tag_id", tagData.getValue(TagData.REMOTE_ID)); "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) { public void fetchUpdatesForTask(final Task task, boolean manual, Runnable done) {
invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done, invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done,
"comments:" + task.getId(), "task_id", task.getValue(Task.REMOTE_ID)); "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) { public void fetchPersonalUpdates(boolean manual, Runnable done) {
invokeFetchList("activity", manual, null, new UpdateListItemProcessor(), done, "personal"); 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> { private class UpdateListItemProcessor extends ListItemProcessor<Update> {
@Override @Override
protected void mergeAndSave(JSONArray list, HashMap<Long,Long> locals) throws JSONException { protected void mergeAndSave(JSONArray list, HashMap<Long,Long> locals) throws JSONException {
@ -935,6 +1032,8 @@ public final class ActFmSyncService {
} }
/** Call sync method */ /** Call sync method */
private void invokeFetchList(final String model, final boolean manual, final SyncExceptionHandler handler, private void invokeFetchList(final String model, final boolean manual, final SyncExceptionHandler handler,
final ListItemProcessor<?> processor, final Runnable done, final String lastSyncKey, final ListItemProcessor<?> processor, final Runnable done, final String lastSyncKey,

@ -11,6 +11,8 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.json.JSONException; import org.json.JSONException;
import android.graphics.Bitmap;
import com.timsu.astrid.C2DMReceiver; import com.timsu.astrid.C2DMReceiver;
import com.timsu.astrid.R; import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor; 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.RemoteModel;
import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task; 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.AstridDependencyInjector;
import com.todoroo.astrid.service.TagDataService; import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.service.TaskService;
@ -287,7 +291,7 @@ public class ActFmSyncV2Provider extends SyncV2Provider {
}).start(); }).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) { final AtomicInteger finisher) {
actFmSyncService.fetchUpdatesForTag(tagData, manual, new Runnable() { actFmSyncService.fetchUpdatesForTag(tagData, manual, new Runnable() {
@Override @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) { final AtomicInteger finisher) {
actFmSyncService.fetchTasksForTag(tagData, manual, new Runnable() { actFmSyncService.fetchTasksForTag(tagData, manual, new Runnable() {
@Override @Override

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

@ -64,24 +64,6 @@
android:orientation="vertical" > android:orientation="vertical" >
</LinearLayout> </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 <LinearLayout
android:id="@+id/more_container" android:id="@+id/more_container"

@ -87,6 +87,9 @@
<!-- EditNoteActivity - no comments --> <!-- EditNoteActivity - no comments -->
<string name="ENA_no_comments">Nothing To Show</string> <string name="ENA_no_comments">Nothing To Show</string>
<!-- EditNoteActivity - no username for comment -->
<string name="ENA_no_user">You</string>
<!-- EditNoteActivity - refresh comments --> <!-- EditNoteActivity - refresh comments -->
<string name="ENA_refresh_comments">Refresh Comments</string> <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;
import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.LayoutParams;
import android.view.ViewParent; import android.view.ViewParent;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.FrameLayout; 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$ 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 * Tab to start on
@ -248,7 +242,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
private long remoteId = 0; private long remoteId = 0;
private boolean moreExpanded = false;
private WebServicesView webServices = null; private WebServicesView webServices = null;
@ -304,9 +297,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
if (savedInstanceState.containsKey(TASK_REMOTE_ID)) { if (savedInstanceState.containsKey(TASK_REMOTE_ID)) {
remoteId = savedInstanceState.getLong(TASK_REMOTE_ID); remoteId = savedInstanceState.getLong(TASK_REMOTE_ID);
} }
if (savedInstanceState.containsKey(MORE_EXPANDED)) {
moreExpanded = savedInstanceState.getBoolean(MORE_EXPANDED);
}
} }
@ -367,25 +357,18 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
} }
private void loadMoreContainer() { private void loadMoreContainer() {
View moreSection = (View) getView().findViewById(R.id.more_header);
View moreTab = (View) getView().findViewById(R.id.more_container); View moreTab = (View) getView().findViewById(R.id.more_container);
View commentsBar = (View) getView().findViewById(R.id.updatesFooter); View commentsBar = (View) getView().findViewById(R.id.updatesFooter);
long idParam = getActivity().getIntent().getLongExtra(TOKEN_ID, -1L); long idParam = getActivity().getIntent().getLongExtra(TOKEN_ID, -1L);
boolean hasTitle = !TextUtils.isEmpty(model.getValue(Task.TITLE)); boolean hasTitle = !TextUtils.isEmpty(model.getValue(Task.TITLE));
boolean hasRemoteId = remoteId > 0 && idParam > -1L;
if(hasTitle && hasRemoteId) if(hasTitle)
tabStyle = TAB_STYLE_ACTIVITY_WEB; tabStyle = TAB_STYLE_ACTIVITY_WEB;
else if(hasTitle)
tabStyle = TAB_STYLE_WEB;
else if(hasRemoteId)
tabStyle = TAB_STYLE_ACTIVITY;
else else
tabStyle = TAB_STYLE_NONE; tabStyle = TAB_STYLE_ACTIVITY;
if (hasRemoteId) {
if (editNotes == null) { if (editNotes == null) {
editNotes = new EditNoteActivity(this, getView(), editNotes = new EditNoteActivity(this, getView(),
idParam); idParam);
@ -405,7 +388,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
Handler refreshHandler = new Handler(); Handler refreshHandler = new Handler();
refreshHandler.postDelayed(refreshActivity, 1000); refreshHandler.postDelayed(refreshActivity, 1000);
}
if(hasTitle) { if(hasTitle) {
if(webServices == null) { if(webServices == null) {
@ -420,7 +402,7 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
} }
} }
if(tabStyle != TAB_STYLE_NONE) {
mAdapter = new TaskEditViewPager(getActivity(), tabStyle); mAdapter = new TaskEditViewPager(getActivity(), tabStyle);
mAdapter.parent = this; mAdapter.parent = this;
@ -437,24 +419,7 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
} }
commentsBar.setVisibility(View.VISIBLE); commentsBar.setVisibility(View.VISIBLE);
moreSection.setVisibility(View.GONE);
moreTab.setVisibility(View.VISIBLE); 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) { 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) { private void constructWhenDialog(View whenDialogView) {
int theme = ThemeService.getEditDialogTheme(); int theme = ThemeService.getEditDialogTheme();
whenDialog = new Dialog(getActivity(), theme); 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) { public void repopulateFromScratch(Intent intent) {
model = null; model = null;
remoteId = 0; remoteId = 0;
moreExpanded = false;
populateFields(intent); populateFields(intent);
} }
@ -1041,7 +969,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
return true; return true;
case MENU_COMMENTS_REFRESH_ID: { case MENU_COMMENTS_REFRESH_ID: {
if (editNotes != null)
editNotes.refreshData(true, null); editNotes.refreshData(true, null);
return true; return true;
} }
@ -1110,7 +1037,7 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
if (taskRabbitControl != null && taskRabbitControl.activityResult(requestCode, resultCode, data)) { if (taskRabbitControl != null && taskRabbitControl.activityResult(requestCode, resultCode, data)) {
return; return;
} }
else if (editNotes != null && editNotes.activityResult(requestCode, resultCode, data)) { else if (editNotes.activityResult(requestCode, resultCode, data)) {
return; return;
} }
else if (requestCode == REQUEST_VOICE_RECOG else if (requestCode == REQUEST_VOICE_RECOG
@ -1139,7 +1066,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
// stick our task into the outState // stick our task into the outState
outState.putParcelable(TASK_IN_PROGRESS, model); outState.putParcelable(TASK_IN_PROGRESS, model);
outState.putLong(TASK_REMOTE_ID, remoteId); outState.putLong(TASK_REMOTE_ID, remoteId);
outState.putBoolean(MORE_EXPANDED, moreExpanded);
} }
@Override @Override

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

@ -37,7 +37,7 @@ public class Database extends AbstractDatabase {
* Database version number. This variable must be updated when database * Database version number. This variable must be updated when database
* tables are updated, as it determines whether a database needs updating. * 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) * Database name (must be unique)
@ -129,6 +129,20 @@ public class Database extends AbstractDatabase {
append(')'); append(')');
database.execSQL(sql.toString()); database.execSQL(sql.toString());
sql.setLength(0); 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);
} }
@Override @Override
@ -240,6 +254,18 @@ public class Database extends AbstractDatabase {
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.e("astrid", "db-upgrade-" + oldVersion + "-" + newVersion, 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; return true;
} }

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

@ -142,9 +142,10 @@ public class TagDataService {
criterion). criterion).
orderBy(Order.desc(Update.CREATION_DATE))); orderBy(Order.desc(Update.CREATION_DATE)));
if(tagData.getValue(Task.REMOTE_ID) < 1) 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, 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))); orderBy(Order.desc(Update.CREATION_DATE)));
} }

Loading…
Cancel
Save