Bugfixes Galore:

- couldn't dismiss initial RTM welcome box
   - duplicated sync notes
   - space between elapsed time & "ago" in view page
   - performance improvements: caching and not inflating on view list
   - tasks due "today" are due at midnight

  New features:
   - postpone button
   - filters persisted
   - timer icon made vertical
   - added a sync shortcut
   - improved cosmetics of the strikeout
pull/14/head
Tim Su 17 years ago
parent 1ccdab86a6
commit 8a247fce08

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 B

@ -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" >
<CheckBox android:id="@+id/cb1"
<!-- icons on the left -->
<LinearLayout android:id="@+id/icon_layout"
android:orientation="vertical"
android:minWidth="41px"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:scaleType="center"
android:minWidth="41px" />
android:layout_height="fill_parent">
<ImageView android:id="@+id/imageLeft"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:scaleType="center"
android:paddingLeft="5dip"/>
<CheckBox android:id="@+id/cb1"
android:paddingBottom="5px"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center" />
<ImageView android:id="@+id/imageLeft"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"/>
</LinearLayout>
<!-- all text -->
<LinearLayout android:id="@+id/text_layout"
@ -105,7 +116,7 @@
</LinearLayout>
<!-- importance -->
<ImageView android:id="@+id/importance"
<View android:id="@+id/importance"
android:layout_width="12px"
android:layout_height="fill_parent"
android:paddingLeft="6dip"/>

@ -60,12 +60,12 @@
<item quantity="one">1 Day</item>
<item quantity="other">%d Days</item>
</plurals>
<string name="days">D\na\ny\ns</string>
<string name="daysVertical">D\na\ny\ns</string>
<plurals name="Nhours">
<item quantity="one">1 Hour</item>
<item quantity="other">%d Hours</item>
</plurals>
<string name="hours">H\no\nu\nr\ns</string>
<string name="hoursVertical">H\no\nu\nr\ns</string>
<plurals name="Nminutes">
<item quantity="one">1 Minute</item>
<item quantity="other">%d Minutes</item>
@ -98,6 +98,7 @@
<string name="taskList_menu_insert">Add</string>
<string name="taskList_menu_tags">Tags</string>
<string name="taskList_menu_filters">Display</string>
<string name="taskList_menu_syncshortcut">Sync</string>
<string name="taskList_menu_more">More</string>
<string name="taskList_menu_sync">Synchronization</string>
<string name="taskList_menu_settings">Settings</string>
@ -107,6 +108,7 @@
<string name="taskList_context_delete">Delete Task</string>
<string name="taskList_context_startTimer">Start Timer</string>
<string name="taskList_context_stopTimer">Stop Timer</string>
<string name="taskList_context_postpone">Postpone</string>
<string name="taskList_filter_title">Sort/Filters</string>
<string name="taskList_filter_hidden">Hidden/Blocked Tasks</string>
@ -116,6 +118,8 @@
<string name="taskList_sort_alpha">Sort By Name</string>
<string name="taskList_sort_duedate">Sort By Due Date</string>
<string name="taskList_sort_reverse">Sort Reverse</string>
<string name="taskList_postpone_dialog">Postpone for how long?</string>
<!-- TaskEdit -->
<skip />
@ -209,15 +213,21 @@ If you don\'t want to see the new task right after you complete the old one, you
<!-- Synchronization -->
<skip />
<string name="p_sync_rtm">sync_rtm</string>
<string name="p_sync_every">sync_every</string>
<string name="sync_pref_group">Synchronization Services</string>
<string name="sync_pref_group_actions">Actions</string>
<string name="sync_pref_group_options">Options</string>
<string name="p_sync_rtm">sync_rtm</string>
<string name="sync_rtm_title">Remember The Milk</string>
<string name="sync_rtm_desc">http://www.rememberthemilk.com</string>
<string name="p_sync_every">sync_every</string>
<string name="sync_every_title">Synchronize Frequency</string>
<string name="sync_every_desc">If set, sync every # hours when Astrid starts</string>
<string name="sync_every_desc">If set, perform sync every # hours</string>
<string name="p_sync_button">sync_button</string>
<string name="sync_button_title">Main Menu Shortcut</string>
<string name="sync_button_desc">Show \"Synchronize\" in Astrid\'s menu</string>
<string name="p_sync_background">sync_background</string>
<string name="sync_background_title">In Background</string>
<string name="sync_background_desc">Synchronize without bothering you</string>
<string name="sync_error">Sync Error! Sorry for the inconvenience! Error:</string>
<string name="sync_auth_request">
In order to synchronize, please log in to your %s account and authorize Astrid to read your data.

@ -18,7 +18,12 @@
<EditTextPreference
android:key="@string/p_sync_every"
android:title="@string/sync_every_title"
android:summary="@string/sync_every_desc" />
android:summary="@string/sync_every_desc" />
<CheckBoxPreference
android:key="@string/p_sync_button"
android:title="@string/sync_button_title"
android:summary="@string/sync_button_desc" />
</PreferenceCategory>

@ -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;

@ -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() {
//
}
/**

@ -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<TaskModelForList, LinkedList<TagModelForView>> 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:

@ -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<TaskModelForList> {
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<TaskModelForList> objects;
@ -72,6 +83,8 @@ public class TaskListAdapter extends ArrayAdapter<TaskModelForList> {
private Integer fontSizePreference;
private AlertController alarmController;
private TaskModelForList recentlyCompleted = null;
public interface TaskListAdapterHooks {
List<TaskModelForList> getTaskArray();
List<TagModelForView> getTagsFor(TaskModelForList task);
@ -100,9 +113,10 @@ public class TaskListAdapter extends ArrayAdapter<TaskModelForList> {
@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<TaskModelForList> {
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<TaskModelForList> {
// 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<TaskModelForList> {
// 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<TaskModelForList> {
// 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<Date> 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<Date> 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<TagModelForView> alltags = hooks.getTagsFor(task);
StringBuilder tagString = new StringBuilder();
for(Iterator<TagModelForView> 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<TagModelForView> alltags = hooks.getTagsFor(task);
StringBuilder tagString = new StringBuilder();
for(Iterator<TagModelForView> 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<TaskModelForList> {
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<TaskModelForList> {
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<TaskModelForList> {
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)

@ -142,7 +142,7 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
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));
}
/* ======================================================================

@ -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();
});
}
}

@ -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);
}
}

@ -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<Integer, String> displayLabels = new HashMap<Integer, String>();
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);
}
}

@ -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<String> 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()];

@ -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:");

@ -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();
}
}

@ -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;

@ -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);

@ -1,5 +0,0 @@
package com.timsu.astrid.utilities;
public class VisibilityCalculator {
}

@ -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:

Loading…
Cancel
Save