Add due date to widget

Closes #48
pull/253/head
Alex Baker 9 years ago
parent 04452686e1
commit 2ed24dd1af

@ -383,7 +383,7 @@ public class Task extends RemoteModel {
long dueDate = getDueDate();
long compareTo = hasDueTime() ? DateUtilities.now() : DateUtilities.getStartOfDay(DateUtilities.now());
return dueDate < compareTo;
return dueDate < compareTo && !isCompleted();
}
public boolean repeatAfterCompletion() {

@ -12,6 +12,7 @@ import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ListView;
import com.todoroo.andlib.utility.AndroidUtilities;
@ -39,6 +40,7 @@ public class WidgetConfigActivity extends InjectingListActivity {
public static final String PREF_CUSTOM_INTENT = "widget-intent-";
public static final String PREF_CUSTOM_EXTRAS = "widget-extras-";
public static final String PREF_TAG_ID = "widget-tag-id-";
public static final String PREF_DUE_DATE = "widget-due-date-";
int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
@ -64,7 +66,6 @@ public class WidgetConfigActivity extends InjectingListActivity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
preferences.applyTheme();
// Set the result to CANCELED. This will cause the widget host to cancel
// out of the widget placement if they press the back button.
@ -95,26 +96,24 @@ public class WidgetConfigActivity extends InjectingListActivity {
setListAdapter(adapter);
Button button = (Button)findViewById(R.id.ok);
button.setOnClickListener(mOnClickListener);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Save configuration options
CheckBox checkBox = (CheckBox) findViewById(R.id.showDueDate);
saveConfiguration(adapter.getSelection(), checkBox.isChecked());
updateWidget();
// Make sure we pass back the original appWidgetId
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
});
}
View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// Save configuration options
saveConfiguration(adapter.getSelection());
updateWidget();
// Make sure we pass back the original appWidgetId
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
};
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
@ -135,11 +134,13 @@ public class WidgetConfigActivity extends InjectingListActivity {
adapter.unregisterRecevier();
}
private void saveConfiguration(FilterListItem filterListItem){
private void saveConfiguration(FilterListItem filterListItem, boolean showDueDate){
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
String sql = null, contentValuesString = null, title = null;
String sql = null;
String contentValuesString = null;
String title = null;
if(filterListItem != null && filterListItem instanceof Filter) {
sql = ((Filter)filterListItem).getSqlQuery();
@ -153,6 +154,7 @@ public class WidgetConfigActivity extends InjectingListActivity {
preferences.setString(WidgetConfigActivity.PREF_TITLE + mAppWidgetId, title);
preferences.setString(WidgetConfigActivity.PREF_SQL + mAppWidgetId, sql);
preferences.setString(WidgetConfigActivity.PREF_VALUES + mAppWidgetId, contentValuesString);
preferences.setBoolean(WidgetConfigActivity.PREF_DUE_DATE + mAppWidgetId, showDueDate);
if(filterListItem instanceof FilterWithCustomIntent) {
String flattenedName = ((FilterWithCustomIntent)filterListItem).customTaskList.flattenToString();

@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
import org.tasks.R;
import org.tasks.injection.InjectingService;
import org.tasks.preferences.Preferences;
import org.tasks.widget.DueDateFormatter;
import org.tasks.widget.WidgetHelper;
import javax.inject.Inject;
@ -43,6 +44,7 @@ public class WidgetUpdateService extends InjectingService {
@Inject WidgetHelper widgetHelper;
@Inject Preferences preferences;
@Inject SubtasksHelper subtasksHelper;
@Inject DueDateFormatter dueDateFormatter;
@Override
public void onStart(final Intent intent, int startId) {
@ -109,30 +111,32 @@ public class WidgetUpdateService extends InjectingService {
filter.getSqlQuery(), flags, sort).replaceAll("LIMIT \\d+", "") + " LIMIT " + numberOfTasks;
String tagName = preferences.getStringValue(WidgetConfigActivity.PREF_TITLE + widgetId);
boolean showDueDates = preferences.getBoolean(WidgetConfigActivity.PREF_DUE_DATE + widgetId, false);
query = subtasksHelper.applySubtasksToWidgetFilter(filter, query, tagName, numberOfTasks);
database.openForReading();
cursor = taskService.fetchFiltered(query, null, Task.ID, Task.TITLE, Task.DUE_DATE, Task.COMPLETION_DATE);
int i;
Resources r = context.getResources();
for (i = 0; i < cursor.getCount() && i < numberOfTasks; i++) {
cursor.moveToPosition(i);
Task task = new Task(cursor);
String textContent;
Resources r = context.getResources();
int textColor = r
.getColor(preferences.isDarkWidgetTheme() ? R.color.widget_text_color_dark : R.color.widget_text_color_light);
textContent = task.getTitle();
String textContent = task.getTitle();
int textColor = r.getColor(preferences.isDarkWidgetTheme()
? R.color.widget_text_color_dark
: R.color.widget_text_color_light);
if(task.isCompleted()) {
textColor = r.getColor(R.color.task_list_done);
} else if(task.hasDueDate() && task.isOverdue()) {
textColor = r.getColor(R.color.task_list_overdue);
}
RemoteViews row = new RemoteViews(Constants.PACKAGE, R.layout.widget_row);
if (showDueDates) {
dueDateFormatter.formatDueDate(row, task, textColor);
} else if(task.hasDueDate() && task.isOverdue()) {
textColor = r.getColor(R.color.task_list_overdue);
}
row.setTextViewText(R.id.text, textContent);
row.setTextColor(R.id.text, textColor);

@ -0,0 +1,61 @@
package org.tasks.widget;
import android.content.Context;
import android.content.res.Resources;
import android.opengl.Visibility;
import android.view.View;
import android.widget.RemoteViews;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Task;
import org.tasks.R;
import org.tasks.injection.ForApplication;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import static org.tasks.date.DateTimeUtils.newDate;
public class DueDateFormatter {
private final Map<Long, String> dateCache = new HashMap<>();
private final Context context;
private final Resources resources;
@Inject
public DueDateFormatter(@ForApplication Context context) {
this.context = context;
resources = context.getResources();
}
public void formatDueDate(RemoteViews row, Task task, int textColor) {
if (task.hasDueDate() || task.hasDueTime()) {
row.setViewVisibility(R.id.dueDate, View.VISIBLE);
row.setTextViewText(R.id.dueDate, task.isCompleted()
? resources.getString(R.string.TAd_completed, formatDate(task.getCompletionDate()))
: formatDate(task.getDueDate()));
row.setTextColor(R.id.dueDate, task.isOverdue() ? resources.getColor(R.color.task_list_overdue) : textColor);
} else {
row.setViewVisibility(R.id.dueDate, View.GONE);
}
}
private String formatDate(long date) {
if (dateCache.containsKey(date)) {
return dateCache.get(date);
}
String formatString = "%s %s";
String string = DateUtilities.getRelativeDay(context, date);
if (Task.hasDueTime(date)) {
string = String.format(formatString, string, //$NON-NLS-1$
DateUtilities.getTimeString(context, newDate(date)));
}
dateCache.put(date, string);
return string;
}
}

@ -45,6 +45,8 @@ public class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFac
private final Filter filter;
private final int widgetId;
private boolean dark;
private boolean showDueDates;
private final DueDateFormatter dueDateFormatter;
private TodorooCursor<Task> cursor;
@ -65,10 +67,13 @@ public class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFac
this.dark = dark;
this.database = database;
this.taskService = taskService;
dueDateFormatter = new DueDateFormatter(context);
}
@Override
public void onCreate() {
showDueDates = preferences.getBoolean(WidgetConfigActivity.PREF_DUE_DATE + widgetId, false);
database.openForReading();
cursor = getCursor();
}
@ -146,9 +151,12 @@ public class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFac
row.setInt(R.id.text, "setPaintFlags", Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
} else {
row.setInt(R.id.text, "setPaintFlags", Paint.ANTI_ALIAS_FLAG);
if (task.hasDueDate() && task.isOverdue()) {
textColor = r.getColor(R.color.task_list_overdue);
}
}
if (showDueDates) {
dueDateFormatter.formatDueDate(row, task, textColor);
} else if (task.hasDueDate() && task.isOverdue()) {
textColor = r.getColor(R.color.task_list_overdue);
}
row.setTextViewText(R.id.text, textContent);

@ -14,13 +14,10 @@ import android.os.Bundle;
import android.widget.RemoteViews;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.activity.TaskEditActivity;
import com.todoroo.astrid.activity.TaskEditFragment;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterWithCustomIntent;
import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.core.BuiltInFilterExposer;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.data.TagData;

@ -2,27 +2,38 @@
<!-- See the file "LICENSE" for the full license governing this code.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="?attr/asContentBackground">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/asContentBackground"
android:orientation="vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:checked="true"
android:id="@+id/showDueDate"
android:text="@string/widget_show_due_date"
android:textSize="18sp"
android:paddingTop="10dp"
android:paddingBottom="10dp" />
<!-- Title -->
<TextView
style="TextAppearance.ActionBar_ListsHeader"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="10dp"
android:text="@string/WCA_title"
android:padding="10dip"
style="TextAppearance.ActionBar_ListsHeader" />
android:textSize="18sp" />
<!-- List -->
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100"
android:scrollbars="vertical"
android:cacheColorHint="#00000000"/>
android:cacheColorHint="#00000000"
android:scrollbars="vertical"/>
<!-- List -->
<Button android:id="@+id/ok"
@ -30,6 +41,6 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@android:string/ok"/>
</LinearLayout>

@ -4,24 +4,50 @@
** See the file "LICENSE" for the full license governing this code.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="35dp">
<ImageView
android:id="@+id/completeBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"/>
android:layout_gravity="center_vertical|center_horizontal" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="5dp"
android:id="@+id/text"
android:background="@android:color/transparent"
style="@style/TextAppearance.Widget"
android:singleLine="true"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:id="@+id/text"
style="@style/TextAppearance.Widget"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="@android:color/transparent"
android:paddingEnd="0dp"
android:paddingLeft="5dp"
android:paddingRight="0dp"
android:paddingStart="5dp"
android:singleLine="true" />
<TextView
android:id="@+id/dueDate"
style="@style/TextAppearance.WidgetDueDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center_vertical"
android:layout_marginTop="-3dp"
android:paddingEnd="0dp"
android:paddingLeft="5dp"
android:paddingRight="0dp"
android:paddingStart="5dp"
android:singleLine="true"
android:visibility="gone"/>
</LinearLayout>
</LinearLayout>

@ -114,6 +114,7 @@
<!-- Sync error: network connectivity problems. %s-> name of sync service-->
<string name="sync_error_offline">There was a problem connecting to the network
during the last sync with %s. Please try again later.</string>
<string name="widget_show_due_date">Show due date</string>
<string-array name="sync_SPr_interval_entries">
<!-- sync_SPr_interval_entries: Synchronization Intervals -->

@ -250,6 +250,11 @@
<item name="android:textColor">@color/widget_text_color_light</item>
</style>
<style name="TextAppearance.WidgetDueDate">
<item name="android:textSize">12sp</item>
<item name="android:textColor">@color/widget_text_color_light</item>
</style>
<!-- ========================================================= Premium == -->
<style name="TextAppearance.Medium">

Loading…
Cancel
Save