/*
* Copyright (c) 2015 Jonas Kalderstam.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nononsenseapps.notepad.ui.dashclock;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.preference.PreferenceManager;
import com.google.android.apps.dashclock.api.DashClockExtension;
import com.google.android.apps.dashclock.api.ExtensionData;
import com.nononsenseapps.notepad.R;
import com.nononsenseapps.notepad.data.model.sql.Task;
import com.nononsenseapps.notepad.data.model.sql.TaskList;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class TasksExtension extends DashClockExtension {
// final static Uri VISIBLE_NOTES_URI = Uri
// .parse("content://com.nononsenseapps.NotePad/visiblenotes");
// final static Uri VISIBLE_LISTS_URI = Uri
// .parse("content://com.nononsenseapps.NotePad/visiblelists");
public static final String DUEDATE_SORT_TYPE = new StringBuilder(
"CASE WHEN ").append(Task.Columns.DUE).append(" IS NULL OR ")
.append(Task.Columns.DUE).append(" IS '' THEN 1 ELSE 0 END, ")
.append(Task.Columns.DUE).toString();
private static final String WHERE_LIST_IS_AND = Task.Columns.DBLIST
+ " IS ? AND ";
private static final String WHERE_DATE_IS = new StringBuilder(
Task.Columns.COMPLETED).append(" IS NULL AND ")
.append(Task.Columns.DUE).append(" IS NOT NULL AND ")
.append(Task.Columns.DUE).append(" <= ? ").toString();
private static final String WHERE_ALL_NOTDONE = Task.Columns.COMPLETED
+ " IS NULL";
private String[] toA(final String... args) {
return args;
}
private String[] appendTo(final String[] array, final String... items) {
final String[] result = new String[array.length + items.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i];
}
for (int i = 0; i < items.length; i++) {
result[array.length + i] = items[i];
}
return result;
}
final static String[] NOTEFIELDS = new String[] { "_id", "title", "note",
"duedate" };
@Override
protected void onInitialize(boolean isReconnect) {
super.onInitialize(isReconnect);
// Watch the notes URI
addWatchContentUris(toA(TaskList.URI.toString(), Task.URI.toString()));
}
@Override
protected void onUpdateData(int reason) {
// Get preferences
final SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(this);
final long listId = Long.parseLong(prefs
.getString("list_spinner", "-1"));
final boolean showOverdue = prefs.getBoolean("show_overdue", true);
final String upperLimit = prefs.getString("list_due_upper_limit",
getString(R.string.dashclock_pref_today));
final boolean showSingle = prefs.getBoolean("show_single_only", false);
final boolean showHeader = prefs.getBoolean("show_header", true);
final ArrayList<Task> notes = getNotesFromDB(listId, upperLimit);
// Show overdue?
if (!showOverdue) {
removeOverdue(notes);
}
if (showSingle && notes.size() > 1) {
final Task first = notes.get(0);
notes.clear();
notes.add(first);
}
if (notes.isEmpty()) {
publishUpdate(null);
}
else {
final String short_header = getString(
R.string.dashclock_tasks_count, notes.size());
final String long_header;
// If no header is to be displayed, show title of first
if (showHeader) {
long_header = getHeader(listId);
}
else {
long_header = notes.get(0).title;
}
final Intent noteIntent = new Intent();
if (notes.size() > 1) {
noteIntent
.setAction(Intent.ACTION_VIEW)
.setData(
TaskList.getUri(notes.get(0).dblist.longValue()))
.putExtra(Task.TABLE_NAME, notes.get(0)._id);
}
else {
noteIntent
.setAction(Intent.ACTION_EDIT)
.setData(Task.getUri(notes.get(0)._id))
.putExtra(Task.Columns.DBLIST,
notes.get(0).dblist.longValue());
}
// Publish the extension data update.
publishUpdate(new ExtensionData().visible(true)
.icon(R.drawable.ic_stat_notification_edit)
.status(short_header).expandedTitle(long_header)
.expandedBody(getBody(notes, showHeader))
.clickIntent(noteIntent));
}
}
@SuppressWarnings("unchecked")
private void removeOverdue(final ArrayList<Task> notes) {
for (Task note : (ArrayList<Task>) notes.clone()) {
if (note.due != null
&& note.due < Calendar.getInstance().getTimeInMillis())
notes.remove(note);
}
}
private String getBody(final ArrayList<Task> notes, final boolean showHeader) {
String result = "";
if (notes.size() == 1) {
if (showHeader) {
// Skip title if no header as the title is the header
result += notes.get(0).title;
result += "\n";
}
result += notes.get(0).note;
}
else {
boolean first = true;
boolean skippable = true;
for (Task note : notes) {
if (!showHeader && skippable) {
// Skip first
skippable = false;
continue;
}
if (!first) result += "\n";
result += note.title;
first = false;
}
}
return result;
}
/**
* Return a list of notes respecting the constraints set in preferences.
*/
private ArrayList<Task> getNotesFromDB(final long list,
final String upperLimit) {
// WHERE_LIST_IS, toA(list)
String where = "";
String[] whereArgs = new String[0];
if (list > -1) {
where += WHERE_LIST_IS_AND;
whereArgs = appendTo(whereArgs, Long.toString(list));
}
where += getUpperQueryLimitWhere(upperLimit);
whereArgs = getUpperQueryLimitWhereArgs(whereArgs, upperLimit);
final Cursor cursor = getContentResolver().query(Task.URI,
Task.Columns.FIELDS, where, whereArgs, DUEDATE_SORT_TYPE);
final ArrayList<Task> result = new ArrayList<Task>();
if (cursor != null) {
while (cursor.moveToNext()) {
result.add(new Task(cursor));
}
cursor.close();
}
return result;
}
/**
* Returns the list name, or "Tasks" if all lists are to be shown.
*/
private String getHeader(final long list) {
String header = getString(R.string.dashclock_tasks);
if (list > -1) {
final Cursor cursor = getContentResolver().query(TaskList.URI,
TaskList.Columns.FIELDS, TaskList.Columns._ID + " IS ?",
new String[] { Long.toString(list) }, null);
if (cursor != null) {
if (!cursor.isClosed() && !cursor.isAfterLast()) {
if (cursor.moveToNext()) {
header = cursor.getString(1);
}
}
cursor.close();
}
}
return header;
}
private String getUpperQueryLimitWhere(final String upperLimit) {
String where = WHERE_DATE_IS;
if (getString(R.string.dashclock_pref_none).equals(upperLimit)) {
where = WHERE_ALL_NOTDONE;
}
return where;
}
private String[] getUpperQueryLimitWhereArgs(final String[] whereArgs,
final String upperLimit) {
final GregorianCalendar gc = new GregorianCalendar();
gc.set(GregorianCalendar.HOUR_OF_DAY, 23);
gc.set(GregorianCalendar.MINUTE, 59);
final long base = gc.getTimeInMillis();
final long day = 24 * 60 * 60 * 1000;
if (getString(R.string.dashclock_pref_today).equals(upperLimit)) {
return appendTo(whereArgs, Long.toString(gc.getTimeInMillis()));
}
else if (getString(R.string.dashclock_pref_tomorrow).equals(upperLimit)) {
gc.setTimeInMillis(base + 1 * day);
return appendTo(whereArgs, Long.toString(gc.getTimeInMillis()));
}
else if (getString(R.string.dashclock_pref_next7).equals(upperLimit)) {
gc.setTimeInMillis(base + 7 * day);
return appendTo(whereArgs, Long.toString(gc.getTimeInMillis()));
}
else {
return whereArgs;
}
}
}