diff --git a/res/drawable/icon_timer.png b/res/drawable/icon_timer.png new file mode 100644 index 000000000..4ff30b6f7 Binary files /dev/null and b/res/drawable/icon_timer.png differ diff --git a/res/drawable/strikeout.png b/res/drawable/strikeout.png deleted file mode 100644 index 175cac2ac..000000000 Binary files a/res/drawable/strikeout.png and /dev/null differ diff --git a/res/layout/task_list_row.xml b/res/layout/task_list_row.xml index deaa46c2d..b5c02d081 100644 --- a/res/layout/task_list_row.xml +++ b/res/layout/task_list_row.xml @@ -25,23 +25,34 @@ android:focusable="true" android:background="@android:drawable/list_selector_background" android:paddingLeft="6dip" + android:paddingTop="2px" + android:paddingBottom="2px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:minHeight="45dip" > - + + android:layout_height="fill_parent"> - + + + + + - diff --git a/res/values/strings.xml b/res/values/strings.xml index 853aca0d3..c6d721905 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -60,12 +60,12 @@ 1 Day %d Days - D\na\ny\ns + D\na\ny\ns 1 Hour %d Hours - H\no\nu\nr\ns + H\no\nu\nr\ns 1 Minute %d Minutes @@ -98,6 +98,7 @@ Add Tags Display + Sync More Synchronization Settings @@ -107,6 +108,7 @@ Delete Task Start Timer Stop Timer + Postpone Sort/Filters Hidden/Blocked Tasks @@ -116,6 +118,8 @@ Sort By Name Sort By Due Date Sort Reverse + + Postpone for how long? @@ -209,15 +213,21 @@ If you don\'t want to see the new task right after you complete the old one, you - sync_rtm - sync_every Synchronization Services Actions Options + sync_rtm Remember The Milk http://www.rememberthemilk.com + sync_every Synchronize Frequency - If set, sync every # hours when Astrid starts + If set, perform sync every # hours + sync_button + Main Menu Shortcut + Show \"Synchronize\" in Astrid\'s menu + sync_background + In Background + Synchronize without bothering you Sync Error! Sorry for the inconvenience! Error: In order to synchronize, please log in to your %s account and authorize Astrid to read your data. diff --git a/res/xml/sync_preferences.xml b/res/xml/sync_preferences.xml index 0bd17781e..afe4dac08 100644 --- a/res/xml/sync_preferences.xml +++ b/res/xml/sync_preferences.xml @@ -18,7 +18,12 @@ + android:summary="@string/sync_every_desc" /> + + diff --git a/src/com/mdt/rtm/Invoker.java b/src/com/mdt/rtm/Invoker.java index 2df2b246e..f7bc21f57 100644 --- a/src/com/mdt/rtm/Invoker.java +++ b/src/com/mdt/rtm/Invoker.java @@ -95,7 +95,7 @@ public class Invoker { public static final String API_SIG_PARAM = "api_sig"; - public static final long INVOCATION_INTERVAL = 750; + public static final long INVOCATION_INTERVAL = 300; private long lastInvocation; diff --git a/src/com/mdt/rtm/data/RtmData.java b/src/com/mdt/rtm/data/RtmData.java index bd455276f..ddb92bd33 100644 --- a/src/com/mdt/rtm/data/RtmData.java +++ b/src/com/mdt/rtm/data/RtmData.java @@ -32,7 +32,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** - * + * * @author Will Ross Jun 21, 2007 */ public abstract class RtmData @@ -40,8 +40,8 @@ public abstract class RtmData private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - public RtmData() - { + public RtmData() { + // } /** diff --git a/src/com/timsu/astrid/activities/TaskList.java b/src/com/timsu/astrid/activities/TaskList.java index 8fcf57cf5..7f68fb336 100644 --- a/src/com/timsu/astrid/activities/TaskList.java +++ b/src/com/timsu/astrid/activities/TaskList.java @@ -64,6 +64,7 @@ import com.timsu.astrid.utilities.Constants; import com.timsu.astrid.utilities.DialogUtilities; import com.timsu.astrid.utilities.Preferences; import com.timsu.astrid.utilities.StartupReceiver; +import com.timsu.astrid.widget.NNumberPickerDialog.OnNNumberPickedListener; /** Primary view for the Astrid Application. Lists all of the tasks in the @@ -88,7 +89,8 @@ public class TaskList extends Activity { private static final int INSERT_ID = Menu.FIRST; private static final int FILTERS_ID = Menu.FIRST + 1; private static final int TAGS_ID = Menu.FIRST + 2; - private static final int MORE_ID = Menu.FIRST + 3; + private static final int SYNC_ID = Menu.FIRST + 3; + private static final int MORE_ID = Menu.FIRST + 4; private static final int OPTIONS_SYNC_ID = Menu.FIRST + 10; private static final int OPTIONS_SETTINGS_ID = Menu.FIRST + 11; @@ -103,8 +105,11 @@ public class TaskList extends Activity { private static final int CONTEXT_SORT_REVERSE = Menu.FIRST + 26; private static final int CONTEXT_SORT_GROUP = Menu.FIRST; - public static final int FLING_DIST_THRESHOLD = 100; - public static final int FLING_VEL_THRESHOLD = 300; + public static final int FLING_DIST_THRESHOLD = 100; + public static final int FLING_VEL_THRESHOLD = 300; + + private static final int SORTFLAG_FILTERDONE = (1 << 5); + private static final int SORTFLAG_FILTERHIDDEN = (1 << 6); // UI components private ListView listView; @@ -117,6 +122,7 @@ public class TaskList extends Activity { private HashMap> taskTags; private GestureDetector gestureDetector; private View.OnTouchListener gestureTouchListener; + private boolean displaySyncShortcut; // display filters private static boolean filterShowHidden = false; @@ -254,6 +260,16 @@ public class TaskList extends Activity { item.setIcon(android.R.drawable.ic_menu_myplaces); item.setAlphabeticShortcut('t'); + if(Preferences.shouldDisplaySyncButton(this)){ + item = menu.add(Menu.NONE, SYNC_ID, Menu.NONE, + R.string.taskList_menu_syncshortcut); + item.setIcon(android.R.drawable.ic_menu_upload); + item.setAlphabeticShortcut('s'); + displaySyncShortcut = true; + } else { + displaySyncShortcut = false; + } + item = menu.add(Menu.NONE, MORE_ID, Menu.NONE, R.string.taskList_menu_more); item.setIcon(android.R.drawable.ic_menu_more); @@ -262,6 +278,27 @@ public class TaskList extends Activity { return true; } + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + + boolean shouldDisplaySyncShortcut = Preferences.shouldDisplaySyncButton(this); + if(shouldDisplaySyncShortcut != displaySyncShortcut) { + if(shouldDisplaySyncShortcut) { + MenuItem item = menu.add(Menu.NONE, SYNC_ID, Menu.NONE, + R.string.taskList_menu_syncshortcut); + item.setIcon(android.R.drawable.ic_menu_upload); + item.setAlphabeticShortcut('s'); + } else + menu.removeItem(SYNC_ID); + + displaySyncShortcut = shouldDisplaySyncShortcut; + } + + + return true; + } + public boolean onCreateMoreOptionsMenu(Menu menu) { MenuItem item; @@ -619,8 +656,15 @@ public class TaskList extends Activity { /** Save the sorting mode to the preferences */ private void saveTaskListSort() { int sortId = sortMode.ordinal() + 1; + + if(filterShowDone) + sortId |= SORTFLAG_FILTERDONE; + if(filterShowHidden) + sortId |= SORTFLAG_FILTERHIDDEN; + if(sortReverse) sortId *= -1; + Preferences.setTaskListSort(this, sortId); } @@ -630,14 +674,21 @@ public class TaskList extends Activity { if(sortId == 0) return; sortReverse = sortId < 0; + sortId = Math.abs(sortId); + + filterShowDone = (sortId & SORTFLAG_FILTERDONE) > 0; + filterShowHidden = (sortId & SORTFLAG_FILTERHIDDEN) > 0; - sortMode = SortMode.values()[Math.abs(sortId - 1)]; + sortId = sortId & ~(SORTFLAG_FILTERDONE | SORTFLAG_FILTERHIDDEN); + + sortMode = SortMode.values()[sortId - 1]; } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { Intent intent; - TaskModelForList task; + final TaskModelForList task; + Resources r = getResources(); switch(item.getItemId()) { case INSERT_ID: @@ -649,6 +700,9 @@ public class TaskList extends Activity { case TAGS_ID: showTagsView(); return true; + case SYNC_ID: + onActivityResult(ACTIVITY_SYNCHRONIZE, Constants.RESULT_SYNCHRONIZE, null); + return true; case MORE_ID: layout.showContextMenu(); return true; @@ -686,13 +740,40 @@ public class TaskList extends Activity { taskController.saveTask(task); fillData(); return true; + case TaskListAdapter.CONTEXT_POSTPONE_ID: + task = taskArray.get(item.getGroupId()); + DialogUtilities.dayHourPicker(this, + r.getString(R.string.taskList_postpone_dialog), + new OnNNumberPickedListener() { + public void onNumbersPicked(int[] values) { + long postponeMillis = (values[0] * 24 + values[1]) * + 3600L * 1000; + Date preferred = task.getPreferredDueDate(); + Date definite = task.getDefiniteDueDate(); + if(preferred != null) { + preferred = new Date(preferred.getTime() + + postponeMillis); + task.setPreferredDueDate(preferred); + } + if(definite != null) { + definite = new Date(definite.getTime() + + postponeMillis); + task.setDefiniteDueDate(definite); + } + taskController.saveTask(task); + fillData(); + } + }); + return true; case CONTEXT_FILTER_HIDDEN: TaskList.filterShowHidden = !filterShowHidden; + saveTaskListSort(); fillData(); return true; case CONTEXT_FILTER_DONE: TaskList.filterShowDone = !filterShowDone; + saveTaskListSort(); fillData(); return true; case CONTEXT_FILTER_TAG: diff --git a/src/com/timsu/astrid/activities/TaskListAdapter.java b/src/com/timsu/astrid/activities/TaskListAdapter.java index b33d37e3d..d0a9d75a8 100644 --- a/src/com/timsu/astrid/activities/TaskListAdapter.java +++ b/src/com/timsu/astrid/activities/TaskListAdapter.java @@ -26,6 +26,7 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; +import android.graphics.Paint; import android.graphics.Typeface; import android.view.ContextMenu; import android.view.LayoutInflater; @@ -62,6 +63,16 @@ public class TaskListAdapter extends ArrayAdapter { public static final int CONTEXT_EDIT_ID = Menu.FIRST + 50; public static final int CONTEXT_DELETE_ID = Menu.FIRST + 51; public static final int CONTEXT_TIMER_ID = Menu.FIRST + 52; + public static final int CONTEXT_POSTPONE_ID = Menu.FIRST + 53; + + private static final int KEY_NAME = 0; + private static final int KEY_DEADLINE = 1; + private static final int KEY_OVERDUE = 2; + private static final int KEY_REPEAT = 3; + private static final int KEY_REMINDERS = 4; + private static final int KEY_TIMES = 5; + private static final int KEY_TAGS = 6; + private static final int KEY_HIDDEN = 7; private final Activity activity; private List objects; @@ -72,6 +83,8 @@ public class TaskListAdapter extends ArrayAdapter { private Integer fontSizePreference; private AlertController alarmController; + private TaskModelForList recentlyCompleted = null; + public interface TaskListAdapterHooks { List getTaskArray(); List getTagsFor(TaskModelForList task); @@ -100,9 +113,10 @@ public class TaskListAdapter extends ArrayAdapter { @Override public View getView(int position, View convertView, ViewGroup parent) { - View view; + View view = convertView; - view = inflater.inflate(resource, parent, false); + if(view == null) + view = inflater.inflate(resource, parent, false); setupView(view, objects.get(position)); addListeners(position, view); @@ -120,7 +134,7 @@ public class TaskListAdapter extends ArrayAdapter { progress.setTag(task); if(task.getTimerStart() != null) - timer.setImageDrawable(r.getDrawable(R.drawable.ic_dialog_time)); + timer.setImageDrawable(r.getDrawable(R.drawable.icon_timer)); progress.setChecked(task.isTaskCompleted()); setFieldContentsAndVisibility(view, task); @@ -144,12 +158,20 @@ public class TaskListAdapter extends ArrayAdapter { // name final TextView name = ((TextView)view.findViewById(R.id.task_name)); if(visibleFields.TITLE) { - String nameValue = task.getName(); - if(task.getHiddenUntil() != null && task.getHiddenUntil().after(new Date())) { - nameValue = "(" + r.getString(R.string.taskList_hiddenPrefix) + ") " + nameValue; - name.setTypeface(Typeface.DEFAULT, Typeface.ITALIC); + String cachedResult = task.getCachedLabel(KEY_NAME); + if(cachedResult == null) { + String nameValue = task.getName(); + if(task.getHiddenUntil() != null && task.getHiddenUntil().after(new Date())) { + nameValue = "(" + r.getString(R.string.taskList_hiddenPrefix) + ") " + nameValue; + task.putCachedLabel(KEY_HIDDEN, ""); + } + cachedResult = nameValue.toString(); + task.putCachedLabel(KEY_NAME, cachedResult); } - name.setText(nameValue); + name.setText(cachedResult); + if(task.getCachedLabel(KEY_HIDDEN) != null) + name.setTypeface(Typeface.DEFAULT, Typeface.ITALIC); + if(fontSizePreference != null && fontSizePreference > 0) name.setTextSize(fontSizePreference); } @@ -157,7 +179,7 @@ public class TaskListAdapter extends ArrayAdapter { // importance - final ImageView importance = (ImageView)view.findViewById(R.id.importance); + final View importance = (View)view.findViewById(R.id.importance); if(visibleFields.IMPORTANCE) { importance.setBackgroundColor(r.getColor( task.getImportance().getColorResource())); @@ -167,126 +189,156 @@ public class TaskListAdapter extends ArrayAdapter { // due date / completion date final TextView deadlines = ((TextView)view.findViewById(R.id.text_deadlines)); if(visibleFields.DEADLINE) { - StringBuilder label = new StringBuilder(); - if(task.isTaskCompleted()) { - if(task.getCompletionDate() != null) { - int secondsLeft = (int)((task.getCompletionDate().getTime() - - System.currentTimeMillis()) / 1000); - label.append(r.getString(R.string.taskList_completedPrefix)). - append(" "). - append(DateUtilities.getDurationString(r, Math.abs(secondsLeft), 1)). - append(" " + r.getString(R.string.ago_suffix)); - } - } else { - boolean taskOverdue = false; - if(task.getDefiniteDueDate() != null) { - long timeLeft = task.getDefiniteDueDate().getTime() - - System.currentTimeMillis(); - if(timeLeft > 0){ - label.append(r.getString(R.string.taskList_dueIn)).append(" "); - } else { - taskOverdue = true; - label.append(r.getString(R.string.taskList_overdueBy)).append(" "); - deadlines.setTextColor(r.getColor(R.color.taskList_dueDateOverdue)); + String cachedResult = task.getCachedLabel(KEY_DEADLINE); + if(cachedResult == null) { + StringBuilder label = new StringBuilder(); + if(task.isTaskCompleted()) { + if(task.getCompletionDate() != null) { + int secondsLeft = (int)((task.getCompletionDate().getTime() - + System.currentTimeMillis()) / 1000); + label.append(r.getString(R.string.taskList_completedPrefix)). + append(" "). + append(DateUtilities.getDurationString(r, Math.abs(secondsLeft), 1)). + append(" " + r.getString(R.string.ago_suffix)); } - label.append(DateUtilities.getDurationString(r, - (int)Math.abs(timeLeft/1000), 1)); - } - if(!taskOverdue && task.getPreferredDueDate() != null) { - if(task.getDefiniteDueDate() != null) - label.append(" / "); - long timeLeft = task.getPreferredDueDate().getTime() - - System.currentTimeMillis(); - label.append(r.getString(R.string.taskList_goalPrefix)).append(" "); - if(timeLeft > 0){ - label.append(r.getString(R.string.taskList_dueIn)).append(" "); - } else { - label.append(r.getString(R.string.taskList_overdueBy)).append(" "); - deadlines.setTextColor(r.getColor(R.color.taskList_dueDateOverdue)); + } else { + boolean taskOverdue = false; + if(task.getDefiniteDueDate() != null) { + long timeLeft = task.getDefiniteDueDate().getTime() - + System.currentTimeMillis(); + if(timeLeft > 0){ + label.append(r.getString(R.string.taskList_dueIn)).append(" "); + } else { + taskOverdue = true; + label.append(r.getString(R.string.taskList_overdueBy)).append(" "); + task.putCachedLabel(KEY_OVERDUE, ""); + } + label.append(DateUtilities.getDurationString(r, + (int)Math.abs(timeLeft/1000), 1)); + } + if(!taskOverdue && task.getPreferredDueDate() != null) { + if(task.getDefiniteDueDate() != null) + label.append(" / "); + long timeLeft = task.getPreferredDueDate().getTime() - + System.currentTimeMillis(); + label.append(r.getString(R.string.taskList_goalPrefix)).append(" "); + if(timeLeft > 0){ + label.append(r.getString(R.string.taskList_dueIn)).append(" "); + } else { + label.append(r.getString(R.string.taskList_overdueBy)).append(" "); + deadlines.setTextColor(r.getColor(R.color.taskList_dueDateOverdue)); + } + label.append(DateUtilities.getDurationString(r, + (int)Math.abs(timeLeft/1000), 1)).append(" "); } - label.append(DateUtilities.getDurationString(r, - (int)Math.abs(timeLeft/1000), 1)).append(" "); } + cachedResult = label.toString(); + task.putCachedLabel(KEY_DEADLINE, cachedResult); } - deadlines.setText(label); + deadlines.setText(cachedResult); + if(task.getCachedLabel(KEY_OVERDUE) != null) + deadlines.setTextColor(r.getColor(R.color.taskList_dueDateOverdue)); } setVisibility(deadlines); // estimated / elapsed time final TextView times = ((TextView)view.findViewById(R.id.text_times)); if(visibleFields.TIMES) { - Integer elapsed = task.getElapsedSeconds(); - if(task.getTimerStart() != null) - elapsed += ((System.currentTimeMillis() - task.getTimerStart().getTime())/1000); - Integer estimated = task.getEstimatedSeconds(); - StringBuilder label = new StringBuilder(); - if(estimated > 0) { - label.append(r.getString(R.string.taskList_estimatedTimePrefix)). - append(" "). - append(DateUtilities.getDurationString(r, estimated, 2)); - if(elapsed > 0) - label.append(" / "); - } - if(elapsed > 0) { - label.append(r.getString(R.string.taskList_elapsedTimePrefix)). - append(" "). - append(DateUtilities.getDurationString(r, elapsed, 2)); + String cachedResult = task.getCachedLabel(KEY_TIMES); + if(cachedResult == null) { + Integer elapsed = task.getElapsedSeconds(); + if(task.getTimerStart() != null) + elapsed += ((System.currentTimeMillis() - task.getTimerStart().getTime())/1000); + Integer estimated = task.getEstimatedSeconds(); + StringBuilder label = new StringBuilder(); + if(estimated > 0) { + label.append(r.getString(R.string.taskList_estimatedTimePrefix)). + append(" "). + append(DateUtilities.getDurationString(r, estimated, 2)); + if(elapsed > 0) + label.append(" / "); + } + if(elapsed > 0) { + label.append(r.getString(R.string.taskList_elapsedTimePrefix)). + append(" "). + append(DateUtilities.getDurationString(r, elapsed, 2)); + } + cachedResult = label.toString(); + task.putCachedLabel(KEY_TIMES, cachedResult); } - times.setText(label); + times.setText(cachedResult); } setVisibility(times); // reminders final TextView reminders = ((TextView)view.findViewById(R.id.text_reminders)); if(visibleFields.REMINDERS) { - Integer notifyEvery = task.getNotificationIntervalSeconds(); - StringBuilder label = new StringBuilder(); - if(notifyEvery != null && notifyEvery > 0) { - label.append(r.getString(R.string.taskList_periodicReminderPrefix)). - append(" ").append(DateUtilities.getDurationString(r, notifyEvery, 1)); - } + String cachedResult = task.getCachedLabel(KEY_REMINDERS); + if(cachedResult == null) { + Integer notifyEvery = task.getNotificationIntervalSeconds(); + StringBuilder label = new StringBuilder(); + if(notifyEvery != null && notifyEvery > 0) { + label.append(r.getString(R.string.taskList_periodicReminderPrefix)). + append(" ").append(DateUtilities.getDurationString(r, notifyEvery, 1)); + } - try { - alarmController.open(); - List alerts = alarmController.getTaskAlerts(task.getTaskIdentifier()); - if(alerts.size() > 0) { - if(label.length() > 0) - label.append(". "); - label.append(r.getQuantityString(R.plurals.Nalarms, alerts.size(), - alerts.size())).append(" ").append(r.getString(R.string.taskList_alarmSuffix)); - } - } finally { - alarmController.close(); + try { + alarmController.open(); + List alerts = alarmController.getTaskAlerts(task.getTaskIdentifier()); + if(alerts.size() > 0) { + if(label.length() > 0) + label.append(". "); + label.append(r.getQuantityString(R.plurals.Nalarms, alerts.size(), + alerts.size())).append(" ").append(r.getString(R.string.taskList_alarmSuffix)); + } + } finally { + alarmController.close(); + } + cachedResult = label.toString(); + task.putCachedLabel(KEY_REMINDERS, cachedResult); } - reminders.setText(label); + reminders.setText(cachedResult); } setVisibility(reminders); // repeats final TextView repeats = ((TextView)view.findViewById(R.id.text_repeats)); if(visibleFields.REPEATS) { - RepeatInfo repeatInfo = task.getRepeat(); - if(repeatInfo != null) { - repeats.setText(r.getString(R.string.taskList_repeatPrefix) + - " " + repeatInfo.getValue() + " " + - r.getString(repeatInfo.getInterval().getLabelResource())); + String cachedResult = task.getCachedLabel(KEY_REPEAT); + if(cachedResult == null) { + RepeatInfo repeatInfo = task.getRepeat(); + if(repeatInfo != null) { + cachedResult = r.getString(R.string.taskList_repeatPrefix) + + " " + repeatInfo.getValue() + " " + + r.getString(repeatInfo.getInterval().getLabelResource()); + } else + cachedResult = ""; + task.putCachedLabel(KEY_REPEAT, cachedResult); } + repeats.setText(cachedResult); } setVisibility(repeats); // tags final TextView tags = ((TextView)view.findViewById(R.id.text_tags)); if(visibleFields.TAGS) { - List alltags = hooks.getTagsFor(task); - StringBuilder tagString = new StringBuilder(); - for(Iterator i = alltags.iterator(); i.hasNext(); ) { - TagModelForView tag = i.next(); - tagString.append(tag.getName()); - if(i.hasNext()) - tagString.append(", "); + String cachedResult = task.getCachedLabel(KEY_TAGS); + if(cachedResult == null) { + List alltags = hooks.getTagsFor(task); + StringBuilder tagString = new StringBuilder(); + for(Iterator i = alltags.iterator(); i.hasNext(); ) { + TagModelForView tag = i.next(); + tagString.append(tag.getName()); + if(i.hasNext()) + tagString.append(", "); + } + if(alltags.size() > 0) + cachedResult = r.getString(R.string.taskList_tagsPrefix) + " " + tagString; + else + cachedResult = ""; + task.putCachedLabel(KEY_TAGS, cachedResult); } - if(alltags.size() > 0) - tags.setText(r.getString(R.string.taskList_tagsPrefix) + " " + tagString); + tags.setText(cachedResult); } setVisibility(tags); @@ -349,6 +401,9 @@ public class TaskListAdapter extends ArrayAdapter { timerTitle = R.string.taskList_context_stopTimer; menu.add(position, CONTEXT_TIMER_ID, Menu.NONE, timerTitle); + menu.add(position, CONTEXT_POSTPONE_ID, Menu.NONE, + R.string.taskList_context_postpone); + menu.setHeaderTitle(task.getName()); } }); @@ -359,6 +414,12 @@ public class TaskListAdapter extends ArrayAdapter { task.setProgressPercentage(progress); hooks.getTaskController().saveTask(task); + // show this task as completed even if it has repeats + if(progress == 100) + recentlyCompleted = task; + else + recentlyCompleted = null; + // if our timer is on, ask if we want to stop if(progress == 100 && task.getTimerStart() != null) { new AlertDialog.Builder(activity) @@ -382,12 +443,13 @@ public class TaskListAdapter extends ArrayAdapter { private void setTaskAppearance(TaskModelForList task, TextView name, CheckBox progress) { Resources r = activity.getResources(); - if(task.isTaskCompleted()) { - name.setBackgroundDrawable(r.getDrawable(R.drawable.strikeout)); + if(task.isTaskCompleted() || task == recentlyCompleted) { + name.setPaintFlags(name.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); name.setTextColor(r.getColor(R.color.task_list_done)); progress.setButtonDrawable(R.drawable.btn_check0); + progress.setChecked(true); } else { - name.setBackgroundDrawable(null); + name.setPaintFlags(name.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG); name.setTextColor(r.getColor(task.getTaskColorResource(getContext()))); if(task.getProgressPercentage() >= 75) diff --git a/src/com/timsu/astrid/activities/TaskView.java b/src/com/timsu/astrid/activities/TaskView.java index f188c14c5..e07ee2238 100644 --- a/src/com/timsu/astrid/activities/TaskView.java +++ b/src/com/timsu/astrid/activities/TaskView.java @@ -142,7 +142,7 @@ public class TaskView extends TaskModificationActivity { int secondsAgo = (int) ((System.currentTimeMillis() - date.getTime())/1000); String text = DateUtilities.getDurationString(r, Math.abs(secondsAgo), 2); - view.setText(text + r.getString(R.string.ago_suffix)); + view.setText(text + " " + r.getString(R.string.ago_suffix)); } /* ====================================================================== diff --git a/src/com/timsu/astrid/activities/TaskViewNotifier.java b/src/com/timsu/astrid/activities/TaskViewNotifier.java index 5ebf7fc7a..9b5e9bc41 100644 --- a/src/com/timsu/astrid/activities/TaskViewNotifier.java +++ b/src/com/timsu/astrid/activities/TaskViewNotifier.java @@ -9,8 +9,8 @@ import android.os.Bundle; import com.timsu.astrid.R; import com.timsu.astrid.utilities.Constants; +import com.timsu.astrid.utilities.DialogUtilities; import com.timsu.astrid.utilities.Notifications; -import com.timsu.astrid.widget.NNumberPickerDialog; import com.timsu.astrid.widget.NNumberPickerDialog.OnNNumberPickedListener; public class TaskViewNotifier extends TaskView { @@ -77,9 +77,9 @@ public class TaskViewNotifier extends TaskView { } private void snoozeAlert() { - Resources r = getResources(); - // ask how long - new NNumberPickerDialog(this, new OnNNumberPickedListener() { + DialogUtilities.hourMinutePicker(this, + getResources().getString(R.string.notify_snooze_title), + new OnNNumberPickedListener() { public void onNumbersPicked(int[] values) { int snoozeSeconds = values[0] * 3600 + values[1] * 60; Notifications.createSnoozeAlarm(TaskViewNotifier.this, @@ -90,8 +90,6 @@ public class TaskViewNotifier extends TaskView { TaskList.shouldCloseInstance = true; finish(); } - }, r.getString(R.string.notify_snooze_title), - new int[] {0, 0}, new int[] {1, 5}, new int[] {0, 0}, - new int[] {99, 59}, new String[] {":", null}).show(); + }); } } diff --git a/src/com/timsu/astrid/data/sync/SyncMapping.java b/src/com/timsu/astrid/data/sync/SyncMapping.java index a27f1e521..0520c80b4 100644 --- a/src/com/timsu/astrid/data/sync/SyncMapping.java +++ b/src/com/timsu/astrid/data/sync/SyncMapping.java @@ -161,8 +161,4 @@ public class SyncMapping extends AbstractModel { private void setRemoteId(String remoteId) { setValues.put(REMOTE_ID, remoteId); } - - private void setUpdated(boolean updated) { - setValues.put(UPDATED, updated ? 1 : 0); - } } diff --git a/src/com/timsu/astrid/data/task/TaskModelForList.java b/src/com/timsu/astrid/data/task/TaskModelForList.java index aad1f30f5..cc2f61ffd 100644 --- a/src/com/timsu/astrid/data/task/TaskModelForList.java +++ b/src/com/timsu/astrid/data/task/TaskModelForList.java @@ -20,6 +20,7 @@ package com.timsu.astrid.data.task; import java.util.Date; +import java.util.HashMap; import android.content.Context; import android.database.Cursor; @@ -96,6 +97,16 @@ public class TaskModelForList extends AbstractTaskModel { return super.isHidden(); } + /** map of cached display labels */ + private HashMap displayLabels = new HashMap(); + + public String getCachedLabel(int key) { + return displayLabels.get(key); + } + public void putCachedLabel(int key, String value) { + displayLabels.put(key, value); + } + // --- constructors public TaskModelForList(Cursor cursor) { @@ -205,4 +216,14 @@ public class TaskModelForList extends AbstractTaskModel { public static String getNameField() { return NAME; } + + @Override + public void setPreferredDueDate(Date preferredDueDate) { + super.setPreferredDueDate(preferredDueDate); + } + + @Override + public void setDefiniteDueDate(Date definiteDueDate) { + super.setDefiniteDueDate(definiteDueDate); + } } diff --git a/src/com/timsu/astrid/sync/RTMSyncService.java b/src/com/timsu/astrid/sync/RTMSyncService.java index b11362466..56a93c518 100644 --- a/src/com/timsu/astrid/sync/RTMSyncService.java +++ b/src/com/timsu/astrid/sync/RTMSyncService.java @@ -60,12 +60,18 @@ public class RTMSyncService extends SynchronizationService { Preferences.getSyncRTMToken(activity) == null) { DialogUtilities.okCancelDialog(activity, activity.getResources().getString(R.string.sync_rtm_notes), - new Dialog.OnClickListener() { + new Dialog.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + authenticate(activity); + } + }, new Dialog.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - authenticate(activity); + if(progressDialog != null) + progressDialog.dismiss(); } - }, null); + }); } else authenticate(activity); } @@ -335,7 +341,7 @@ public class RTMSyncService extends SynchronizationService { sb.append(note.getText() + "\n"); } if(sb.length() > 0) - task.notes = sb.toString(); + task.notes = sb.toString().trim(); // list / tags LinkedList tagsList = rtmTaskSeries.getTags(); @@ -355,8 +361,18 @@ public class RTMSyncService extends SynchronizationService { } task.creationDate = rtmTaskSeries.getCreated(); task.completionDate = rtmTask.getCompleted(); - if(rtmTask.getDue() != null) - task.definiteDueDate = rtmTask.getDue(); + if(rtmTask.getDue() != null) { + Date due = rtmTask.getDue(); + + // just a day - set it to midnight + if(due.getHours() == 0 && due.getMinutes() == 0 && due.getSeconds() == 0) { + due.setHours(23); + due.setMinutes(59); + } + + task.definiteDueDate = due; + + } task.progressPercentage = (rtmTask.getCompleted() == null) ? 0 : 100; task.importance = Importance.values()[rtmTask.getPriority().ordinal()]; diff --git a/src/com/timsu/astrid/sync/SynchronizationService.java b/src/com/timsu/astrid/sync/SynchronizationService.java index b59b0a7f6..c924edf8a 100644 --- a/src/com/timsu/astrid/sync/SynchronizationService.java +++ b/src/com/timsu/astrid/sync/SynchronizationService.java @@ -480,7 +480,7 @@ public abstract class SynchronizationService { sb.append("\nDeleted: " + localDeletedTasks); if(mergedTasks > 0) - sb.append("\n\nMerged: " + localCreatedTasks); + sb.append("\n\nMerged: " + mergedTasks); if(remoteCreatedTasks + remoteDeletedTasks + remoteUpdatedTasks > 0) sb.append("\n\nSummary - Remote Server:"); diff --git a/src/com/timsu/astrid/utilities/DialogUtilities.java b/src/com/timsu/astrid/utilities/DialogUtilities.java index 192cf878f..7c2503a6c 100644 --- a/src/com/timsu/astrid/utilities/DialogUtilities.java +++ b/src/com/timsu/astrid/utilities/DialogUtilities.java @@ -3,11 +3,21 @@ package com.timsu.astrid.utilities; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; +import android.content.res.Resources; import com.timsu.astrid.R; +import com.timsu.astrid.widget.NNumberPickerDialog; +import com.timsu.astrid.widget.NNumberPickerDialog.OnNNumberPickedListener; public class DialogUtilities { + /** + * Displays a dialog box with an OK button + * + * @param context + * @param text + * @param okListener + */ public static void okDialog(Context context, String text, DialogInterface.OnClickListener okListener) { new AlertDialog.Builder(context) @@ -18,6 +28,14 @@ public class DialogUtilities { .show(); } + /** + * Displays a dialog box with OK and Cancel buttons + * + * @param context + * @param text + * @param okListener + * @param cancelListener + */ public static void okCancelDialog(Context context, String text, DialogInterface.OnClickListener okListener, DialogInterface.OnClickListener cancelListener) { @@ -29,4 +47,36 @@ public class DialogUtilities { .setNegativeButton(android.R.string.cancel, cancelListener) .show(); } + + /** + * Displays a dialog box that lets users pick a day & hour value + * + * @param context + * @param title title of the dialog box + * @param listener what happens when users click ok + */ + public static void dayHourPicker(Context context, String title, + OnNNumberPickedListener listener) { + Resources r = context.getResources(); + new NNumberPickerDialog(context, listener, title, + new int[] {0, 0}, new int[] {1, 1}, new int[] {0, 0}, + new int[] {31, 23}, new String[] { + r.getString(R.string.daysVertical), + r.getString(R.string.hoursVertical) + }).show(); + } + + /** + * Displays a dialog box that lets users pick an hour & minute value. + * + * @param context + * @param title title of the dialog box + * @param listener what happens when users click ok + */ + public static void hourMinutePicker(Context context, String title, + OnNNumberPickedListener listener) { + new NNumberPickerDialog(context, listener, title, + new int[] {0, 0}, new int[] {1, 5}, new int[] {0, 0}, + new int[] {99, 59}, new String[] {":", null}).show(); + } } diff --git a/src/com/timsu/astrid/utilities/Notifications.java b/src/com/timsu/astrid/utilities/Notifications.java index 319c9a97a..d62668385 100644 --- a/src/com/timsu/astrid/utilities/Notifications.java +++ b/src/com/timsu/astrid/utilities/Notifications.java @@ -385,9 +385,13 @@ public class Notifications extends BroadcastReceiver { appName, reminder + " " + taskName, pendingIntent); - if(Preferences.isPersistenceMode(context)) - notification.flags |= Notification.FLAG_NO_CLEAR; notification.defaults = Notification.DEFAULT_LIGHTS; + notification.flags |= Notification.FLAG_AUTO_CANCEL; + if(Preferences.isPersistenceMode(context)) { + notification.flags |= Notification.FLAG_NO_CLEAR; + notification.ledOffMS = 5000; + notification.ledOnMS = 700; + } if(quietHours) { notification.vibrate = null; notification.sound = null; diff --git a/src/com/timsu/astrid/utilities/Preferences.java b/src/com/timsu/astrid/utilities/Preferences.java index 6e7f01298..a3b45ae3c 100644 --- a/src/com/timsu/astrid/utilities/Preferences.java +++ b/src/com/timsu/astrid/utilities/Preferences.java @@ -41,6 +41,9 @@ public class Preferences { if(!prefs.contains(r.getString(R.string.p_deadlineTime))) { editor.putString(r.getString(R.string.p_deadlineTime), "7"); } + if(!prefs.contains(r.getString(R.string.p_notif_defaultRemind))) { + editor.putString(r.getString(R.string.p_notif_defaultRemind), "7"); + } if(!prefs.contains(r.getString(R.string.p_colorize))) { editor.putBoolean(r.getString(R.string.p_colorize), DEFAULT_COLORIZE); } @@ -213,6 +216,13 @@ public class Preferences { R.string.p_sync_rtm), false); } + /** Should display sync shortcut? */ + public static boolean shouldDisplaySyncButton(Context context) { + Resources r = context.getResources(); + return getPrefs(context).getBoolean(r.getString( + R.string.p_sync_button), false); + } + /** returns the font size user wants on the front page */ public static Integer autoSyncFrequency(Context context) { return getIntegerValue(context, R.string.p_sync_every); diff --git a/src/com/timsu/astrid/utilities/VisibilityCalculator.java b/src/com/timsu/astrid/utilities/VisibilityCalculator.java deleted file mode 100644 index 6478edea4..000000000 --- a/src/com/timsu/astrid/utilities/VisibilityCalculator.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.timsu.astrid.utilities; - -public class VisibilityCalculator { - -} diff --git a/src/com/timsu/astrid/widget/TimeDurationControlSet.java b/src/com/timsu/astrid/widget/TimeDurationControlSet.java index 557e14da6..e871df7f2 100644 --- a/src/com/timsu/astrid/widget/TimeDurationControlSet.java +++ b/src/com/timsu/astrid/widget/TimeDurationControlSet.java @@ -60,8 +60,8 @@ public class TimeDurationControlSet implements OnNNumberPickedListener, activity.getResources().getString(titleResource), new int[] {0, 0}, new int[] {1, 1}, new int[] {0, 0}, new int[] {31, 23}, new String[] { - r.getString(R.string.days), - r.getString(R.string.hours) + r.getString(R.string.daysVertical), + r.getString(R.string.hoursVertical) }); break; case HOURS_MINUTES: