Merge remote branch 'origin/master' into dev

pull/14/head
Tim Su 14 years ago
commit b50e22996c

@ -16,7 +16,7 @@ Getting Started With Development
*[Eclipse](http://eclipse.org)* (preferred: Eclipse IDE for Java Developers)
• *[Android SDK](http://developer.android.com/sdk/index.html)*
3. Use **git** to clone your forked repository (see Github's instructions if you need help).
3. Use **git** to clone your forked repository (see Github's instructions if you need help). Follow the [Github Line Ending Help](http://help.github.com/dealing-with-lineendings/)
4. Open up **eclipse** and import the *astrid* and *astrid-tests* projects.

@ -1,89 +1,89 @@
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.AND;
import static com.todoroo.andlib.sql.SqlConstants.EXISTS;
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.NOT;
import static com.todoroo.andlib.sql.SqlConstants.OR;
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public abstract class Criterion {
protected final Operator operator;
Criterion(Operator operator) {
this.operator = operator;
}
public static Criterion all = new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(1);
}
};
public static Criterion none = new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(0);
}
};
public static Criterion and(final Criterion criterion, final Criterion... criterions) {
return new Criterion(Operator.and) {
@Override
protected void populate(StringBuilder sb) {
sb.append(criterion);
for (Criterion c : criterions) {
sb.append(SPACE).append(AND).append(SPACE).append(c);
}
}
};
}
public static Criterion or(final Criterion criterion, final Criterion... criterions) {
return new Criterion(Operator.or) {
@Override
protected void populate(StringBuilder sb) {
sb.append(criterion);
for (Criterion c : criterions) {
sb.append(SPACE).append(OR).append(SPACE).append(c.toString());
}
}
};
}
public static Criterion exists(final Query query) {
return new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(EXISTS).append(SPACE).append(LEFT_PARENTHESIS).append(query).append(RIGHT_PARENTHESIS);
}
};
}
public static Criterion not(final Criterion criterion) {
return new Criterion(Operator.not) {
@Override
protected void populate(StringBuilder sb) {
sb.append(NOT).append(SPACE);
criterion.populate(sb);
}
};
}
protected abstract void populate(StringBuilder sb);
@Override
public String toString() {
StringBuilder builder = new StringBuilder(LEFT_PARENTHESIS);
populate(builder);
builder.append(RIGHT_PARENTHESIS);
return builder.toString();
}
}
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.AND;
import static com.todoroo.andlib.sql.SqlConstants.EXISTS;
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.NOT;
import static com.todoroo.andlib.sql.SqlConstants.OR;
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public abstract class Criterion {
protected final Operator operator;
Criterion(Operator operator) {
this.operator = operator;
}
public static Criterion all = new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(1);
}
};
public static Criterion none = new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(0);
}
};
public static Criterion and(final Criterion criterion, final Criterion... criterions) {
return new Criterion(Operator.and) {
@Override
protected void populate(StringBuilder sb) {
sb.append(criterion);
for (Criterion c : criterions) {
sb.append(SPACE).append(AND).append(SPACE).append(c);
}
}
};
}
public static Criterion or(final Criterion criterion, final Criterion... criterions) {
return new Criterion(Operator.or) {
@Override
protected void populate(StringBuilder sb) {
sb.append(criterion);
for (Criterion c : criterions) {
sb.append(SPACE).append(OR).append(SPACE).append(c.toString());
}
}
};
}
public static Criterion exists(final Query query) {
return new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(EXISTS).append(SPACE).append(LEFT_PARENTHESIS).append(query).append(RIGHT_PARENTHESIS);
}
};
}
public static Criterion not(final Criterion criterion) {
return new Criterion(Operator.not) {
@Override
protected void populate(StringBuilder sb) {
sb.append(NOT).append(SPACE);
criterion.populate(sb);
}
};
}
protected abstract void populate(StringBuilder sb);
@Override
public String toString() {
StringBuilder builder = new StringBuilder(LEFT_PARENTHESIS);
populate(builder);
builder.append(RIGHT_PARENTHESIS);
return builder.toString();
}
}

@ -1,67 +1,67 @@
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.AS;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
protected String alias;
protected final String expression;
protected DBObject(String expression){
this.expression = expression;
}
public T as(String newAlias) {
try {
T clone = (T) clone();
clone.alias = newAlias;
return clone;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public boolean hasAlias() {
return alias != null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DBObject<?> dbObject = (DBObject<?>) o;
if (alias != null ? !alias.equals(dbObject.alias) : dbObject.alias != null) return false;
if (expression != null ? !expression.equals(dbObject.expression) : dbObject.expression != null) return false;
return true;
}
@Override
public int hashCode() {
int result = alias != null ? alias.hashCode() : 0;
result = 31 * result + (expression != null ? expression.hashCode() : 0);
return result;
}
@Override
public final String toString() {
if (hasAlias()) {
return alias;
}
return expression;
}
public final String toStringInSelect() {
StringBuilder sb = new StringBuilder(expression);
if (hasAlias()) {
sb.append(SPACE).append(AS).append(SPACE).append(alias);
} else {
int pos = expression.indexOf('.');
if(pos > 0)
sb.append(SPACE).append(AS).append(SPACE).append(expression.substring(pos + 1));
}
return sb.toString();
}
}
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.AS;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
protected String alias;
protected final String expression;
protected DBObject(String expression){
this.expression = expression;
}
public T as(String newAlias) {
try {
T clone = (T) clone();
clone.alias = newAlias;
return clone;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public boolean hasAlias() {
return alias != null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DBObject<?> dbObject = (DBObject<?>) o;
if (alias != null ? !alias.equals(dbObject.alias) : dbObject.alias != null) return false;
if (expression != null ? !expression.equals(dbObject.expression) : dbObject.expression != null) return false;
return true;
}
@Override
public int hashCode() {
int result = alias != null ? alias.hashCode() : 0;
result = 31 * result + (expression != null ? expression.hashCode() : 0);
return result;
}
@Override
public final String toString() {
if (hasAlias()) {
return alias;
}
return expression;
}
public final String toStringInSelect() {
StringBuilder sb = new StringBuilder(expression);
if (hasAlias()) {
sb.append(SPACE).append(AS).append(SPACE).append(alias);
} else {
int pos = expression.indexOf('.');
if(pos > 0)
sb.append(SPACE).append(AS).append(SPACE).append(expression.substring(pos + 1));
}
return sb.toString();
}
}

@ -1,7 +1,7 @@
package com.todoroo.andlib.sql;
public class EqCriterion extends UnaryCriterion {
EqCriterion(Field field, Object value) {
super(field, Operator.eq, value);
}
}
package com.todoroo.andlib.sql;
public class EqCriterion extends UnaryCriterion {
EqCriterion(Field field, Object value) {
super(field, Operator.eq, value);
}
}

@ -1,95 +1,95 @@
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.AND;
import static com.todoroo.andlib.sql.SqlConstants.BETWEEN;
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public class Field extends DBObject<Field> {
protected Field(String expression) {
super(expression);
}
public static Field field(String expression) {
return new Field(expression);
}
public Criterion eq(Object value) {
if(value == null)
return UnaryCriterion.isNull(this);
return UnaryCriterion.eq(this, value);
}
public Criterion neq(Object value) {
if(value == null)
return UnaryCriterion.isNotNull(this);
return UnaryCriterion.neq(this, value);
}
public Criterion gt(Object value) {
return UnaryCriterion.gt(this, value);
}
public Criterion lt(final Object value) {
return UnaryCriterion.lt(this, value);
}
public Criterion isNull() {
return UnaryCriterion.isNull(this);
}
public Criterion isNotNull() {
return UnaryCriterion.isNotNull(this);
}
public Criterion between(final Object lower, final Object upper) {
final Field field = this;
return new Criterion(null) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(BETWEEN).append(SPACE).append(lower).append(SPACE).append(AND)
.append(SPACE).append(upper);
}
};
}
public Criterion like(final String value) {
return UnaryCriterion.like(this, value);
}
public Criterion like(String value, String escape) {
return UnaryCriterion.like(this, value, escape);
}
public <T> Criterion in(final T... value) {
final Field field = this;
return new Criterion(Operator.in) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS);
for (T t : value) {
sb.append(t.toString()).append(COMMA);
}
sb.deleteCharAt(sb.length() - 1).append(RIGHT_PARENTHESIS);
}
};
}
public Criterion in(final Query query) {
final Field field = this;
return new Criterion(Operator.in) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS).append(query)
.append(RIGHT_PARENTHESIS);
}
};
}
}
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.AND;
import static com.todoroo.andlib.sql.SqlConstants.BETWEEN;
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public class Field extends DBObject<Field> {
protected Field(String expression) {
super(expression);
}
public static Field field(String expression) {
return new Field(expression);
}
public Criterion eq(Object value) {
if(value == null)
return UnaryCriterion.isNull(this);
return UnaryCriterion.eq(this, value);
}
public Criterion neq(Object value) {
if(value == null)
return UnaryCriterion.isNotNull(this);
return UnaryCriterion.neq(this, value);
}
public Criterion gt(Object value) {
return UnaryCriterion.gt(this, value);
}
public Criterion lt(final Object value) {
return UnaryCriterion.lt(this, value);
}
public Criterion isNull() {
return UnaryCriterion.isNull(this);
}
public Criterion isNotNull() {
return UnaryCriterion.isNotNull(this);
}
public Criterion between(final Object lower, final Object upper) {
final Field field = this;
return new Criterion(null) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(BETWEEN).append(SPACE).append(lower).append(SPACE).append(AND)
.append(SPACE).append(upper);
}
};
}
public Criterion like(final String value) {
return UnaryCriterion.like(this, value);
}
public Criterion like(String value, String escape) {
return UnaryCriterion.like(this, value, escape);
}
public <T> Criterion in(final T... value) {
final Field field = this;
return new Criterion(Operator.in) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS);
for (T t : value) {
sb.append(t.toString()).append(COMMA);
}
sb.deleteCharAt(sb.length() - 1).append(RIGHT_PARENTHESIS);
}
};
}
public Criterion in(final Query query) {
final Field field = this;
return new Criterion(Operator.in) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS).append(query)
.append(RIGHT_PARENTHESIS);
}
};
}
}

@ -1,14 +1,14 @@
package com.todoroo.andlib.sql;
import java.util.ArrayList;
import java.util.List;
public class GroupBy {
private List<Field> fields = new ArrayList<Field>();
public static GroupBy groupBy(Field field) {
GroupBy groupBy = new GroupBy();
groupBy.fields.add(field);
return groupBy;
}
}
package com.todoroo.andlib.sql;
import java.util.ArrayList;
import java.util.List;
public class GroupBy {
private List<Field> fields = new ArrayList<Field>();
public static GroupBy groupBy(Field field) {
GroupBy groupBy = new GroupBy();
groupBy.fields.add(field);
return groupBy;
}
}

@ -1,43 +1,43 @@
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.JOIN;
import static com.todoroo.andlib.sql.SqlConstants.ON;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public class Join {
private final SqlTable joinTable;
private final JoinType joinType;
private final Criterion[] criterions;
private Join(SqlTable table, JoinType joinType, Criterion... criterions) {
joinTable = table;
this.joinType = joinType;
this.criterions = criterions;
}
public static Join inner(SqlTable expression, Criterion... criterions) {
return new Join(expression, JoinType.INNER, criterions);
}
public static Join left(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.LEFT, criterions);
}
public static Join right(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.RIGHT, criterions);
}
public static Join out(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.OUT, criterions);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(joinType).append(SPACE).append(JOIN).append(SPACE).append(joinTable).append(SPACE).append(ON);
for (Criterion criterion : criterions) {
sb.append(SPACE).append(criterion);
}
return sb.toString();
}
}
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.JOIN;
import static com.todoroo.andlib.sql.SqlConstants.ON;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public class Join {
private final SqlTable joinTable;
private final JoinType joinType;
private final Criterion[] criterions;
private Join(SqlTable table, JoinType joinType, Criterion... criterions) {
joinTable = table;
this.joinType = joinType;
this.criterions = criterions;
}
public static Join inner(SqlTable expression, Criterion... criterions) {
return new Join(expression, JoinType.INNER, criterions);
}
public static Join left(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.LEFT, criterions);
}
public static Join right(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.RIGHT, criterions);
}
public static Join out(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.OUT, criterions);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(joinType).append(SPACE).append(JOIN).append(SPACE).append(joinTable).append(SPACE).append(ON);
for (Criterion criterion : criterions) {
sb.append(SPACE).append(criterion);
}
return sb.toString();
}
}

@ -1,5 +1,5 @@
package com.todoroo.andlib.sql;
public enum JoinType {
INNER, LEFT, RIGHT, OUT
}
package com.todoroo.andlib.sql;
public enum JoinType {
INNER, LEFT, RIGHT, OUT
}

@ -1,57 +1,57 @@
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("nls")
public final class Operator {
private final String operator;
public static final Operator eq = new Operator("=");
public static final Operator neq = new Operator("<>");
public static final Operator isNull = new Operator("IS NULL");
public static final Operator isNotNull = new Operator("IS NOT NULL");
public static final Operator gt = new Operator(">");
public static final Operator lt = new Operator("<");
public static final Operator gte = new Operator(">=");
public static final Operator lte = new Operator("<=");
public static final Operator and = new Operator("AND");
public static final Operator or = new Operator("OR");
public static final Operator not = new Operator("NOT");
public static final Operator exists = new Operator("EXISTS");
public static final Operator like = new Operator("LIKE");
public static final Operator in = new Operator("IN");
private static final Map<Operator, Operator> contraryRegistry = new HashMap<Operator, Operator>();
static {
contraryRegistry.put(eq, neq);
contraryRegistry.put(neq, eq);
contraryRegistry.put(isNull, isNotNull);
contraryRegistry.put(isNotNull, isNull);
contraryRegistry.put(gt, lte);
contraryRegistry.put(lte, gt);
contraryRegistry.put(lt, gte);
contraryRegistry.put(gte, lt);
}
private Operator(String operator) {
this.operator = operator;
}
public Operator getContrary() {
if(!contraryRegistry.containsKey(this)){
Operator opposite = new Operator(not.toString() + SPACE + this.toString());
contraryRegistry.put(this, opposite);
contraryRegistry.put(opposite, this);
}
return contraryRegistry.get(this);
}
@Override
public String toString() {
return this.operator.toString();
}
}
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("nls")
public final class Operator {
private final String operator;
public static final Operator eq = new Operator("=");
public static final Operator neq = new Operator("<>");
public static final Operator isNull = new Operator("IS NULL");
public static final Operator isNotNull = new Operator("IS NOT NULL");
public static final Operator gt = new Operator(">");
public static final Operator lt = new Operator("<");
public static final Operator gte = new Operator(">=");
public static final Operator lte = new Operator("<=");
public static final Operator and = new Operator("AND");
public static final Operator or = new Operator("OR");
public static final Operator not = new Operator("NOT");
public static final Operator exists = new Operator("EXISTS");
public static final Operator like = new Operator("LIKE");
public static final Operator in = new Operator("IN");
private static final Map<Operator, Operator> contraryRegistry = new HashMap<Operator, Operator>();
static {
contraryRegistry.put(eq, neq);
contraryRegistry.put(neq, eq);
contraryRegistry.put(isNull, isNotNull);
contraryRegistry.put(isNotNull, isNull);
contraryRegistry.put(gt, lte);
contraryRegistry.put(lte, gt);
contraryRegistry.put(lt, gte);
contraryRegistry.put(gte, lt);
}
private Operator(String operator) {
this.operator = operator;
}
public Operator getContrary() {
if(!contraryRegistry.containsKey(this)){
Operator opposite = new Operator(not.toString() + SPACE + this.toString());
contraryRegistry.put(this, opposite);
contraryRegistry.put(opposite, this);
}
return contraryRegistry.get(this);
}
@Override
public String toString() {
return this.operator.toString();
}
}

@ -1,30 +1,37 @@
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public class Order {
private final Object expression;
private final OrderType orderType;
private Order(Object expression) {
this(expression, OrderType.ASC);
}
private Order(Object expression, OrderType orderType) {
this.expression = expression;
this.orderType = orderType;
}
public static Order asc(Object expression) {
return new Order(expression);
}
public static Order desc(Object expression) {
return new Order(expression, OrderType.DESC);
}
@Override
public String toString() {
return expression + SPACE + orderType;
}
}
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public class Order {
private final Object expression;
private final OrderType orderType;
private Order(Object expression) {
this(expression, OrderType.ASC);
}
private Order(Object expression, OrderType orderType) {
this.expression = expression;
this.orderType = orderType;
}
public static Order asc(Object expression) {
return new Order(expression);
}
public static Order desc(Object expression) {
return new Order(expression, OrderType.DESC);
}
@Override
public String toString() {
return expression + SPACE + orderType;
}
public Order reverse() {
if(orderType == OrderType.ASC)
return new Order(expression, OrderType.DESC);
else
return new Order(expression, OrderType.ASC);
}
}

@ -1,5 +1,5 @@
package com.todoroo.andlib.sql;
public enum OrderType {
DESC, ASC
}
package com.todoroo.andlib.sql;
public enum OrderType {
DESC, ASC
}

@ -1,205 +1,205 @@
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.ALL;
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
import static com.todoroo.andlib.sql.SqlConstants.FROM;
import static com.todoroo.andlib.sql.SqlConstants.GROUP_BY;
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.LIMIT;
import static com.todoroo.andlib.sql.SqlConstants.ORDER_BY;
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.SELECT;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
import static com.todoroo.andlib.sql.SqlConstants.WHERE;
import static com.todoroo.andlib.sql.SqlTable.table;
import static java.util.Arrays.asList;
import java.util.ArrayList;
import com.todoroo.andlib.data.Property;
public final class Query {
private SqlTable table;
private String queryTemplate = null;
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
private final ArrayList<Field> fields = new ArrayList<Field>();
private final ArrayList<Join> joins = new ArrayList<Join>();
private final ArrayList<Field> groupBies = new ArrayList<Field>();
private final ArrayList<Order> orders = new ArrayList<Order>();
private final ArrayList<Criterion> havings = new ArrayList<Criterion>();
private int limits = -1;
private Query(Field... fields) {
this.fields.addAll(asList(fields));
}
public static Query select(Field... fields) {
return new Query(fields);
}
public Query from(SqlTable fromTable) {
this.table = fromTable;
return this;
}
public Query join(Join... join) {
joins.addAll(asList(join));
return this;
}
public Query where(Criterion criterion) {
criterions.add(criterion);
return this;
}
public Query groupBy(Field... groupBy) {
groupBies.addAll(asList(groupBy));
return this;
}
public Query orderBy(Order... order) {
orders.addAll(asList(order));
return this;
}
public Query limit(int limit) {
limits = limit;
return this;
}
public Query appendSelectFields(Property<?>... selectFields) {
this.fields.addAll(asList(selectFields));
return this;
}
@Override
public boolean equals(Object o) {
return this == o || !(o == null || getClass() != o.getClass()) && this.toString().equals(o.toString());
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public String toString() {
StringBuilder sql = new StringBuilder();
visitSelectClause(sql);
visitFromClause(sql);
visitJoinClause(sql);
if(queryTemplate == null) {
visitWhereClause(sql);
visitGroupByClause(sql);
visitOrderByClause(sql);
visitLimitClause(sql);
} else {
if(groupBies.size() > 0 || orders.size() > 0 ||
havings.size() > 0)
throw new IllegalStateException("Can't have extras AND query template"); //$NON-NLS-1$
sql.append(queryTemplate);
}
return sql.toString();
}
private void visitOrderByClause(StringBuilder sql) {
if (orders.isEmpty()) {
return;
}
sql.append(ORDER_BY);
for (Order order : orders) {
sql.append(SPACE).append(order).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
@SuppressWarnings("nls")
private void visitGroupByClause(StringBuilder sql) {
if (groupBies.isEmpty()) {
return;
}
sql.append(GROUP_BY);
for (Field groupBy : groupBies) {
sql.append(SPACE).append(groupBy).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
if (havings.isEmpty()) {
return;
}
sql.append("HAVING");
for (Criterion havingCriterion : havings) {
sql.append(SPACE).append(havingCriterion).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
private void visitWhereClause(StringBuilder sql) {
if (criterions.isEmpty()) {
return;
}
sql.append(WHERE);
for (Criterion criterion : criterions) {
sql.append(SPACE).append(criterion).append(SPACE);
}
}
private void visitJoinClause(StringBuilder sql) {
for (Join join : joins) {
sql.append(join).append(SPACE);
}
}
private void visitFromClause(StringBuilder sql) {
if (table == null) {
return;
}
sql.append(FROM).append(SPACE).append(table).append(SPACE);
}
private void visitSelectClause(StringBuilder sql) {
sql.append(SELECT).append(SPACE);
if (fields.isEmpty()) {
sql.append(ALL).append(SPACE);
return;
}
for (Field field : fields) {
sql.append(field.toStringInSelect()).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
private void visitLimitClause(StringBuilder sql) {
if(limits > -1)
sql.append(LIMIT).append(SPACE).append(limits).append(SPACE);
}
public SqlTable as(String alias) {
return table(LEFT_PARENTHESIS + this.toString() + RIGHT_PARENTHESIS).as(alias);
}
public Query having(Criterion criterion) {
this.havings.add(criterion);
return this;
}
/**
* Gets a list of fields returned by this query
* @return
*/
public Property<?>[] getFields() {
return fields.toArray(new Property<?>[fields.size()]);
}
/**
* Add the SQL query template (comes after the "from")
* @param sqlQuery
* @return
*/
public Query withQueryTemplate(String template) {
queryTemplate = template;
return this;
}
}
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.ALL;
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
import static com.todoroo.andlib.sql.SqlConstants.FROM;
import static com.todoroo.andlib.sql.SqlConstants.GROUP_BY;
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.LIMIT;
import static com.todoroo.andlib.sql.SqlConstants.ORDER_BY;
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.SELECT;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
import static com.todoroo.andlib.sql.SqlConstants.WHERE;
import static com.todoroo.andlib.sql.SqlTable.table;
import static java.util.Arrays.asList;
import java.util.ArrayList;
import com.todoroo.andlib.data.Property;
public final class Query {
private SqlTable table;
private String queryTemplate = null;
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
private final ArrayList<Field> fields = new ArrayList<Field>();
private final ArrayList<Join> joins = new ArrayList<Join>();
private final ArrayList<Field> groupBies = new ArrayList<Field>();
private final ArrayList<Order> orders = new ArrayList<Order>();
private final ArrayList<Criterion> havings = new ArrayList<Criterion>();
private int limits = -1;
private Query(Field... fields) {
this.fields.addAll(asList(fields));
}
public static Query select(Field... fields) {
return new Query(fields);
}
public Query from(SqlTable fromTable) {
this.table = fromTable;
return this;
}
public Query join(Join... join) {
joins.addAll(asList(join));
return this;
}
public Query where(Criterion criterion) {
criterions.add(criterion);
return this;
}
public Query groupBy(Field... groupBy) {
groupBies.addAll(asList(groupBy));
return this;
}
public Query orderBy(Order... order) {
orders.addAll(asList(order));
return this;
}
public Query limit(int limit) {
limits = limit;
return this;
}
public Query appendSelectFields(Property<?>... selectFields) {
this.fields.addAll(asList(selectFields));
return this;
}
@Override
public boolean equals(Object o) {
return this == o || !(o == null || getClass() != o.getClass()) && this.toString().equals(o.toString());
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public String toString() {
StringBuilder sql = new StringBuilder();
visitSelectClause(sql);
visitFromClause(sql);
visitJoinClause(sql);
if(queryTemplate == null) {
visitWhereClause(sql);
visitGroupByClause(sql);
visitOrderByClause(sql);
visitLimitClause(sql);
} else {
if(groupBies.size() > 0 || orders.size() > 0 ||
havings.size() > 0)
throw new IllegalStateException("Can't have extras AND query template"); //$NON-NLS-1$
sql.append(queryTemplate);
}
return sql.toString();
}
private void visitOrderByClause(StringBuilder sql) {
if (orders.isEmpty()) {
return;
}
sql.append(ORDER_BY);
for (Order order : orders) {
sql.append(SPACE).append(order).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
@SuppressWarnings("nls")
private void visitGroupByClause(StringBuilder sql) {
if (groupBies.isEmpty()) {
return;
}
sql.append(GROUP_BY);
for (Field groupBy : groupBies) {
sql.append(SPACE).append(groupBy).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
if (havings.isEmpty()) {
return;
}
sql.append("HAVING");
for (Criterion havingCriterion : havings) {
sql.append(SPACE).append(havingCriterion).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
private void visitWhereClause(StringBuilder sql) {
if (criterions.isEmpty()) {
return;
}
sql.append(WHERE);
for (Criterion criterion : criterions) {
sql.append(SPACE).append(criterion).append(SPACE);
}
}
private void visitJoinClause(StringBuilder sql) {
for (Join join : joins) {
sql.append(join).append(SPACE);
}
}
private void visitFromClause(StringBuilder sql) {
if (table == null) {
return;
}
sql.append(FROM).append(SPACE).append(table).append(SPACE);
}
private void visitSelectClause(StringBuilder sql) {
sql.append(SELECT).append(SPACE);
if (fields.isEmpty()) {
sql.append(ALL).append(SPACE);
return;
}
for (Field field : fields) {
sql.append(field.toStringInSelect()).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
private void visitLimitClause(StringBuilder sql) {
if(limits > -1)
sql.append(LIMIT).append(SPACE).append(limits).append(SPACE);
}
public SqlTable as(String alias) {
return table(LEFT_PARENTHESIS + this.toString() + RIGHT_PARENTHESIS).as(alias);
}
public Query having(Criterion criterion) {
this.havings.add(criterion);
return this;
}
/**
* Gets a list of fields returned by this query
* @return
*/
public Property<?>[] getFields() {
return fields.toArray(new Property<?>[fields.size()]);
}
/**
* Add the SQL query template (comes after the "from")
* @param sqlQuery
* @return
*/
public Query withQueryTemplate(String template) {
queryTemplate = template;
return this;
}
}

@ -1,117 +1,117 @@
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
import static com.todoroo.andlib.sql.SqlConstants.GROUP_BY;
import static com.todoroo.andlib.sql.SqlConstants.LIMIT;
import static com.todoroo.andlib.sql.SqlConstants.ORDER_BY;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
import static com.todoroo.andlib.sql.SqlConstants.WHERE;
import static java.util.Arrays.asList;
import java.util.ArrayList;
/**
* Query Template returns a bunch of criteria that allows a query to be
* constructed
*
* @author Tim Su <tim@todoroo.com>
*
*/
public final class QueryTemplate {
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
private final ArrayList<Join> joins = new ArrayList<Join>();
private final ArrayList<Field> groupBies = new ArrayList<Field>();
private final ArrayList<Order> orders = new ArrayList<Order>();
private final ArrayList<Criterion> havings = new ArrayList<Criterion>();
private Integer limit = null;
public QueryTemplate join(Join... join) {
joins.addAll(asList(join));
return this;
}
public QueryTemplate where(Criterion criterion) {
criterions.add(criterion);
return this;
}
public QueryTemplate groupBy(Field... groupBy) {
groupBies.addAll(asList(groupBy));
return this;
}
public QueryTemplate orderBy(Order... order) {
orders.addAll(asList(order));
return this;
}
@Override
public String toString() {
StringBuilder sql = new StringBuilder();
visitJoinClause(sql);
visitWhereClause(sql);
visitGroupByClause(sql);
visitOrderByClause(sql);
if(limit != null)
sql.append(LIMIT).append(SPACE).append(limit);
return sql.toString();
}
private void visitOrderByClause(StringBuilder sql) {
if (orders.isEmpty()) {
return;
}
sql.append(ORDER_BY);
for (Order order : orders) {
sql.append(SPACE).append(order).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
@SuppressWarnings("nls")
private void visitGroupByClause(StringBuilder sql) {
if (groupBies.isEmpty()) {
return;
}
sql.append(GROUP_BY);
for (Field groupBy : groupBies) {
sql.append(SPACE).append(groupBy).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
if (havings.isEmpty()) {
return;
}
sql.append("HAVING");
for (Criterion havingCriterion : havings) {
sql.append(SPACE).append(havingCriterion).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
private void visitWhereClause(StringBuilder sql) {
if (criterions.isEmpty()) {
return;
}
sql.append(WHERE);
for (Criterion criterion : criterions) {
sql.append(SPACE).append(criterion).append(SPACE);
}
}
private void visitJoinClause(StringBuilder sql) {
for (Join join : joins) {
sql.append(join).append(SPACE);
}
}
public QueryTemplate having(Criterion criterion) {
this.havings.add(criterion);
return this;
}
public QueryTemplate limit(int limitValue) {
this.limit = limitValue;
return this;
}
}
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
import static com.todoroo.andlib.sql.SqlConstants.GROUP_BY;
import static com.todoroo.andlib.sql.SqlConstants.LIMIT;
import static com.todoroo.andlib.sql.SqlConstants.ORDER_BY;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
import static com.todoroo.andlib.sql.SqlConstants.WHERE;
import static java.util.Arrays.asList;
import java.util.ArrayList;
/**
* Query Template returns a bunch of criteria that allows a query to be
* constructed
*
* @author Tim Su <tim@todoroo.com>
*
*/
public final class QueryTemplate {
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
private final ArrayList<Join> joins = new ArrayList<Join>();
private final ArrayList<Field> groupBies = new ArrayList<Field>();
private final ArrayList<Order> orders = new ArrayList<Order>();
private final ArrayList<Criterion> havings = new ArrayList<Criterion>();
private Integer limit = null;
public QueryTemplate join(Join... join) {
joins.addAll(asList(join));
return this;
}
public QueryTemplate where(Criterion criterion) {
criterions.add(criterion);
return this;
}
public QueryTemplate groupBy(Field... groupBy) {
groupBies.addAll(asList(groupBy));
return this;
}
public QueryTemplate orderBy(Order... order) {
orders.addAll(asList(order));
return this;
}
@Override
public String toString() {
StringBuilder sql = new StringBuilder();
visitJoinClause(sql);
visitWhereClause(sql);
visitGroupByClause(sql);
visitOrderByClause(sql);
if(limit != null)
sql.append(LIMIT).append(SPACE).append(limit);
return sql.toString();
}
private void visitOrderByClause(StringBuilder sql) {
if (orders.isEmpty()) {
return;
}
sql.append(ORDER_BY);
for (Order order : orders) {
sql.append(SPACE).append(order).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
@SuppressWarnings("nls")
private void visitGroupByClause(StringBuilder sql) {
if (groupBies.isEmpty()) {
return;
}
sql.append(GROUP_BY);
for (Field groupBy : groupBies) {
sql.append(SPACE).append(groupBy).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
if (havings.isEmpty()) {
return;
}
sql.append("HAVING");
for (Criterion havingCriterion : havings) {
sql.append(SPACE).append(havingCriterion).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
private void visitWhereClause(StringBuilder sql) {
if (criterions.isEmpty()) {
return;
}
sql.append(WHERE);
for (Criterion criterion : criterions) {
sql.append(SPACE).append(criterion).append(SPACE);
}
}
private void visitJoinClause(StringBuilder sql) {
for (Join join : joins) {
sql.append(join).append(SPACE);
}
}
public QueryTemplate having(Criterion criterion) {
this.havings.add(criterion);
return this;
}
public QueryTemplate limit(int limitValue) {
this.limit = limitValue;
return this;
}
}

@ -1,25 +1,25 @@
package com.todoroo.andlib.sql;
@SuppressWarnings("nls")
public final class SqlConstants {
static final String SELECT = "SELECT";
static final String SPACE = " ";
static final String AS = "AS";
static final String COMMA = ",";
static final String FROM = "FROM";
static final String ON = "ON";
static final String JOIN = "JOIN";
static final String ALL = "*";
static final String LEFT_PARENTHESIS = "(";
static final String RIGHT_PARENTHESIS = ")";
static final String AND = "AND";
static final String BETWEEN = "BETWEEN";
static final String LIKE = "LIKE";
static final String OR = "OR";
static final String ORDER_BY = "ORDER BY";
static final String GROUP_BY = "GROUP BY";
static final String WHERE = "WHERE";
public static final String EXISTS = "EXISTS";
public static final String NOT = "NOT";
public static final String LIMIT = "LIMIT";
}
package com.todoroo.andlib.sql;
@SuppressWarnings("nls")
public final class SqlConstants {
static final String SELECT = "SELECT";
static final String SPACE = " ";
static final String AS = "AS";
static final String COMMA = ",";
static final String FROM = "FROM";
static final String ON = "ON";
static final String JOIN = "JOIN";
static final String ALL = "*";
static final String LEFT_PARENTHESIS = "(";
static final String RIGHT_PARENTHESIS = ")";
static final String AND = "AND";
static final String BETWEEN = "BETWEEN";
static final String LIKE = "LIKE";
static final String OR = "OR";
static final String ORDER_BY = "ORDER BY";
static final String GROUP_BY = "GROUP BY";
static final String WHERE = "WHERE";
public static final String EXISTS = "EXISTS";
public static final String NOT = "NOT";
public static final String LIMIT = "LIMIT";
}

@ -1,20 +1,20 @@
package com.todoroo.andlib.sql;
public class SqlTable extends DBObject<SqlTable> {
protected SqlTable(String expression) {
super(expression);
}
public static SqlTable table(String table) {
return new SqlTable(table);
}
@SuppressWarnings("nls")
protected String fieldExpression(String fieldName) {
if (hasAlias()) {
return alias + "." + fieldName;
}
return expression+"."+fieldName;
}
}
package com.todoroo.andlib.sql;
public class SqlTable extends DBObject<SqlTable> {
protected SqlTable(String expression) {
super(expression);
}
public static SqlTable table(String table) {
return new SqlTable(table);
}
@SuppressWarnings("nls")
protected String fieldExpression(String fieldName) {
if (hasAlias()) {
return alias + "." + fieldName;
}
return expression+"."+fieldName;
}
}

@ -1,107 +1,107 @@
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public class UnaryCriterion extends Criterion {
protected final Field expression;
protected final Object value;
UnaryCriterion(Field expression, Operator operator, Object value) {
super(operator);
this.expression = expression;
this.value = value;
}
@Override
protected void populate(StringBuilder sb) {
beforePopulateOperator(sb);
populateOperator(sb);
afterPopulateOperator(sb);
}
public static Criterion eq(Field expression, Object value) {
return new UnaryCriterion(expression, Operator.eq, value);
}
protected void beforePopulateOperator(StringBuilder sb) {
sb.append(expression);
}
protected void populateOperator(StringBuilder sb) {
sb.append(operator);
}
@SuppressWarnings("nls")
protected void afterPopulateOperator(StringBuilder sb) {
if(value == null)
return;
else if(value instanceof String)
sb.append("'").append(sanitize((String) value)).append("'");
else
sb.append(value);
}
/**
* Sanitize the given input for SQL
* @param input
* @return
*/
@SuppressWarnings("nls")
public static String sanitize(String input) {
return input.replace("'", "''");
}
public static Criterion neq(Field field, Object value) {
return new UnaryCriterion(field, Operator.neq, value);
}
public static Criterion gt(Field field, Object value) {
return new UnaryCriterion(field, Operator.gt, value);
}
public static Criterion lt(Field field, Object value) {
return new UnaryCriterion(field, Operator.lt, value);
}
public static Criterion isNull(Field field) {
return new UnaryCriterion(field, Operator.isNull, null) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator);
}
};
}
public static Criterion isNotNull(Field field) {
return new UnaryCriterion(field, Operator.isNotNull, null) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator);
}
};
}
public static Criterion like(Field field, String value) {
return new UnaryCriterion(field, Operator.like, value) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator).append(SPACE);
}
};
}
public static Criterion like(Field field, String value, final String escape) {
return new UnaryCriterion(field, Operator.like, value) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator).append(SPACE);
}
@SuppressWarnings("nls")
@Override
protected void afterPopulateOperator(StringBuilder sb) {
super.afterPopulateOperator(sb);
sb.append(SPACE).append("ESCAPE").append(" '").append(sanitize(escape)).append("'");
}
};
}
}
package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public class UnaryCriterion extends Criterion {
protected final Field expression;
protected final Object value;
UnaryCriterion(Field expression, Operator operator, Object value) {
super(operator);
this.expression = expression;
this.value = value;
}
@Override
protected void populate(StringBuilder sb) {
beforePopulateOperator(sb);
populateOperator(sb);
afterPopulateOperator(sb);
}
public static Criterion eq(Field expression, Object value) {
return new UnaryCriterion(expression, Operator.eq, value);
}
protected void beforePopulateOperator(StringBuilder sb) {
sb.append(expression);
}
protected void populateOperator(StringBuilder sb) {
sb.append(operator);
}
@SuppressWarnings("nls")
protected void afterPopulateOperator(StringBuilder sb) {
if(value == null)
return;
else if(value instanceof String)
sb.append("'").append(sanitize((String) value)).append("'");
else
sb.append(value);
}
/**
* Sanitize the given input for SQL
* @param input
* @return
*/
@SuppressWarnings("nls")
public static String sanitize(String input) {
return input.replace("'", "''");
}
public static Criterion neq(Field field, Object value) {
return new UnaryCriterion(field, Operator.neq, value);
}
public static Criterion gt(Field field, Object value) {
return new UnaryCriterion(field, Operator.gt, value);
}
public static Criterion lt(Field field, Object value) {
return new UnaryCriterion(field, Operator.lt, value);
}
public static Criterion isNull(Field field) {
return new UnaryCriterion(field, Operator.isNull, null) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator);
}
};
}
public static Criterion isNotNull(Field field) {
return new UnaryCriterion(field, Operator.isNotNull, null) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator);
}
};
}
public static Criterion like(Field field, String value) {
return new UnaryCriterion(field, Operator.like, value) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator).append(SPACE);
}
};
}
public static Criterion like(Field field, String value, final String escape) {
return new UnaryCriterion(field, Operator.like, value) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator).append(SPACE);
}
@SuppressWarnings("nls")
@Override
protected void afterPopulateOperator(StringBuilder sb) {
super.afterPopulateOperator(sb);
sb.append(SPACE).append("ESCAPE").append(" '").append(sanitize(escape)).append("'");
}
};
}
}

@ -1,146 +1,146 @@
package com.todoroo.astrid.gcal;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.utility.Preferences;
@SuppressWarnings("nls")
public class Calendars {
public static final String CALENDAR_CONTENT_CALENDARS = "calendars";
public static final String CALENDAR_CONTENT_EVENTS = "events";
private static final String ID_COLUMN_NAME = "_id";
private static final String DISPLAY_COLUMN_NAME = "displayName";
private static final String ACCES_LEVEL_COLUMN_NAME = "access_level";
private static final String[] CALENDARS_PROJECTION = new String[] {
ID_COLUMN_NAME, // Calendars._ID,
DISPLAY_COLUMN_NAME // Calendars.DISPLAY_NAME
};
// Only show calendars that the user can modify. Access level 500
// corresponds to Calendars.CONTRIBUTOR_ACCESS
private static final String CALENDARS_WHERE = ACCES_LEVEL_COLUMN_NAME + ">= 500";
private static final String CALENDARS_SORT = "displayName ASC";
// --- api access
/** Return content uri for calendars
* @param table provider table, something like calendars, events
*/
public static Uri getCalendarContentUri(String table) {
if(AndroidUtilities.getSdkVersion() >= 8)
return Uri.parse("content://com.android.calendar/" + table);
else
return Uri.parse("content://calendar/" + table);
}
/** Return calendar package name */
public static String getCalendarPackage() {
if(AndroidUtilities.getSdkVersion() >= 8)
return "com.google.android.calendar";
else
return "com.android.calendar";
}
// --- helper data structure
/**
* Helper class for working with the results of getCalendars
*/
public static class CalendarResult {
/** calendar names */
public String[] calendars;
/** calendar ids. null entry -> use default */
public String[] calendarIds;
/** default selection index */
public int defaultIndex = -1;
}
/**
* Appends all user-modifiable calendars to listPreference. Always includes
* entry called "Astrid default" with calendar id of
* prefs_defaultCalendar_default.
*
* @param context
* context
* @param listPreference
* preference to init
*/
public static CalendarResult getCalendars() {
Context context = ContextManager.getContext();
ContentResolver cr = context.getContentResolver();
Resources r = context.getResources();
Cursor c = cr.query(getCalendarContentUri(CALENDAR_CONTENT_CALENDARS), CALENDARS_PROJECTION,
CALENDARS_WHERE, null, CALENDARS_SORT);
try {
// Fetch the current setting. Invalid calendar id will
// be changed to default value.
String defaultSetting = Preferences.getStringValue(R.string.gcal_p_default);
CalendarResult result = new CalendarResult();
if (c == null || c.getCount() == 0) {
// Something went wrong when querying calendars. Only offer them
// the system default choice
result.calendars = new String[] {
r.getString(R.string.gcal_GCP_default) };
result.calendarIds = new String[] { null };
result.defaultIndex = 0;
return result;
}
int calendarCount = c.getCount();
result.calendars = new String[calendarCount];
result.calendarIds = new String[calendarCount];
// Iterate calendars one by one, and fill up the list preference
int row = 0;
int idColumn = c.getColumnIndex(ID_COLUMN_NAME);
int nameColumn = c.getColumnIndex(DISPLAY_COLUMN_NAME);
while (c.moveToNext()) {
String id = c.getString(idColumn);
String name = c.getString(nameColumn);
result.calendars[row] = name;
result.calendarIds[row] = id;
// We found currently selected calendar
if (defaultSetting != null && defaultSetting.equals(id)) {
result.defaultIndex = row;
}
row++;
}
if (result.defaultIndex == -1 || result.defaultIndex >= calendarCount) {
result.defaultIndex = 0;
}
return result;
} finally {
if(c != null)
c.close();
}
}
/**
* sets the default calendar for future use
* @param defaultCalendar default calendar id
*/
public static void setDefaultCalendar(String defaultCalendar) {
Preferences.setString(R.string.gcal_p_default, defaultCalendar);
}
package com.todoroo.astrid.gcal;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.utility.Preferences;
@SuppressWarnings("nls")
public class Calendars {
public static final String CALENDAR_CONTENT_CALENDARS = "calendars";
public static final String CALENDAR_CONTENT_EVENTS = "events";
private static final String ID_COLUMN_NAME = "_id";
private static final String DISPLAY_COLUMN_NAME = "displayName";
private static final String ACCES_LEVEL_COLUMN_NAME = "access_level";
private static final String[] CALENDARS_PROJECTION = new String[] {
ID_COLUMN_NAME, // Calendars._ID,
DISPLAY_COLUMN_NAME // Calendars.DISPLAY_NAME
};
// Only show calendars that the user can modify. Access level 500
// corresponds to Calendars.CONTRIBUTOR_ACCESS
private static final String CALENDARS_WHERE = ACCES_LEVEL_COLUMN_NAME + ">= 500";
private static final String CALENDARS_SORT = "displayName ASC";
// --- api access
/** Return content uri for calendars
* @param table provider table, something like calendars, events
*/
public static Uri getCalendarContentUri(String table) {
if(AndroidUtilities.getSdkVersion() >= 8)
return Uri.parse("content://com.android.calendar/" + table);
else
return Uri.parse("content://calendar/" + table);
}
/** Return calendar package name */
public static String getCalendarPackage() {
if(AndroidUtilities.getSdkVersion() >= 8)
return "com.google.android.calendar";
else
return "com.android.calendar";
}
// --- helper data structure
/**
* Helper class for working with the results of getCalendars
*/
public static class CalendarResult {
/** calendar names */
public String[] calendars;
/** calendar ids. null entry -> use default */
public String[] calendarIds;
/** default selection index */
public int defaultIndex = -1;
}
/**
* Appends all user-modifiable calendars to listPreference. Always includes
* entry called "Astrid default" with calendar id of
* prefs_defaultCalendar_default.
*
* @param context
* context
* @param listPreference
* preference to init
*/
public static CalendarResult getCalendars() {
Context context = ContextManager.getContext();
ContentResolver cr = context.getContentResolver();
Resources r = context.getResources();
Cursor c = cr.query(getCalendarContentUri(CALENDAR_CONTENT_CALENDARS), CALENDARS_PROJECTION,
CALENDARS_WHERE, null, CALENDARS_SORT);
try {
// Fetch the current setting. Invalid calendar id will
// be changed to default value.
String defaultSetting = Preferences.getStringValue(R.string.gcal_p_default);
CalendarResult result = new CalendarResult();
if (c == null || c.getCount() == 0) {
// Something went wrong when querying calendars. Only offer them
// the system default choice
result.calendars = new String[] {
r.getString(R.string.gcal_GCP_default) };
result.calendarIds = new String[] { null };
result.defaultIndex = 0;
return result;
}
int calendarCount = c.getCount();
result.calendars = new String[calendarCount];
result.calendarIds = new String[calendarCount];
// Iterate calendars one by one, and fill up the list preference
int row = 0;
int idColumn = c.getColumnIndex(ID_COLUMN_NAME);
int nameColumn = c.getColumnIndex(DISPLAY_COLUMN_NAME);
while (c.moveToNext()) {
String id = c.getString(idColumn);
String name = c.getString(nameColumn);
result.calendars[row] = name;
result.calendarIds[row] = id;
// We found currently selected calendar
if (defaultSetting != null && defaultSetting.equals(id)) {
result.defaultIndex = row;
}
row++;
}
if (result.defaultIndex == -1 || result.defaultIndex >= calendarCount) {
result.defaultIndex = 0;
}
return result;
} finally {
if(c != null)
c.close();
}
}
/**
* sets the default calendar for future use
* @param defaultCalendar default calendar id
*/
public static void setDefaultCalendar(String defaultCalendar) {
Preferences.setString(R.string.gcal_p_default, defaultCalendar);
}
}

@ -70,7 +70,8 @@ public class LocaleReceiver extends BroadcastReceiver {
DependencyInjectionService.getInstance().inject(this);
Filter filter = new Filter(title, title, null, null);
filter.sqlQuery = sql;
TodorooCursor<Task> cursor = PluginServices.getTaskService().fetchFiltered(filter, null, Task.ID);
TodorooCursor<Task> cursor = PluginServices.getTaskService().fetchFiltered(
sql, null, Task.ID);
try {
if(cursor.getCount() == 0)
return;

@ -62,7 +62,9 @@ public class ProducteevDetailExposer extends BroadcastReceiver implements Detail
if(!extended) {
long dashboardId = metadata.getValue(ProducteevTask.DASHBOARD_ID);
long responsibleId = metadata.getValue(ProducteevTask.RESPONSIBLE_ID);
long responsibleId = -1;
if(metadata.containsNonNullValue(ProducteevTask.RESPONSIBLE_ID))
responsibleId = metadata.getValue(ProducteevTask.RESPONSIBLE_ID);
// display dashboard if not "no sync" or "default"
StoreObject ownerDashboard = null;

@ -1,149 +1,149 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.todoroo.astrid.reminders;
import java.util.Date;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;
import com.timsu.astrid.R;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.utility.Preferences;
/**
* This activity is launched when a user opens up a notification from the
* tray. It launches the appropriate activity based on the passed in parameters.
*
* @author timsu
*
*/
public class NotificationActivity extends TaskListActivity implements OnTimeSetListener {
// --- constants
/** task id from notification */
public static final String TOKEN_ID = "id"; //$NON-NLS-1$
// --- implementation
private long taskId;
@Override
public void onCreate(Bundle savedInstanceState) {
populateFilter(getIntent());
super.onCreate(savedInstanceState);
displayNotificationPopup();
}
@Override
protected void onNewIntent(Intent intent) {
populateFilter(intent);
super.onNewIntent(intent);
}
private void populateFilter(Intent intent) {
taskId = intent.getLongExtra(TOKEN_ID, -1);
if(taskId == -1)
return;
Filter itemFilter = new Filter(getString(R.string.rmd_NoA_filter),
getString(R.string.rmd_NoA_filter),
new QueryTemplate().where(TaskCriteria.byId(taskId)),
null);
intent.putExtra(TaskListActivity.TOKEN_FILTER, itemFilter);
}
/**
* Set up the UI for this activity
*/
private void displayNotificationPopup() {
// hide quick add
findViewById(R.id.taskListFooter).setVisibility(View.GONE);
// instantiate reminder window
ViewGroup parent = (ViewGroup) findViewById(R.id.taskListParent);
getLayoutInflater().inflate(R.layout.notification_control, parent, true);
String reminder = Notifications.getRandomReminder(getResources().getStringArray(R.array.reminder_responses));
if(Preferences.getBoolean(R.string.p_rmd_nagging, true))
((TextView)findViewById(R.id.reminderLabel)).setText(reminder);
else {
findViewById(R.id.reminderLabel).setVisibility(View.GONE);
findViewById(R.id.astridIcon).setVisibility(View.GONE);
}
// set up listeners
((Button)findViewById(R.id.goAway)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
finish();
}
});
((Button)findViewById(R.id.snooze)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
snooze();
}
});
}
/**
* Snooze and re-trigger this alarm
*/
private void snooze() {
Date now = new Date();
now.setHours(now.getHours() + 1);
int hour = now.getHours();
int minute = now.getMinutes();
TimePickerDialog timePicker = new TimePickerDialog(this, this,
hour, minute, DateUtilities.is24HourFormat(this));
timePicker.show();
}
/** snooze timer set */
@Override
public void onTimeSet(TimePicker picker, int hours, int minutes) {
Date alarmTime = new Date();
alarmTime.setHours(hours);
alarmTime.setMinutes(minutes);
if(alarmTime.getTime() < DateUtilities.now())
alarmTime.setDate(alarmTime.getDate() + 1);
ReminderService.getInstance().scheduleSnoozeAlarm(taskId, alarmTime.getTime());
finish();
}
}
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.todoroo.astrid.reminders;
import java.util.Date;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;
import com.timsu.astrid.R;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.utility.Preferences;
/**
* This activity is launched when a user opens up a notification from the
* tray. It launches the appropriate activity based on the passed in parameters.
*
* @author timsu
*
*/
public class NotificationActivity extends TaskListActivity implements OnTimeSetListener {
// --- constants
/** task id from notification */
public static final String TOKEN_ID = "id"; //$NON-NLS-1$
// --- implementation
private long taskId;
@Override
public void onCreate(Bundle savedInstanceState) {
populateFilter(getIntent());
super.onCreate(savedInstanceState);
displayNotificationPopup();
}
@Override
protected void onNewIntent(Intent intent) {
populateFilter(intent);
super.onNewIntent(intent);
}
private void populateFilter(Intent intent) {
taskId = intent.getLongExtra(TOKEN_ID, -1);
if(taskId == -1)
return;
Filter itemFilter = new Filter(getString(R.string.rmd_NoA_filter),
getString(R.string.rmd_NoA_filter),
new QueryTemplate().where(TaskCriteria.byId(taskId)),
null);
intent.putExtra(TaskListActivity.TOKEN_FILTER, itemFilter);
}
/**
* Set up the UI for this activity
*/
private void displayNotificationPopup() {
// hide quick add
findViewById(R.id.taskListFooter).setVisibility(View.GONE);
// instantiate reminder window
ViewGroup parent = (ViewGroup) findViewById(R.id.taskListParent);
getLayoutInflater().inflate(R.layout.notification_control, parent, true);
String reminder = Notifications.getRandomReminder(getResources().getStringArray(R.array.reminder_responses));
if(Preferences.getBoolean(R.string.p_rmd_nagging, true))
((TextView)findViewById(R.id.reminderLabel)).setText(reminder);
else {
findViewById(R.id.reminderLabel).setVisibility(View.GONE);
findViewById(R.id.astridIcon).setVisibility(View.GONE);
}
// set up listeners
((Button)findViewById(R.id.goAway)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
finish();
}
});
((Button)findViewById(R.id.snooze)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
snooze();
}
});
}
/**
* Snooze and re-trigger this alarm
*/
private void snooze() {
Date now = new Date();
now.setHours(now.getHours() + 1);
int hour = now.getHours();
int minute = now.getMinutes();
TimePickerDialog timePicker = new TimePickerDialog(this, this,
hour, minute, DateUtilities.is24HourFormat(this));
timePicker.show();
}
/** snooze timer set */
@Override
public void onTimeSet(TimePicker picker, int hours, int minutes) {
Date alarmTime = new Date();
alarmTime.setHours(hours);
alarmTime.setMinutes(minutes);
if(alarmTime.getTime() < DateUtilities.now())
alarmTime.setDate(alarmTime.getDate() + 1);
ReminderService.getInstance().scheduleSnoozeAlarm(taskId, alarmTime.getTime());
finish();
}
}

@ -1,128 +1,128 @@
package com.todoroo.astrid.rmilk;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.rmilk.sync.RTMSyncProvider;
import com.todoroo.astrid.utility.Preferences;
/**
* SynchronizationService is the service that performs Astrid's background
* synchronization with online task managers. Starting this service
* schedules a repeating alarm which handles the synchronization
*
* @author Tim Su
*
*/
public class MilkBackgroundService extends Service {
/** Minimum time before an auto-sync */
private static final long AUTO_SYNC_MIN_OFFSET = 5*60*1000L;
/** alarm identifier */
private static final String SYNC_ACTION = "sync"; //$NON-NLS-1$
// --- BroadcastReceiver abstract methods
/** Receive the alarm - start the synchronize service! */
@Override
public void onStart(Intent intent, int startId) {
if(SYNC_ACTION.equals(intent.getAction()))
startSynchronization(this);
}
/** Start the actual synchronization */
private void startSynchronization(Context context) {
if(context == null || context.getResources() == null)
return;
ContextManager.setContext(context);
if(MilkUtilities.isOngoing())
return;
new RTMSyncProvider().synchronize(context);
}
// --- alarm management
/**
* Schedules repeating alarm for auto-synchronization
*/
public static void scheduleService() {
int syncFrequencySeconds = Preferences.getIntegerFromString(
R.string.rmilk_MPr_interval_key, -1);
Context context = ContextManager.getContext();
if(syncFrequencySeconds <= 0) {
unscheduleService(context);
return;
}
// figure out synchronization frequency
long interval = 1000L * syncFrequencySeconds;
long offset = computeNextSyncOffset(interval);
// give a little padding
offset = Math.max(offset, AUTO_SYNC_MIN_OFFSET);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
Log.i("Astrid", "Autosync set for " + offset / 1000 //$NON-NLS-1$ //$NON-NLS-2$
+ " seconds repeating every " + syncFrequencySeconds); //$NON-NLS-1$
// cancel all existing
am.cancel(pendingIntent);
// schedule new
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + offset,
interval, pendingIntent);
}
/**
* Removes repeating alarm for auto-synchronization
*/
private static void unscheduleService(Context context) {
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pendingIntent);
}
/** Create the alarm intent */
private static Intent createAlarmIntent(Context context) {
Intent intent = new Intent(context, MilkBackgroundService.class);
intent.setAction(SYNC_ACTION);
return intent;
}
// --- utility methods
private static long computeNextSyncOffset(long interval) {
// figure out last synchronize time
long lastSyncDate = MilkUtilities.getLastSyncDate();
// if user never synchronized, give them a full offset period before bg sync
if(lastSyncDate != 0)
return Math.max(0, lastSyncDate + interval - DateUtilities.now());
else
return interval;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
package com.todoroo.astrid.rmilk;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.rmilk.sync.RTMSyncProvider;
import com.todoroo.astrid.utility.Preferences;
/**
* SynchronizationService is the service that performs Astrid's background
* synchronization with online task managers. Starting this service
* schedules a repeating alarm which handles the synchronization
*
* @author Tim Su
*
*/
public class MilkBackgroundService extends Service {
/** Minimum time before an auto-sync */
private static final long AUTO_SYNC_MIN_OFFSET = 5*60*1000L;
/** alarm identifier */
private static final String SYNC_ACTION = "sync"; //$NON-NLS-1$
// --- BroadcastReceiver abstract methods
/** Receive the alarm - start the synchronize service! */
@Override
public void onStart(Intent intent, int startId) {
if(SYNC_ACTION.equals(intent.getAction()))
startSynchronization(this);
}
/** Start the actual synchronization */
private void startSynchronization(Context context) {
if(context == null || context.getResources() == null)
return;
ContextManager.setContext(context);
if(MilkUtilities.isOngoing())
return;
new RTMSyncProvider().synchronize(context);
}
// --- alarm management
/**
* Schedules repeating alarm for auto-synchronization
*/
public static void scheduleService() {
int syncFrequencySeconds = Preferences.getIntegerFromString(
R.string.rmilk_MPr_interval_key, -1);
Context context = ContextManager.getContext();
if(syncFrequencySeconds <= 0) {
unscheduleService(context);
return;
}
// figure out synchronization frequency
long interval = 1000L * syncFrequencySeconds;
long offset = computeNextSyncOffset(interval);
// give a little padding
offset = Math.max(offset, AUTO_SYNC_MIN_OFFSET);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
Log.i("Astrid", "Autosync set for " + offset / 1000 //$NON-NLS-1$ //$NON-NLS-2$
+ " seconds repeating every " + syncFrequencySeconds); //$NON-NLS-1$
// cancel all existing
am.cancel(pendingIntent);
// schedule new
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + offset,
interval, pendingIntent);
}
/**
* Removes repeating alarm for auto-synchronization
*/
private static void unscheduleService(Context context) {
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pendingIntent);
}
/** Create the alarm intent */
private static Intent createAlarmIntent(Context context) {
Intent intent = new Intent(context, MilkBackgroundService.class);
intent.setAction(SYNC_ACTION);
return intent;
}
// --- utility methods
private static long computeNextSyncOffset(long interval) {
// figure out last synchronize time
long lastSyncDate = MilkUtilities.getLastSyncDate();
// if user never synchronized, give them a full offset period before bg sync
if(lastSyncDate != 0)
return Math.max(0, lastSyncDate + interval - DateUtilities.now());
else
return interval;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

@ -1,106 +1,106 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API 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 Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.todoroo.astrid.rmilk.api.data;
import java.util.Date;
import org.w3c.dom.Element;
import org.w3c.dom.EntityReference;
import org.w3c.dom.Text;
import android.util.Log;
/**
* Represents a single task note.
*
* @author Edouard Mercier
* @since 2008.04.22
*/
@SuppressWarnings("nls")
public class RtmTaskNote
extends RtmData
{
private final String id;
private final Date created;
private final Date modified;
private final String title;
private String text;
public RtmTaskNote(Element element)
{
id = element.getAttribute("id");
created = parseDate(element.getAttribute("created"));
modified = parseDate(element.getAttribute("modified"));
title = element.getAttribute("title");
// The note text itself might be split across multiple children of the
// note element, so get all of the children.
for (int i=0; i < element.getChildNodes().getLength(); i++) {
Object innerNote = element.getChildNodes().item(i);
if(innerNote instanceof EntityReference) // this node is empty
continue;
if(!(innerNote instanceof Text)) {
Log.w("rtm-note", "Expected text type, got " + innerNote.getClass());
continue;
}
Text innerText = (Text) innerNote;
if (text == null)
text = innerText.getData();
else
text = text.concat(innerText.getData());
}
}
public String getId()
{
return id;
}
public Date getCreated()
{
return created;
}
public Date getModified()
{
return modified;
}
public String getTitle()
{
return title;
}
public String getText()
{
return text;
}
}
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API 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 Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.todoroo.astrid.rmilk.api.data;
import java.util.Date;
import org.w3c.dom.Element;
import org.w3c.dom.EntityReference;
import org.w3c.dom.Text;
import android.util.Log;
/**
* Represents a single task note.
*
* @author Edouard Mercier
* @since 2008.04.22
*/
@SuppressWarnings("nls")
public class RtmTaskNote
extends RtmData
{
private final String id;
private final Date created;
private final Date modified;
private final String title;
private String text;
public RtmTaskNote(Element element)
{
id = element.getAttribute("id");
created = parseDate(element.getAttribute("created"));
modified = parseDate(element.getAttribute("modified"));
title = element.getAttribute("title");
// The note text itself might be split across multiple children of the
// note element, so get all of the children.
for (int i=0; i < element.getChildNodes().getLength(); i++) {
Object innerNote = element.getChildNodes().item(i);
if(innerNote instanceof EntityReference) // this node is empty
continue;
if(!(innerNote instanceof Text)) {
Log.w("rtm-note", "Expected text type, got " + innerNote.getClass());
continue;
}
Text innerText = (Text) innerNote;
if (text == null)
text = innerText.getData();
else
text = text.concat(innerText.getData());
}
}
public String getId()
{
return id;
}
public Date getCreated()
{
return created;
}
public Date getModified()
{
return modified;
}
public String getTitle()
{
return title;
}
public String getText()
{
return text;
}
}

@ -1,50 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/background_gradient">
<!-- =================================================== tab: installed == -->
<FrameLayout android:id="@+id/tab_installed"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/empty_installed"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:text="@string/TEA_no_addons"
style="@style/TextAppearance.TLA_NoItems" />
<ListView android:id="@+id/installed"
android:paddingRight="8dip"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
<!-- =================================================== tab: available == -->
<FrameLayout android:id="@+id/tab_available"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/empty_available"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:text="@string/TEA_no_addons"
style="@style/TextAppearance.TLA_NoItems" />
<ListView android:id="@+id/available"
android:paddingRight="8dip"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/background_gradient">
<!-- =================================================== tab: installed == -->
<FrameLayout android:id="@+id/tab_installed"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/empty_installed"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:text="@string/TEA_no_addons"
style="@style/TextAppearance.TLA_NoItems" />
<ListView android:id="@+id/installed"
android:paddingRight="8dip"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
<!-- =================================================== tab: available == -->
<FrameLayout android:id="@+id/tab_available"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/empty_available"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:text="@string/TEA_no_addons"
style="@style/TextAppearance.TLA_NoItems" />
<ListView android:id="@+id/available"
android:paddingRight="8dip"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
</FrameLayout>

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- See the file "LICENSE" for the full license governing this code. -->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dip"
android:paddingRight="10dip">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- hidden task status -->
<CheckBox android:id="@+id/hidden"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SSD_hidden" />
<CheckBox android:id="@+id/completed"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SSD_completed" />
<CheckBox android:id="@+id/deleted"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SSD_deleted" />
<!-- Sorting -->
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dip"
android:gravity="center"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="@string/SSD_sort_header"
android:background="@drawable/edit_titlebar"/>
<RadioGroup
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton android:id="@+id/sort_smart"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SSD_sort_auto" />
<RadioButton android:id="@+id/sort_due"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SSD_sort_due" />
<RadioButton android:id="@+id/sort_importance"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SSD_sort_importance" />
<RadioButton android:id="@+id/sort_alpha"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SSD_sort_alpha" />
<RadioButton android:id="@+id/sort_modified"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SSD_sort_modified" />
</RadioGroup>
<CheckBox android:id="@+id/reverse"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SSD_sort_reverse" />
</LinearLayout>
</ScrollView>

@ -1,304 +1,304 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/background_gradient">
<!-- ======================================================= tab: basic == -->
<ScrollView
android:id="@+id/tab_basic"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:id="@+id/event"
android:paddingRight="8dip"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- title -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_title_label"
style="@style/TextAppearance.GEN_EditLabel" />
<EditText
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/TEA_title_hint"
android:autoText="true"
android:capitalize="sentences" />
<!-- importance -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_importance_label"
style="@style/TextAppearance.GEN_EditLabel" />
<LinearLayout
android:id="@+id/importance_container"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</LinearLayout>
<!-- urgency -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_urgency_label"
style="@style/TextAppearance.GEN_EditLabel" />
<Spinner
android:id="@+id/urgency"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<!-- tags -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_tags_label"
style="@style/TextAppearance.GEN_EditLabel" />
<LinearLayout
android:id="@+id/tags_container"
android:orientation="vertical"
android:paddingBottom="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<!-- separator -->
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:padding="5dip"
android:background="@android:drawable/divider_horizontal_dark" />
<!-- notes -->
<TextView
android:paddingTop="5dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_note_label"
style="@style/TextAppearance.GEN_EditLabel" />
<EditText
android:id="@+id/notes"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scrollbars="vertical"
android:gravity="top"
android:hint="@string/TEA_notes_hint"
android:autoText="true"
android:capitalize="sentences"
android:singleLine="false" />
<!-- buttons -->
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:padding="5dip"
android:background="@drawable/edit_header"
android:baselineAligned="false">
<ImageButton
android:id="@+id/save_basic"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_save" />
<ImageButton
android:id="@+id/discard_basic"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_stop" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<!-- ======================================================= tab: extra == -->
<ScrollView
android:id="@+id/tab_extra"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:paddingRight="8dip"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- reminders -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_reminder_label"
style="@style/TextAppearance.GEN_EditLabel" />
<CheckBox
android:id="@+id/reminder_due"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TEA_reminder_due" />
<CheckBox
android:id="@+id/reminder_overdue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TEA_reminder_overdue" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<CheckBox
android:id="@+id/reminder_random"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_reminder_random" />
<Spinner
android:id="@+id/reminder_random_interval"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- reminder mode -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_reminder_alarm_label"
style="@style/TextAppearance.GEN_EditLabel" />
<Spinner
android:id="@+id/reminder_alarm"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<!-- separator -->
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:padding="5dip"
android:background="@android:drawable/divider_horizontal_dark" />
<!-- hide until -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_hideUntil_label"
style="@style/TextAppearance.GEN_EditLabel" />
<Spinner
android:id="@+id/hideUntil"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<!-- add-ons -->
<LinearLayout android:id="@+id/tab_extra_addons"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<!-- buttons -->
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:padding="5dip"
android:background="@drawable/edit_header"
android:baselineAligned="false">
<ImageButton
android:id="@+id/save_extra"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_save" />
<ImageButton
android:id="@+id/discard_extra"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_stop" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<!-- ===================================================== tab: add-ons == -->
<LinearLayout
android:id="@+id/tab_addons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100">
<!-- add-ons -->
<LinearLayout android:id="@+id/tab_addons_addons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" />
</ScrollView>
<LinearLayout android:id="@+id/addons_empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100"
android:gravity="center"
android:visibility="gone"
android:orientation="vertical">
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dip"
android:src="@drawable/icon_pp" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TEA_no_addons"
android:padding="10dip"
android:gravity="center"
style="@style/TextAppearance.TLA_NoItems" />
<Button android:id="@+id/addons_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dip"
android:text="@string/TEA_addons_button" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="10dip"
android:padding="5dip"
android:orientation="horizontal"
android:background="@drawable/edit_header"
android:baselineAligned="false">
<ImageButton
android:id="@+id/save_addons"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_save" />
<ImageButton
android:id="@+id/discard_addons"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_stop" />
</LinearLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/background_gradient">
<!-- ======================================================= tab: basic == -->
<ScrollView
android:id="@+id/tab_basic"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:id="@+id/event"
android:paddingRight="8dip"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- title -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_title_label"
style="@style/TextAppearance.GEN_EditLabel" />
<EditText
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/TEA_title_hint"
android:autoText="true"
android:capitalize="sentences" />
<!-- importance -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_importance_label"
style="@style/TextAppearance.GEN_EditLabel" />
<LinearLayout
android:id="@+id/importance_container"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</LinearLayout>
<!-- urgency -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_urgency_label"
style="@style/TextAppearance.GEN_EditLabel" />
<Spinner
android:id="@+id/urgency"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<!-- tags -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_tags_label"
style="@style/TextAppearance.GEN_EditLabel" />
<LinearLayout
android:id="@+id/tags_container"
android:orientation="vertical"
android:paddingBottom="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<!-- separator -->
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:padding="5dip"
android:background="@android:drawable/divider_horizontal_dark" />
<!-- notes -->
<TextView
android:paddingTop="5dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_note_label"
style="@style/TextAppearance.GEN_EditLabel" />
<EditText
android:id="@+id/notes"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scrollbars="vertical"
android:gravity="top"
android:hint="@string/TEA_notes_hint"
android:autoText="true"
android:capitalize="sentences"
android:singleLine="false" />
<!-- buttons -->
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:padding="5dip"
android:background="@drawable/edit_header"
android:baselineAligned="false">
<ImageButton
android:id="@+id/save_basic"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_save" />
<ImageButton
android:id="@+id/discard_basic"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_stop" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<!-- ======================================================= tab: extra == -->
<ScrollView
android:id="@+id/tab_extra"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:paddingRight="8dip"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- reminders -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_reminder_label"
style="@style/TextAppearance.GEN_EditLabel" />
<CheckBox
android:id="@+id/reminder_due"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TEA_reminder_due" />
<CheckBox
android:id="@+id/reminder_overdue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TEA_reminder_overdue" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<CheckBox
android:id="@+id/reminder_random"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_reminder_random" />
<Spinner
android:id="@+id/reminder_random_interval"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- reminder mode -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_reminder_alarm_label"
style="@style/TextAppearance.GEN_EditLabel" />
<Spinner
android:id="@+id/reminder_alarm"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<!-- separator -->
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:padding="5dip"
android:background="@android:drawable/divider_horizontal_dark" />
<!-- hide until -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TEA_hideUntil_label"
style="@style/TextAppearance.GEN_EditLabel" />
<Spinner
android:id="@+id/hideUntil"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<!-- add-ons -->
<LinearLayout android:id="@+id/tab_extra_addons"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<!-- buttons -->
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:padding="5dip"
android:background="@drawable/edit_header"
android:baselineAligned="false">
<ImageButton
android:id="@+id/save_extra"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_save" />
<ImageButton
android:id="@+id/discard_extra"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_stop" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<!-- ===================================================== tab: add-ons == -->
<LinearLayout
android:id="@+id/tab_addons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100">
<!-- add-ons -->
<LinearLayout android:id="@+id/tab_addons_addons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" />
</ScrollView>
<LinearLayout android:id="@+id/addons_empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100"
android:gravity="center"
android:visibility="gone"
android:orientation="vertical">
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dip"
android:src="@drawable/icon_pp" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TEA_no_addons"
android:padding="10dip"
android:gravity="center"
style="@style/TextAppearance.TLA_NoItems" />
<Button android:id="@+id/addons_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dip"
android:text="@string/TEA_addons_button" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="10dip"
android:padding="5dip"
android:orientation="horizontal"
android:background="@drawable/edit_header"
android:baselineAligned="false">
<ImageButton
android:id="@+id/save_addons"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_save" />
<ImageButton
android:id="@+id/discard_addons"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_stop" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

@ -624,25 +624,25 @@ to the plugin creator for fastest service.
<string name="BFE_Extended">More...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Recently Modified</string>
<string name="SSD_sort_modified">Recently Modified</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Tasques Completades</string>
<string name="SSD_completed">Tasques Completades</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Hidden Tasks</string>
<string name="SSD_hidden">Hidden Tasks</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">By Title</string>
<string name="SSD_sort_alpha">By Title</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">By Due Date</string>
<string name="SSD_sort_due">By Due Date</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">By Importance</string>
<string name="SSD_sort_importance">By Importance</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Deleted Tasks</string>
<string name="SSD_deleted">Deleted Tasks</string>

@ -617,25 +617,25 @@ to the plugin creator for fastest service.
<string name="BFE_Extended">Více...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Nedávno upravené</string>
<string name="SSD_sort_modified">Nedávno upravené</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Dokončené úkoly</string>
<string name="SSD_completed">Dokončené úkoly</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Skryté úkoly</string>
<string name="SSD_hidden">Skryté úkoly</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">Podle názvu</string>
<string name="SSD_sort_alpha">Podle názvu</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">Podle data ukončení</string>
<string name="SSD_sort_due">Podle data ukončení</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">Podle důležitosti</string>
<string name="SSD_sort_importance">Podle důležitosti</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Smazané úkoly</string>
<string name="SSD_deleted">Smazané úkoly</string>

@ -617,25 +617,25 @@ to the plugin creator for fastest service.
<string name="BFE_Extended">Mehr...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Kürzlich bearbeitet</string>
<string name="SSD_sort_modified">Kürzlich bearbeitet</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Erledigte Aufgaben</string>
<string name="SSD_completed">Erledigte Aufgaben</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Versteckte Aufgaben</string>
<string name="SSD_hidden">Versteckte Aufgaben</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">Nach Titel</string>
<string name="SSD_sort_alpha">Nach Titel</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">Nach Fälligkeit</string>
<string name="SSD_sort_due">Nach Fälligkeit</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">Nach Wichtigkeit</string>
<string name="SSD_sort_importance">Nach Wichtigkeit</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Gelöschte Aufgaben</string>
<string name="SSD_deleted">Gelöschte Aufgaben</string>

@ -618,25 +618,25 @@ Si puede añada Astrid a la lista de exclusión de modo que no sea matada. De ot
<string name="BFE_Extended">Más…</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Recientemente modificado</string>
<string name="SSD_sort_modified">Recientemente modificado</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Tareas Finalizadas</string>
<string name="SSD_completed">Tareas Finalizadas</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Tareas ocultas</string>
<string name="SSD_hidden">Tareas ocultas</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">Por título</string>
<string name="SSD_sort_alpha">Por título</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">Por fecha de vencimiento</string>
<string name="SSD_sort_due">Por fecha de vencimiento</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">Por importancia</string>
<string name="SSD_sort_importance">Por importancia</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Tareas eliminadas</string>
<string name="SSD_deleted">Tareas eliminadas</string>

@ -617,25 +617,25 @@ to the plugin creator for fastest service.
<string name="BFE_Extended">Plus...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Récemment modifié</string>
<string name="SSD_sort_modified">Récemment modifié</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Tâches complétées</string>
<string name="SSD_completed">Tâches complétées</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Tâches masquées</string>
<string name="SSD_hidden">Tâches masquées</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">Par Titre</string>
<string name="SSD_sort_alpha">Par Titre</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">Par date d\'échéance</string>
<string name="SSD_sort_due">Par date d\'échéance</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">Par priorité</string>
<string name="SSD_sort_importance">Par priorité</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Tâches supprimées</string>
<string name="SSD_deleted">Tâches supprimées</string>

@ -631,25 +631,25 @@ you get stuff done. It features reminders, tags, sync, a widget and more.
<string name="BFE_Extended">More...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Recently Modified</string>
<string name="SSD_sort_modified">Recently Modified</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Tugas Selesai</string>
<string name="SSD_completed">Tugas Selesai</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Hidden Tasks</string>
<string name="SSD_hidden">Hidden Tasks</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">By Title</string>
<string name="SSD_sort_alpha">By Title</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">By Due Date</string>
<string name="SSD_sort_due">By Due Date</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">By Importance</string>
<string name="SSD_sort_importance">By Importance</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Deleted Tasks</string>
<string name="SSD_deleted">Deleted Tasks</string>

@ -620,25 +620,25 @@ you get stuff done. It features reminders, tags, sync, a widget and more.
<string name="BFE_Extended">Altri...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Modificato di recente</string>
<string name="SSD_sort_modified">Modificato di recente</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Attività Completate</string>
<string name="SSD_completed">Attività Completate</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Attività Nascoste</string>
<string name="SSD_hidden">Attività Nascoste</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">Per Titotlo</string>
<string name="SSD_sort_alpha">Per Titotlo</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">Per scadenza</string>
<string name="SSD_sort_due">Per scadenza</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">Per Importanza</string>
<string name="SSD_sort_importance">Per Importanza</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Attività Eliminate</string>
<string name="SSD_deleted">Attività Eliminate</string>

@ -622,25 +622,25 @@ you get stuff done. It features reminders, tags, sync, a widget and more.
<string name="BFE_Extended">その他のフィルタ</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">最近編集したタスク</string>
<string name="SSD_sort_modified">最近編集したタスク</string>
<!-- Completed Filter -->
<string name="BFE_Completed">完了したタスク</string>
<string name="SSD_completed">完了したタスク</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">非表示のタスク</string>
<string name="SSD_hidden">非表示のタスク</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">タイトル順</string>
<string name="SSD_sort_alpha">タイトル順</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">期限順</string>
<string name="SSD_sort_due">期限順</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">重要度順</string>
<string name="SSD_sort_importance">重要度順</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">削除したタスク</string>
<string name="SSD_deleted">削除したタスク</string>

@ -628,25 +628,25 @@ Astrid might not let you know when your tasks are due.\n
<string name="BFE_Extended">More...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Recently Modified</string>
<string name="SSD_sort_modified">Recently Modified</string>
<!-- Completed Filter -->
<string name="BFE_Completed">완료된 할일</string>
<string name="SSD_completed">완료된 할일</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Hidden Tasks</string>
<string name="SSD_hidden">Hidden Tasks</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">By Title</string>
<string name="SSD_sort_alpha">By Title</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">By Due Date</string>
<string name="SSD_sort_due">By Due Date</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">By Importance</string>
<string name="SSD_sort_importance">By Importance</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Deleted Tasks</string>
<string name="SSD_deleted">Deleted Tasks</string>

@ -617,25 +617,25 @@ to the plugin creator for fastest service.
<string name="BFE_Extended">Mer...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Nylig endret</string>
<string name="SSD_sort_modified">Nylig endret</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Fullførte oppgaver</string>
<string name="SSD_completed">Fullførte oppgaver</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Skjulte oppgaver</string>
<string name="SSD_hidden">Skjulte oppgaver</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">Etter tittel</string>
<string name="SSD_sort_alpha">Etter tittel</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">Etter forfallsdato</string>
<string name="SSD_sort_due">Etter forfallsdato</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">Etter viktighet</string>
<string name="SSD_sort_importance">Etter viktighet</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Slettede oppgaver</string>
<string name="SSD_deleted">Slettede oppgaver</string>

@ -631,25 +631,25 @@ you get stuff done. It features reminders, tags, sync, a widget and more.
<string name="BFE_Extended">More...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Recently Modified</string>
<string name="SSD_sort_modified">Recently Modified</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Afgeronde taken</string>
<string name="SSD_completed">Afgeronde taken</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Hidden Tasks</string>
<string name="SSD_hidden">Hidden Tasks</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">By Title</string>
<string name="SSD_sort_alpha">By Title</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">By Due Date</string>
<string name="SSD_sort_due">By Due Date</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">By Importance</string>
<string name="SSD_sort_importance">By Importance</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Deleted Tasks</string>
<string name="SSD_deleted">Deleted Tasks</string>

@ -628,25 +628,25 @@ Astrid might not let you know when your tasks are due.\n
<string name="BFE_Extended">More...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Recently Modified</string>
<string name="SSD_sort_modified">Recently Modified</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Zakończone zadania</string>
<string name="SSD_completed">Zakończone zadania</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Hidden Tasks</string>
<string name="SSD_hidden">Hidden Tasks</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">By Title</string>
<string name="SSD_sort_alpha">By Title</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">By Due Date</string>
<string name="SSD_sort_due">By Due Date</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">By Importance</string>
<string name="SSD_sort_importance">By Importance</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Deleted Tasks</string>
<string name="SSD_deleted">Deleted Tasks</string>

@ -621,25 +621,25 @@ Astrid might not let you know when your tasks are due.\n
<string name="BFE_Extended">Mais...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Recently Modified</string>
<string name="SSD_sort_modified">Recently Modified</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Tarefas Terminadas</string>
<string name="SSD_completed">Tarefas Terminadas</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Hidden Tasks</string>
<string name="SSD_hidden">Hidden Tasks</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">Por Título</string>
<string name="SSD_sort_alpha">Por Título</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">By Due Date</string>
<string name="SSD_sort_due">By Due Date</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">By Importance</string>
<string name="SSD_sort_importance">By Importance</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Deleted Tasks</string>
<string name="SSD_deleted">Deleted Tasks</string>

@ -620,25 +620,25 @@ you get stuff done. It features reminders, tags, sync, a widget and more.
<string name="BFE_Extended">Ещё...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Недавно изменённые</string>
<string name="SSD_sort_modified">Недавно изменённые</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Завершённые задачи</string>
<string name="SSD_completed">Завершённые задачи</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Скрытые задачи</string>
<string name="SSD_hidden">Скрытые задачи</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">По названию</string>
<string name="SSD_sort_alpha">По названию</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">По намеченному сроку</string>
<string name="SSD_sort_due">По намеченному сроку</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">По уровню важности</string>
<string name="SSD_sort_importance">По уровню важности</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Удалённые задачи</string>
<string name="SSD_deleted">Удалённые задачи</string>

@ -631,25 +631,25 @@ you get stuff done. It features reminders, tags, sync, a widget and more.
<string name="BFE_Extended">More...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Recently Modified</string>
<string name="SSD_sort_modified">Recently Modified</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Färdiga uppgifter</string>
<string name="SSD_completed">Färdiga uppgifter</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Hidden Tasks</string>
<string name="SSD_hidden">Hidden Tasks</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">By Title</string>
<string name="SSD_sort_alpha">By Title</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">By Due Date</string>
<string name="SSD_sort_due">By Due Date</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">By Importance</string>
<string name="SSD_sort_importance">By Importance</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Deleted Tasks</string>
<string name="SSD_deleted">Deleted Tasks</string>

@ -631,25 +631,25 @@ you get stuff done. It features reminders, tags, sync, a widget and more.
<string name="BFE_Extended">More...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Recently Modified</string>
<string name="SSD_sort_modified">Recently Modified</string>
<!-- Completed Filter -->
<string name="BFE_Completed">Tamamlanmış Görevler</string>
<string name="SSD_completed">Tamamlanmış Görevler</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Hidden Tasks</string>
<string name="SSD_hidden">Hidden Tasks</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">By Title</string>
<string name="SSD_sort_alpha">By Title</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">By Due Date</string>
<string name="SSD_sort_due">By Due Date</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">By Importance</string>
<string name="SSD_sort_importance">By Importance</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Deleted Tasks</string>
<string name="SSD_deleted">Deleted Tasks</string>

@ -631,25 +631,25 @@ you get stuff done. It features reminders, tags, sync, a widget and more.
<string name="BFE_Extended">More...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">Recently Modified</string>
<string name="SSD_sort_modified">Recently Modified</string>
<!-- Completed Filter -->
<string name="BFE_Completed">已完成的任务</string>
<string name="SSD_completed">已完成的任务</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">Hidden Tasks</string>
<string name="SSD_hidden">Hidden Tasks</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">By Title</string>
<string name="SSD_sort_alpha">By Title</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">By Due Date</string>
<string name="SSD_sort_due">By Due Date</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">By Importance</string>
<string name="SSD_sort_importance">By Importance</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">Deleted Tasks</string>
<string name="SSD_deleted">Deleted Tasks</string>

@ -617,25 +617,25 @@ to the plugin creator for fastest service.
<string name="BFE_Extended">更多...</string>
<!-- sort recent modification filter -->
<string name="BFE_Recent">最近修改過</string>
<string name="SSD_sort_modified">最近修改過</string>
<!-- Completed Filter -->
<string name="BFE_Completed">已完成的工作</string>
<string name="SSD_completed">已完成的工作</string>
<!-- hidden tasks filter -->
<string name="BFE_Hidden">隱藏的工作</string>
<string name="SSD_hidden">隱藏的工作</string>
<!-- sort Alphabetical filter -->
<string name="BFE_Alphabetical">依主旨</string>
<string name="SSD_sort_alpha">依主旨</string>
<!-- sort Due Date filter -->
<string name="BFE_DueDate">依到期日</string>
<string name="SSD_sort_due">依到期日</string>
<!-- sort Importance filter -->
<string name="BFE_Importance">依重要性</string>
<string name="SSD_sort_importance">依重要性</string>
<!-- deleted tasks filter -->
<string name="BFE_Deleted">刪除的工作</string>
<string name="SSD_deleted">刪除的工作</string>

@ -156,6 +156,9 @@
<!-- Menu: Add-ons -->
<string name="TLA_menu_addons">Add-ons</string>
<!-- Menu: Adjust Sort and Hidden Task Settings -->
<string name="TLA_menu_sort">Sort &amp; Hidden</string>
<!-- Menu: Settings -->
<string name="TLA_menu_settings">Settings</string>
@ -209,6 +212,47 @@ button: add task & go to the edit page.
<!-- Context Item: undelete task -->
<string name="TAd_contextUndeleteTask">Undelete Task</string>
<!-- ============================================== SortSelectionDialog == -->
<!-- Sort Selection: dialog title -->
<string name="SSD_title">Sorting and Hidden Tasks</string>
<!-- Hidden Task Selection: show completed tasks -->
<string name="SSD_completed">Show Completed Tasks</string>
<!-- Hidden Task Selection: show hidden tasks -->
<string name="SSD_hidden">Show Hidden Tasks</string>
<!-- Hidden Task Selection: show deleted tasks -->
<string name="SSD_deleted">Show Deleted Tasks</string>
<!-- Sort Selection: sort options header -->
<string name="SSD_sort_header">Sort Options</string>
<!-- Sort Selection: smart sort -->
<string name="SSD_sort_auto">Astrid Smart Sort</string>
<!-- Sort Selection: sort by alpha -->
<string name="SSD_sort_alpha">By Title</string>
<!-- Sort Selection: sort by due date -->
<string name="SSD_sort_due">By Due Date</string>
<!-- Sort Selection: sort by importance -->
<string name="SSD_sort_importance">By Importance</string>
<!-- Sort Selection: sort by modified date -->
<string name="SSD_sort_modified">By Last Modified</string>
<!-- Sort Selection: reverse -->
<string name="SSD_sort_reverse">Reverse Sort</string>
<!-- Sort Button: sort temporarily -->
<string name="SSD_save_temp">Just Once</string>
<!-- Sort Button: sort permanently -->
<string name="SSD_save_always">Always</string>
<!-- =============================================== FilterListActivity == -->
<!-- Filter List Activity Title -->

@ -1,63 +1,63 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.activities;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import com.todoroo.astrid.activity.TaskListActivity;
/**
* Legacy task shortcut, takes users to the updated {@link TaskListActivity}.
* This activity is around so users with existing desktop icons will
* be able to still launch Astrid.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class TaskList extends Activity {
// --- implementation
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
launchTaskList(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
launchTaskList(intent);
}
/**
* intent: ignored for now
* @param intent
*/
private void launchTaskList(Intent intent) {
Intent taskListIntent = new Intent(this, TaskListActivity.class);
startActivity(taskListIntent);
finish();
}
}
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.activities;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import com.todoroo.astrid.activity.TaskListActivity;
/**
* Legacy task shortcut, takes users to the updated {@link TaskListActivity}.
* This activity is around so users with existing desktop icons will
* be able to still launch Astrid.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class TaskList extends Activity {
// --- implementation
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
launchTaskList(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
launchTaskList(intent);
}
/**
* intent: ignored for now
* @param intent
*/
private void launchTaskList(Intent intent) {
Intent taskListIntent = new Intent(this, TaskListActivity.class);
startActivity(taskListIntent);
finish();
}
}

@ -1,144 +1,144 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.todoroo.astrid.activity;
import java.util.Map.Entry;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.os.Bundle;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.api.Filter;
/**
* This activity is launched when a user opens up a notification from the
* tray. It launches the appropriate activity based on the passed in parameters.
*
* @author timsu
*
*/
public class ShortcutActivity extends Activity {
// --- constants
/** token for passing a {@link Filter}'s title through extras */
public static final String TOKEN_FILTER_TITLE = "title"; //$NON-NLS-1$
/** token for passing a {@link Filter}'s sql through extras */
public static final String TOKEN_FILTER_SQL = "sql"; //$NON-NLS-1$
/** token for passing a {@link Filter}'s values for new tasks through extras as string */
@Deprecated
public static final String TOKEN_FILTER_VALUES = "v4nt"; //$NON-NLS-1$
/** token for passing a {@link Filter}'s values for new tasks through extras as exploded ContentValues */
public static final String TOKEN_FILTER_VALUES_ITEM = "v4ntp_"; //$NON-NLS-1$
// --- implementation
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
launchTaskList(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
launchTaskList(intent);
}
private void launchTaskList(Intent intent) {
Bundle extras = intent.getExtras();
if(extras != null && extras.containsKey(TOKEN_FILTER_SQL)) {
// launched from desktop shortcut, must create a fake filter
String title = extras.getString(TOKEN_FILTER_TITLE);
String sql = extras.getString(TOKEN_FILTER_SQL);
ContentValues values = null;
if(extras.containsKey(TOKEN_FILTER_VALUES))
values = AndroidUtilities.contentValuesFromString(extras.getString(TOKEN_FILTER_VALUES));
else {
values = new ContentValues();
for(String key : extras.keySet()) {
if(!key.startsWith(TOKEN_FILTER_VALUES_ITEM))
continue;
Object value = extras.get(key);
key = key.substring(TOKEN_FILTER_VALUES_ITEM.length());
// assume one of the big 4...
if(value instanceof String)
values.put(key, (String) value);
else if(value instanceof Integer)
values.put(key, (Integer) value);
else if(value instanceof Double)
values.put(key, (Double) value);
else if(value instanceof Long)
values.put(key, (Long) value);
else
throw new IllegalStateException("Unsupported bundle type " + value.getClass()); //$NON-NLS-1$
}
}
Filter filter = new Filter("", title, new QueryTemplate(), values); //$NON-NLS-1$
filter.sqlQuery = sql;
Intent taskListIntent = new Intent(this, TaskListActivity.class);
taskListIntent.putExtra(TaskListActivity.TOKEN_FILTER, filter);
startActivity(taskListIntent);
}
finish();
}
public static Intent createIntent(Filter filter) {
Intent shortcutIntent = new Intent(ContextManager.getContext(),
ShortcutActivity.class);
shortcutIntent.setAction(Intent.ACTION_VIEW);
shortcutIntent.putExtra(ShortcutActivity.TOKEN_FILTER_TITLE, filter.title);
shortcutIntent.putExtra(ShortcutActivity.TOKEN_FILTER_SQL, filter.sqlQuery);
if(filter.valuesForNewTasks != null) {
for(Entry<String, Object> item : filter.valuesForNewTasks.valueSet()) {
String key = TOKEN_FILTER_VALUES_ITEM + item.getKey();
Object value = item.getValue();
// assume one of the big 4...
if(value instanceof String)
shortcutIntent.putExtra(key, (String) value);
else if(value instanceof Integer)
shortcutIntent.putExtra(key, (Integer) value);
else if(value instanceof Double)
shortcutIntent.putExtra(key, (Double) value);
else if(value instanceof Long)
shortcutIntent.putExtra(key, (Long) value);
else
throw new IllegalStateException("Unsupported bundle type " + value.getClass()); //$NON-NLS-1$
}
}
return shortcutIntent;
}
}
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.todoroo.astrid.activity;
import java.util.Map.Entry;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.os.Bundle;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.api.Filter;
/**
* This activity is launched when a user opens up a notification from the
* tray. It launches the appropriate activity based on the passed in parameters.
*
* @author timsu
*
*/
public class ShortcutActivity extends Activity {
// --- constants
/** token for passing a {@link Filter}'s title through extras */
public static final String TOKEN_FILTER_TITLE = "title"; //$NON-NLS-1$
/** token for passing a {@link Filter}'s sql through extras */
public static final String TOKEN_FILTER_SQL = "sql"; //$NON-NLS-1$
/** token for passing a {@link Filter}'s values for new tasks through extras as string */
@Deprecated
public static final String TOKEN_FILTER_VALUES = "v4nt"; //$NON-NLS-1$
/** token for passing a {@link Filter}'s values for new tasks through extras as exploded ContentValues */
public static final String TOKEN_FILTER_VALUES_ITEM = "v4ntp_"; //$NON-NLS-1$
// --- implementation
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
launchTaskList(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
launchTaskList(intent);
}
private void launchTaskList(Intent intent) {
Bundle extras = intent.getExtras();
if(extras != null && extras.containsKey(TOKEN_FILTER_SQL)) {
// launched from desktop shortcut, must create a fake filter
String title = extras.getString(TOKEN_FILTER_TITLE);
String sql = extras.getString(TOKEN_FILTER_SQL);
ContentValues values = null;
if(extras.containsKey(TOKEN_FILTER_VALUES))
values = AndroidUtilities.contentValuesFromString(extras.getString(TOKEN_FILTER_VALUES));
else {
values = new ContentValues();
for(String key : extras.keySet()) {
if(!key.startsWith(TOKEN_FILTER_VALUES_ITEM))
continue;
Object value = extras.get(key);
key = key.substring(TOKEN_FILTER_VALUES_ITEM.length());
// assume one of the big 4...
if(value instanceof String)
values.put(key, (String) value);
else if(value instanceof Integer)
values.put(key, (Integer) value);
else if(value instanceof Double)
values.put(key, (Double) value);
else if(value instanceof Long)
values.put(key, (Long) value);
else
throw new IllegalStateException("Unsupported bundle type " + value.getClass()); //$NON-NLS-1$
}
}
Filter filter = new Filter("", title, new QueryTemplate(), values); //$NON-NLS-1$
filter.sqlQuery = sql;
Intent taskListIntent = new Intent(this, TaskListActivity.class);
taskListIntent.putExtra(TaskListActivity.TOKEN_FILTER, filter);
startActivity(taskListIntent);
}
finish();
}
public static Intent createIntent(Filter filter) {
Intent shortcutIntent = new Intent(ContextManager.getContext(),
ShortcutActivity.class);
shortcutIntent.setAction(Intent.ACTION_VIEW);
shortcutIntent.putExtra(ShortcutActivity.TOKEN_FILTER_TITLE, filter.title);
shortcutIntent.putExtra(ShortcutActivity.TOKEN_FILTER_SQL, filter.sqlQuery);
if(filter.valuesForNewTasks != null) {
for(Entry<String, Object> item : filter.valuesForNewTasks.valueSet()) {
String key = TOKEN_FILTER_VALUES_ITEM + item.getKey();
Object value = item.getValue();
// assume one of the big 4...
if(value instanceof String)
shortcutIntent.putExtra(key, (String) value);
else if(value instanceof Integer)
shortcutIntent.putExtra(key, (Integer) value);
else if(value instanceof Double)
shortcutIntent.putExtra(key, (Double) value);
else if(value instanceof Long)
shortcutIntent.putExtra(key, (Long) value);
else
throw new IllegalStateException("Unsupported bundle type " + value.getClass()); //$NON-NLS-1$
}
}
return shortcutIntent;
}
}

@ -0,0 +1,189 @@
package com.todoroo.astrid.activity;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.view.View;
import android.widget.CheckBox;
import android.widget.RadioButton;
import com.timsu.astrid.R;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.TaskService;
/**
* Shows the sort / hidden dialog
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class SortSelectionActivity {
public static final int FLAG_REVERSE_SORT = 1 << 0;
public static final int FLAG_SHOW_COMPLETED = 1 << 1;
public static final int FLAG_SHOW_HIDDEN = 1 << 2;
public static final int FLAG_SHOW_DELETED = 1 << 3;
public static final int SORT_AUTO = 0;
public static final int SORT_ALPHA = 1;
public static final int SORT_DUE = 2;
public static final int SORT_IMPORTANCE = 3;
public static final int SORT_MODIFIED = 4;
public interface OnSortSelectedListener {
public void onSortSelected(boolean always, int flags, int sort);
}
/**
* Create the dialog
* @param activity
* @return
*/
public static AlertDialog createDialog(Activity activity,
OnSortSelectedListener listener, int flags, int sort) {
View body = activity.getLayoutInflater().inflate(R.layout.sort_selection_dialog, null);
if((flags & FLAG_REVERSE_SORT) > 0)
((CheckBox)body.findViewById(R.id.reverse)).setChecked(true);
if((flags & FLAG_SHOW_COMPLETED) > 0)
((CheckBox)body.findViewById(R.id.completed)).setChecked(true);
if((flags & FLAG_SHOW_HIDDEN) > 0)
((CheckBox)body.findViewById(R.id.hidden)).setChecked(true);
if((flags & FLAG_SHOW_DELETED) > 0)
((CheckBox)body.findViewById(R.id.deleted)).setChecked(true);
switch(sort) {
case SORT_ALPHA:
((RadioButton)body.findViewById(R.id.sort_alpha)).setChecked(true);
break;
case SORT_DUE:
((RadioButton)body.findViewById(R.id.sort_due)).setChecked(true);
break;
case SORT_IMPORTANCE:
((RadioButton)body.findViewById(R.id.sort_importance)).setChecked(true);
break;
case SORT_MODIFIED:
((RadioButton)body.findViewById(R.id.sort_modified)).setChecked(true);
break;
default:
((RadioButton)body.findViewById(R.id.sort_smart)).setChecked(true);
}
AlertDialog dialog = new AlertDialog.Builder(activity).
setTitle(R.string.SSD_title).
setIcon(android.R.drawable.ic_menu_sort_by_size).
setView(body).
setPositiveButton(R.string.SSD_save_always,
new DialogOkListener(body, listener, true)).
setNegativeButton(R.string.SSD_save_temp,
new DialogOkListener(body, listener, false)).
create();
dialog.setOwnerActivity(activity);
return dialog;
}
@SuppressWarnings("nls")
public static String adjustQueryForFlagsAndSort(String originalSql, int flags, int sort) {
// sort
if(!originalSql.toUpperCase().contains("ORDER BY")) {
Order order;
switch(sort) {
case SortSelectionActivity.SORT_ALPHA:
order = Order.asc(Functions.upper(Task.TITLE));
break;
case SortSelectionActivity.SORT_DUE:
order = Order.asc(Functions.caseStatement(Task.DUE_DATE.eq(0),
DateUtilities.now()*2, Task.DUE_DATE) + "+" + Task.IMPORTANCE);
break;
case SortSelectionActivity.SORT_IMPORTANCE:
order = Order.asc(Task.IMPORTANCE + "*" + (2*DateUtilities.now()) + //$NON-NLS-1$
"+" + Functions.caseStatement(Task.DUE_DATE.eq(0), //$NON-NLS-1$
Functions.now() + "+" + DateUtilities.ONE_WEEK, //$NON-NLS-1$
Task.DUE_DATE));
break;
case SortSelectionActivity.SORT_MODIFIED:
order = Order.desc(Task.MODIFICATION_DATE);
break;
default:
order = TaskService.defaultTaskOrder();
}
if((flags & SortSelectionActivity.FLAG_REVERSE_SORT) > 0)
order = order.reverse();
originalSql += " ORDER BY " + order;
}
// flags
if((flags & FLAG_SHOW_COMPLETED) > 0)
originalSql = originalSql.replace(Task.COMPLETION_DATE.eq(0).toString(),
Criterion.all.toString());
if((flags & FLAG_SHOW_HIDDEN) > 0)
originalSql = originalSql.replace(TaskCriteria.isVisible().toString(),
Criterion.all.toString());
if((flags & FLAG_SHOW_DELETED) > 0)
originalSql = originalSql.replace(Task.DELETION_DATE.eq(0).toString(),
Criterion.all.toString());
return originalSql;
}
// --- internal implementation
/** preference key for sort flags */
public static final String PREF_SORT_FLAGS = "sort_flags"; //$NON-NLS-1$
/** preference key for sort sort */
public static final String PREF_SORT_SORT = "sort_sort"; //$NON-NLS-1$
private SortSelectionActivity() {
// use the static method
}
private static class DialogOkListener implements OnClickListener {
private final OnSortSelectedListener listener;
private final boolean always;
private final View body;
public DialogOkListener(View body, OnSortSelectedListener listener, boolean always) {
this.body = body;
this.listener = listener;
this.always = always;
}
@Override
public void onClick(DialogInterface view, int button) {
int flags = 0;
int sort = 0;
if(((CheckBox)body.findViewById(R.id.reverse)).isChecked())
flags |= FLAG_REVERSE_SORT;
if(((CheckBox)body.findViewById(R.id.completed)).isChecked())
flags |= FLAG_SHOW_COMPLETED;
if(((CheckBox)body.findViewById(R.id.hidden)).isChecked())
flags |= FLAG_SHOW_HIDDEN;
if(((CheckBox)body.findViewById(R.id.deleted)).isChecked())
flags |= FLAG_SHOW_DELETED;
if(((RadioButton)body.findViewById(R.id.sort_alpha)).isChecked())
sort = SORT_ALPHA;
else if(((RadioButton)body.findViewById(R.id.sort_due)).isChecked())
sort = SORT_DUE;
else if(((RadioButton)body.findViewById(R.id.sort_importance)).isChecked())
sort = SORT_IMPORTANCE;
else if(((RadioButton)body.findViewById(R.id.sort_modified)).isChecked())
sort = SORT_MODIFIED;
else
sort = SORT_AUTO;
listener.onSortSelected(always, flags, sort);
}
}
}

@ -3,6 +3,7 @@ package com.todoroo.astrid.activity;
import java.util.Date;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicReference;
import android.app.AlertDialog;
import android.app.ListActivity;
@ -48,6 +49,7 @@ import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.utility.AndroidUtilities;
@ -56,6 +58,7 @@ import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Pair;
import com.todoroo.andlib.widget.GestureService;
import com.todoroo.andlib.widget.GestureService.GestureInterface;
import com.todoroo.astrid.activity.SortSelectionActivity.OnSortSelectedListener;
import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.adapter.TaskAdapter.ViewHolder;
import com.todoroo.astrid.api.AstridApiConstants;
@ -80,6 +83,8 @@ import com.todoroo.astrid.service.StartupService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.utility.Constants;
import com.todoroo.astrid.utility.Flags;
import com.todoroo.astrid.utility.Preferences;
import com.todoroo.astrid.widget.TasksWidget;
/**
* Primary activity for the Bente application. Shows a list of upcoming
@ -88,29 +93,32 @@ import com.todoroo.astrid.utility.Flags;
* @author Tim Su <tim@todoroo.com>
*
*/
public class TaskListActivity extends ListActivity implements OnScrollListener, GestureInterface {
public class TaskListActivity extends ListActivity implements OnScrollListener,
GestureInterface, OnSortSelectedListener {
// --- activities
public static final int ACTIVITY_EDIT_TASK = 0;
public static final int ACTIVITY_SETTINGS = 1;
public static final int ACTIVITY_ADDONS = 2;
public static final int ACTIVITY_MENU_EXTERNAL = 3;
public static final int ACTIVITY_SORT = 2;
public static final int ACTIVITY_ADDONS = 3;
public static final int ACTIVITY_MENU_EXTERNAL = 4;
// --- menu codes
private static final int MENU_ADDONS_ID = Menu.FIRST + 1;
private static final int MENU_SETTINGS_ID = Menu.FIRST + 2;
private static final int MENU_HELP_ID = Menu.FIRST + 3;
private static final int MENU_ADDON_INTENT_ID = Menu.FIRST + 4;
private static final int MENU_SORT_ID = Menu.FIRST + 3;
private static final int MENU_HELP_ID = Menu.FIRST + 4;
private static final int MENU_ADDON_INTENT_ID = Menu.FIRST + 5;
private static final int CONTEXT_MENU_EDIT_TASK_ID = Menu.FIRST + 5;
private static final int CONTEXT_MENU_DELETE_TASK_ID = Menu.FIRST + 6;
private static final int CONTEXT_MENU_UNDELETE_TASK_ID = Menu.FIRST + 7;
private static final int CONTEXT_MENU_ADDON_INTENT_ID = Menu.FIRST + 8;
private static final int CONTEXT_MENU_EDIT_TASK_ID = Menu.FIRST + 6;
private static final int CONTEXT_MENU_DELETE_TASK_ID = Menu.FIRST + 7;
private static final int CONTEXT_MENU_UNDELETE_TASK_ID = Menu.FIRST + 8;
private static final int CONTEXT_MENU_ADDON_INTENT_ID = Menu.FIRST + 9;
/** menu code indicating the end of the context menu */
private static final int CONTEXT_MENU_DEBUG = Menu.FIRST + 9;
private static final int CONTEXT_MENU_DEBUG = Menu.FIRST + 10;
// --- constants
@ -143,6 +151,9 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
ImageButton quickAddButton;
EditText quickAddBox;
Filter filter;
int sortFlags;
int sortSort;
AtomicReference<String> sqlQueryTemplate = new AtomicReference<String>();
/* ======================================================================
* ======================================================= initialization
@ -213,6 +224,10 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
R.string.TLA_menu_settings);
item.setIcon(android.R.drawable.ic_menu_preferences);
item = menu.add(Menu.NONE, MENU_SORT_ID, Menu.NONE,
R.string.TLA_menu_sort);
item.setIcon(android.R.drawable.ic_menu_sort_by_size);
item = menu.add(Menu.NONE, MENU_HELP_ID, Menu.NONE,
R.string.TLA_menu_help);
item.setIcon(android.R.drawable.ic_menu_help);
@ -348,6 +363,9 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
} catch (VerifyError e) {
// failed check, no gestures :P
}
sortFlags = Preferences.getInt(SortSelectionActivity.PREF_SORT_FLAGS, 0);
sortSort= Preferences.getInt(SortSelectionActivity.PREF_SORT_SORT, 0);
}
public void bindServices() {
@ -509,21 +527,18 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
* Fill in the Task List with current items
* @param withCustomId force task with given custom id to be part of list
*/
@SuppressWarnings("nls")
protected void setUpTaskList() {
// use default ordering if none specified
if(!filter.sqlQuery.toUpperCase().contains("ORDER BY")) {
filter.sqlQuery += " ORDER BY " + TaskService.defaultTaskOrder();
}
sqlQueryTemplate.set(SortSelectionActivity.adjustQueryForFlagsAndSort(filter.sqlQuery,
sortFlags, sortSort));
// perform query
TodorooCursor<Task> currentCursor = taskService.fetchFiltered(
filter, null, TaskAdapter.PROPERTIES);
sqlQueryTemplate.get(), null, TaskAdapter.PROPERTIES);
startManagingCursor(currentCursor);
// set up list adapters
taskAdapter = new TaskAdapter(this, R.layout.task_adapter_row,
currentCursor, filter, false, null);
currentCursor, sqlQueryTemplate, false, null);
setListAdapter(taskAdapter);
getListView().setOnScrollListener(this);
registerForContextMenu(getListView());
@ -549,14 +564,13 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
}
// create a custom cursor
if(filter.sqlQuery == null)
filter.sqlQuery = "";
if(!filter.sqlQuery.contains("WHERE"))
filter.sqlQuery += " WHERE " + TaskCriteria.byId(withCustomId);
if(!sqlQueryTemplate.get().contains("WHERE"))
sqlQueryTemplate.set(sqlQueryTemplate.get() + " WHERE " + TaskCriteria.byId(withCustomId));
else
filter.sqlQuery = filter.sqlQuery.replace("WHERE ", "WHERE " +
TaskCriteria.byId(withCustomId) + " OR ");
currentCursor = taskService.fetchFiltered(filter, null, TaskAdapter.PROPERTIES);
sqlQueryTemplate.set(sqlQueryTemplate.get().replace("WHERE ", "WHERE " +
TaskCriteria.byId(withCustomId) + " OR "));
currentCursor = taskService.fetchFiltered(sqlQueryTemplate.get(), null, TaskAdapter.PROPERTIES);
getListView().setFilterText("");
startManagingCursor(currentCursor);
@ -717,6 +731,11 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
intent = new Intent(this, EditPreferences.class);
startActivityForResult(intent, ACTIVITY_SETTINGS);
return true;
case MENU_SORT_ID:
AlertDialog dialog = SortSelectionActivity.createDialog(this,
this, sortFlags, sortSort);
dialog.show();
return true;
case MENU_HELP_ID:
intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://weloveastrid.com/help-user-guide-astrid-v3/active-tasks/")); //$NON-NLS-1$
@ -727,8 +746,8 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
AndroidUtilities.startExternalIntent(this, intent, ACTIVITY_MENU_EXTERNAL);
return true;
// --- context menu items
// context menu items
case CONTEXT_MENU_ADDON_INTENT_ID: {
intent = item.getIntent();
AndroidUtilities.startExternalIntent(this, intent, ACTIVITY_MENU_EXTERNAL);
@ -805,4 +824,19 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
}
}
@Override
public void onSortSelected(boolean always, int flags, int sort) {
sortFlags = flags;
sortSort = sort;
if(always) {
Preferences.setInt(SortSelectionActivity.PREF_SORT_FLAGS, flags);
Preferences.setInt(SortSelectionActivity.PREF_SORT_SORT, sort);
ContextManager.getContext().startService(new Intent(ContextManager.getContext(),
TasksWidget.UpdateService.class));
}
setUpTaskList();
}
}

@ -5,6 +5,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import android.app.ListActivity;
import android.content.Context;
@ -15,12 +16,12 @@ import android.graphics.Paint;
import android.text.Html;
import android.text.util.Linkify;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.view.View.OnCreateContextMenuListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.CheckBox;
@ -42,7 +43,6 @@ import com.todoroo.astrid.activity.TaskEditActivity;
import com.todoroo.astrid.alarms.AlarmDetailExposer;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.TaskAction;
import com.todoroo.astrid.api.TaskDecoration;
import com.todoroo.astrid.model.Task;
@ -109,7 +109,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
private final LayoutInflater inflater;
private int fontSize;
private final Filter filter;
private final AtomicReference<String> query;
// the task that's expanded
private long expanded = -1;
@ -136,7 +136,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
* task listener. can be null
*/
public TaskAdapter(ListActivity activity, int resource,
Cursor c, Filter filter, boolean autoRequery,
Cursor c, AtomicReference<String> query, boolean autoRequery,
OnCompletedTaskListener onCompletedTaskListener) {
super(activity, c, autoRequery);
DependencyInjectionService.getInstance().inject(this);
@ -144,7 +144,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
inflater = (LayoutInflater) activity.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
this.filter = filter;
this.query = query;
this.resource = resource;
this.activity = activity;
this.onCompletedTaskListener = onCompletedTaskListener;
@ -169,7 +169,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
// perform query
TodorooCursor<Task> newCursor = taskService.fetchFiltered(
filter, constraint, TaskAdapter.PROPERTIES);
query.get(), constraint, TaskAdapter.PROPERTIES);
activity.startManagingCursor(newCursor);
return newCursor;
}

@ -1,289 +1,289 @@
package com.todoroo.astrid.provider;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.util.Log;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TagService.Tag;
/**
* This is the legacy Astrid task provider. While it will continue to be
* supported, note that it does not expose all of the information in
* Astrid, nor does it support many editing operations.
*
* See the individual methods for a description of what is returned.
*
* @author Tim Su <tim@todoroo.com>
*
*/
@SuppressWarnings("nls")
public class Astrid2TaskProvider extends ContentProvider {
static {
AstridDependencyInjector.initialize();
}
private static final String TAG = "MessageProvider";
private static final boolean LOGD = false;
public static final String AUTHORITY = "com.timsu.astrid.tasksprovider";
public static final Uri CONTENT_URI = Uri.parse("content://com.timsu.astrid.tasksprovider");
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
private static final int MAX_NUMBER_OF_TASKS = 30;
private final static String NAME = "name";
private final static String IMPORTANCE_COLOR = "importance_color";
private final static String IDENTIFIER = "identifier";
private final static String PREFERRED_DUE_DATE = "preferredDueDate";
private final static String DEFINITE_DUE_DATE = "definiteDueDate";
private final static String IMPORTANCE = "importance";
private final static String ID = "id";
// fake property for updating that completes a task
private final static String COMPLETED = "completed";
private final static String TAGS_ID = "tags_id";
static String[] TASK_FIELD_LIST = new String[] { NAME, IMPORTANCE_COLOR, PREFERRED_DUE_DATE, DEFINITE_DUE_DATE,
IMPORTANCE, IDENTIFIER, TAGS_ID };
static String[] TAGS_FIELD_LIST = new String[] { ID, NAME };
private static final int URI_TASKS = 0;
private static final int URI_TAGS = 1;
private static final String TAG_SEPARATOR = "|";
@Autowired
private TaskService taskService;
private static Context ctx = null;
static {
URI_MATCHER.addURI(AUTHORITY, "tasks", URI_TASKS);
URI_MATCHER.addURI(AUTHORITY, "tags", URI_TAGS);
AstridDependencyInjector.initialize();
}
public Astrid2TaskProvider() {
DependencyInjectionService.getInstance().inject(this);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
if (LOGD)
Log.d(TAG, "delete");
return 0;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public boolean onCreate() {
ctx = getContext();
return false;
}
/**
* Note: tag id is no longer a real column, so we pass in a UID
* generated from the tag string.
*
* @return two-column cursor: tag id (string) and tag name
*/
public Cursor getTags() {
Tag[] tags = TagService.getInstance().getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE,
Criterion.all);
MatrixCursor ret = new MatrixCursor(TAGS_FIELD_LIST);
for (int i = 0; i < tags.length; i++) {
Object[] values = new Object[2];
values[0] = tagNameToLong(tags[i].tag);
values[1] = tags[i].tag;
ret.addRow(values);
}
return ret;
}
private long tagNameToLong(String tag) {
MessageDigest m;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
return -1;
}
m.update(tag.getBytes(), 0, tag.length());
return new BigInteger(1, m.digest()).longValue();
}
/**
* Cursor with the following columns
* <ol>
* <li>task title, string
* <li>task importance color, int android RGB color
* <li>task due date (was: preferred due date), long millis since epoch
* <li>task due date (was: absolute due date), long millis since epoch
* <li>task importance, integer from 0 to 3 (0 => most important)
* <li>task id, long
* <li>task tags, string tags separated by |
* </ol>
*
* @return cursor as described above
*/
public Cursor getTasks() {
MatrixCursor ret = new MatrixCursor(TASK_FIELD_LIST);
TodorooCursor<Task> cursor = taskService.query(Query.select(Task.ID, Task.TITLE,
Task.IMPORTANCE, Task.DUE_DATE).where(Criterion.and(TaskCriteria.isActive(),
TaskCriteria.isVisible())).
orderBy(TaskService.defaultTaskOrder()).limit(MAX_NUMBER_OF_TASKS));
try {
int[] importanceColors = Task.getImportanceColors(ctx.getResources());
Task task = new Task();
for (int i = 0; i < cursor.getCount(); i++) {
cursor.moveToNext();
task.readFromCursor(cursor);
StringBuilder taskTags = new StringBuilder();
TodorooCursor<Metadata> tagCursor = TagService.getInstance().getTags(task.getId());
try {
for(tagCursor.moveToFirst(); !tagCursor.isAfterLast(); tagCursor.moveToNext())
taskTags.append(tagCursor.get(TagService.TAG)).append(TAG_SEPARATOR);
} finally {
tagCursor.close();
}
Object[] values = new Object[7];
values[0] = task.getValue(Task.TITLE);
values[1] = importanceColors[task.getValue(Task.IMPORTANCE)];
values[2] = task.getValue(Task.DUE_DATE);
values[3] = task.getValue(Task.DUE_DATE);
values[4] = task.getValue(Task.IMPORTANCE);
values[5] = task.getId();
values[6] = taskTags.toString();
ret.addRow(values);
}
} finally {
cursor.close();
}
return ret;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
if (LOGD)
Log.d(TAG, "query");
Cursor cursor;
switch (URI_MATCHER.match(uri)) {
case URI_TASKS:
cursor = getTasks();
break;
case URI_TAGS:
cursor = getTags();
break;
default:
throw new IllegalStateException("Unrecognized URI:" + uri);
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
if (LOGD)
Log.d(TAG, "update");
switch (URI_MATCHER.match(uri)) {
case URI_TASKS:
Task task = new Task();
// map values
if(values.containsKey(NAME))
task.setValue(Task.TITLE, values.getAsString(NAME));
if(values.containsKey(PREFERRED_DUE_DATE))
task.setValue(Task.DUE_DATE, values.getAsLong(PREFERRED_DUE_DATE));
if(values.containsKey(DEFINITE_DUE_DATE))
task.setValue(Task.DUE_DATE, values.getAsLong(DEFINITE_DUE_DATE));
if(values.containsKey(IMPORTANCE))
task.setValue(Task.IMPORTANCE, values.getAsInteger(IMPORTANCE));
if(values.containsKey(COMPLETED))
task.setValue(Task.COMPLETION_DATE,
values.getAsBoolean(COMPLETED) ? DateUtilities.now() : 0);
// map selection criteria
String criteria = selection.replace(NAME, Task.TITLE.name).
replace(PREFERRED_DUE_DATE, Task.DUE_DATE.name).
replace(DEFINITE_DUE_DATE, Task.DUE_DATE.name).
replace(IDENTIFIER, Task.ID.name).
replace(ID, Task.ID.name).
replace(IMPORTANCE, Task.IMPORTANCE.name);
return taskService.updateBySelection(criteria, selectionArgs, task);
case URI_TAGS:
throw new UnsupportedOperationException("tags updating: not yet");
default:
throw new IllegalStateException("Unrecognized URI:" + uri);
}
}
public static void notifyDatabaseModification() {
if (LOGD)
Log.d(TAG, "notifyDatabaseModification");
ctx.getContentResolver().notifyChange(CONTENT_URI, null);
}
}
package com.todoroo.astrid.provider;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.util.Log;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TagService.Tag;
/**
* This is the legacy Astrid task provider. While it will continue to be
* supported, note that it does not expose all of the information in
* Astrid, nor does it support many editing operations.
*
* See the individual methods for a description of what is returned.
*
* @author Tim Su <tim@todoroo.com>
*
*/
@SuppressWarnings("nls")
public class Astrid2TaskProvider extends ContentProvider {
static {
AstridDependencyInjector.initialize();
}
private static final String TAG = "MessageProvider";
private static final boolean LOGD = false;
public static final String AUTHORITY = "com.timsu.astrid.tasksprovider";
public static final Uri CONTENT_URI = Uri.parse("content://com.timsu.astrid.tasksprovider");
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
private static final int MAX_NUMBER_OF_TASKS = 30;
private final static String NAME = "name";
private final static String IMPORTANCE_COLOR = "importance_color";
private final static String IDENTIFIER = "identifier";
private final static String PREFERRED_DUE_DATE = "preferredDueDate";
private final static String DEFINITE_DUE_DATE = "definiteDueDate";
private final static String IMPORTANCE = "importance";
private final static String ID = "id";
// fake property for updating that completes a task
private final static String COMPLETED = "completed";
private final static String TAGS_ID = "tags_id";
static String[] TASK_FIELD_LIST = new String[] { NAME, IMPORTANCE_COLOR, PREFERRED_DUE_DATE, DEFINITE_DUE_DATE,
IMPORTANCE, IDENTIFIER, TAGS_ID };
static String[] TAGS_FIELD_LIST = new String[] { ID, NAME };
private static final int URI_TASKS = 0;
private static final int URI_TAGS = 1;
private static final String TAG_SEPARATOR = "|";
@Autowired
private TaskService taskService;
private static Context ctx = null;
static {
URI_MATCHER.addURI(AUTHORITY, "tasks", URI_TASKS);
URI_MATCHER.addURI(AUTHORITY, "tags", URI_TAGS);
AstridDependencyInjector.initialize();
}
public Astrid2TaskProvider() {
DependencyInjectionService.getInstance().inject(this);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
if (LOGD)
Log.d(TAG, "delete");
return 0;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public boolean onCreate() {
ctx = getContext();
return false;
}
/**
* Note: tag id is no longer a real column, so we pass in a UID
* generated from the tag string.
*
* @return two-column cursor: tag id (string) and tag name
*/
public Cursor getTags() {
Tag[] tags = TagService.getInstance().getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE,
Criterion.all);
MatrixCursor ret = new MatrixCursor(TAGS_FIELD_LIST);
for (int i = 0; i < tags.length; i++) {
Object[] values = new Object[2];
values[0] = tagNameToLong(tags[i].tag);
values[1] = tags[i].tag;
ret.addRow(values);
}
return ret;
}
private long tagNameToLong(String tag) {
MessageDigest m;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
return -1;
}
m.update(tag.getBytes(), 0, tag.length());
return new BigInteger(1, m.digest()).longValue();
}
/**
* Cursor with the following columns
* <ol>
* <li>task title, string
* <li>task importance color, int android RGB color
* <li>task due date (was: preferred due date), long millis since epoch
* <li>task due date (was: absolute due date), long millis since epoch
* <li>task importance, integer from 0 to 3 (0 => most important)
* <li>task id, long
* <li>task tags, string tags separated by |
* </ol>
*
* @return cursor as described above
*/
public Cursor getTasks() {
MatrixCursor ret = new MatrixCursor(TASK_FIELD_LIST);
TodorooCursor<Task> cursor = taskService.query(Query.select(Task.ID, Task.TITLE,
Task.IMPORTANCE, Task.DUE_DATE).where(Criterion.and(TaskCriteria.isActive(),
TaskCriteria.isVisible())).
orderBy(TaskService.defaultTaskOrder()).limit(MAX_NUMBER_OF_TASKS));
try {
int[] importanceColors = Task.getImportanceColors(ctx.getResources());
Task task = new Task();
for (int i = 0; i < cursor.getCount(); i++) {
cursor.moveToNext();
task.readFromCursor(cursor);
StringBuilder taskTags = new StringBuilder();
TodorooCursor<Metadata> tagCursor = TagService.getInstance().getTags(task.getId());
try {
for(tagCursor.moveToFirst(); !tagCursor.isAfterLast(); tagCursor.moveToNext())
taskTags.append(tagCursor.get(TagService.TAG)).append(TAG_SEPARATOR);
} finally {
tagCursor.close();
}
Object[] values = new Object[7];
values[0] = task.getValue(Task.TITLE);
values[1] = importanceColors[task.getValue(Task.IMPORTANCE)];
values[2] = task.getValue(Task.DUE_DATE);
values[3] = task.getValue(Task.DUE_DATE);
values[4] = task.getValue(Task.IMPORTANCE);
values[5] = task.getId();
values[6] = taskTags.toString();
ret.addRow(values);
}
} finally {
cursor.close();
}
return ret;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
if (LOGD)
Log.d(TAG, "query");
Cursor cursor;
switch (URI_MATCHER.match(uri)) {
case URI_TASKS:
cursor = getTasks();
break;
case URI_TAGS:
cursor = getTags();
break;
default:
throw new IllegalStateException("Unrecognized URI:" + uri);
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
if (LOGD)
Log.d(TAG, "update");
switch (URI_MATCHER.match(uri)) {
case URI_TASKS:
Task task = new Task();
// map values
if(values.containsKey(NAME))
task.setValue(Task.TITLE, values.getAsString(NAME));
if(values.containsKey(PREFERRED_DUE_DATE))
task.setValue(Task.DUE_DATE, values.getAsLong(PREFERRED_DUE_DATE));
if(values.containsKey(DEFINITE_DUE_DATE))
task.setValue(Task.DUE_DATE, values.getAsLong(DEFINITE_DUE_DATE));
if(values.containsKey(IMPORTANCE))
task.setValue(Task.IMPORTANCE, values.getAsInteger(IMPORTANCE));
if(values.containsKey(COMPLETED))
task.setValue(Task.COMPLETION_DATE,
values.getAsBoolean(COMPLETED) ? DateUtilities.now() : 0);
// map selection criteria
String criteria = selection.replace(NAME, Task.TITLE.name).
replace(PREFERRED_DUE_DATE, Task.DUE_DATE.name).
replace(DEFINITE_DUE_DATE, Task.DUE_DATE.name).
replace(IDENTIFIER, Task.ID.name).
replace(ID, Task.ID.name).
replace(IMPORTANCE, Task.IMPORTANCE.name);
return taskService.updateBySelection(criteria, selectionArgs, task);
case URI_TAGS:
throw new UnsupportedOperationException("tags updating: not yet");
default:
throw new IllegalStateException("Unrecognized URI:" + uri);
}
}
public static void notifyDatabaseModification() {
if (LOGD)
Log.d(TAG, "notifyDatabaseModification");
ctx.getContentResolver().notifyChange(CONTENT_URI, null);
}
}

@ -9,10 +9,9 @@ import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
@ -157,14 +156,14 @@ public class TaskService {
* @return
*/
@SuppressWarnings("nls")
public TodorooCursor<Task> fetchFiltered(Filter filter, CharSequence constraint,
public TodorooCursor<Task> fetchFiltered(String queryTemplate, CharSequence constraint,
Property<?>... properties) {
Criterion whereConstraint = null;
if(constraint != null)
whereConstraint = Functions.upper(Task.TITLE).like("%" +
constraint.toString().toUpperCase() + "%");
if(filter == null || filter.sqlQuery == null) {
if(queryTemplate == null) {
if(whereConstraint == null)
return taskDao.query(Query.select(properties));
else
@ -173,12 +172,13 @@ public class TaskService {
String sql;
if(whereConstraint != null) {
if(!filter.sqlQuery.toUpperCase().contains("WHERE"))
sql = filter.sqlQuery + " WHERE " + whereConstraint;
if(!queryTemplate.toUpperCase().contains("WHERE"))
sql = queryTemplate + " WHERE " + whereConstraint;
else
sql = filter.sqlQuery.replace("WHERE ", "WHERE " + whereConstraint + " AND ");
sql = queryTemplate.replace("WHERE ", "WHERE " + whereConstraint + " AND ");
} else
sql = filter.sqlQuery;
sql = queryTemplate;
return taskDao.query(Query.select(properties).withQueryTemplate(sql));
}

@ -224,6 +224,31 @@ public class Preferences {
editor.commit();
}
// --- preference fetching (int)
/** Gets a int preference
*
* @param key
* @param defValue
* @return default if value is unset otherwise the value
*/
public static int getInt(String key, int defValue) {
Context context = ContextManager.getContext();
return getPrefs(context).getInt(key, defValue);
}
/**
* Sets int preference
* @param key
* @param value
*/
public static void setInt(String key, int value) {
Context context = ContextManager.getContext();
Editor editor = getPrefs(context).edit();
editor.putInt(key, value);
editor.commit();
}
// --- preference fetching (long)
/** Gets a long preference

@ -1,146 +1,151 @@
package com.todoroo.astrid.widget;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.activity.TaskEditActivity;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.core.CoreFilterExposer;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.TaskService;
public class TasksWidget extends AppWidgetProvider {
static {
AstridDependencyInjector.initialize();
}
public final static int[] TEXT_IDS = { R.id.task_1, R.id.task_2,
R.id.task_3, R.id.task_4, R.id.task_5 };
public final static int[] SEPARATOR_IDS = { R.id.separator_1,
R.id.separator_2, R.id.separator_3, R.id.separator_4 };
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
try {
super.onUpdate(context, appWidgetManager, appWidgetIds);
// Start in service to prevent Application Not Responding timeout
context.startService(new Intent(context, UpdateService.class));
} catch (SecurityException e) {
// :(
}
}
public static class UpdateService extends Service {
@Autowired
Database database;
@Autowired
TaskService taskService;
@Override
public void onStart(Intent intent, int startId) {
ContextManager.setContext(this);
RemoteViews updateViews = buildUpdate(this);
ComponentName thisWidget = new ComponentName(this,
TasksWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@SuppressWarnings("nls")
public RemoteViews buildUpdate(Context context) {
DependencyInjectionService.getInstance().inject(this);
RemoteViews views = null;
views = new RemoteViews(context.getPackageName(),
R.layout.widget_initialized);
int[] textIDs = TEXT_IDS;
int[] separatorIDs = SEPARATOR_IDS;
int numberOfTasks = 5;
Intent listIntent = new Intent(context, TaskListActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
listIntent, 0);
views.setOnClickPendingIntent(R.id.taskbody, pendingIntent);
TodorooCursor<Task> cursor = null;
try {
Filter inboxFilter = CoreFilterExposer.buildInboxFilter(getResources());
inboxFilter.sqlQuery += "ORDER BY " + TaskService.defaultTaskOrder() + " LIMIT " + numberOfTasks;
database.openForReading();
cursor = taskService.fetchFiltered(inboxFilter, null, Task.TITLE, Task.DUE_DATE);
Task task = new Task();
for (int i = 0; i < cursor.getCount() && i < numberOfTasks; i++) {
cursor.moveToPosition(i);
task.readFromCursor(cursor);
String textContent = "";
int textColor = Color.WHITE;
textContent = task.getValue(Task.TITLE);
if(task.hasDueDate() && task.getValue(Task.DUE_DATE) < DateUtilities.now())
textColor = context.getResources().getColor(R.color.task_list_overdue);
if(i > 0)
views.setViewVisibility(separatorIDs[i-1], View.VISIBLE);
views.setTextViewText(textIDs[i], textContent);
views.setTextColor(textIDs[i], textColor);
}
for(int i = cursor.getCount() - 1; i < separatorIDs.length; i++) {
if(i >= 0)
views.setViewVisibility(separatorIDs[i], View.INVISIBLE);
if(i > cursor.getCount() - 1)
views.setViewVisibility(textIDs[i], View.INVISIBLE);
}
} catch (Exception e) {
// can happen if database is not ready
Log.e("WIDGET-UPDATE", "Error updating widget", e);
} finally {
if(cursor != null)
cursor.close();
}
Intent editIntent = new Intent(context, TaskEditActivity.class);
pendingIntent = PendingIntent.getActivity(context, 0,
editIntent, 0);
views.setOnClickPendingIntent(R.id.widget_button, pendingIntent);
return views;
}
}
}
package com.todoroo.astrid.widget;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.activity.SortSelectionActivity;
import com.todoroo.astrid.activity.TaskEditActivity;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.core.CoreFilterExposer;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.utility.Preferences;
public class TasksWidget extends AppWidgetProvider {
static {
AstridDependencyInjector.initialize();
}
public final static int[] TEXT_IDS = { R.id.task_1, R.id.task_2,
R.id.task_3, R.id.task_4, R.id.task_5 };
public final static int[] SEPARATOR_IDS = { R.id.separator_1,
R.id.separator_2, R.id.separator_3, R.id.separator_4 };
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
try {
super.onUpdate(context, appWidgetManager, appWidgetIds);
// Start in service to prevent Application Not Responding timeout
context.startService(new Intent(context, UpdateService.class));
} catch (SecurityException e) {
// :(
}
}
public static class UpdateService extends Service {
@Autowired
Database database;
@Autowired
TaskService taskService;
@Override
public void onStart(Intent intent, int startId) {
ContextManager.setContext(this);
RemoteViews updateViews = buildUpdate(this);
ComponentName thisWidget = new ComponentName(this,
TasksWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@SuppressWarnings("nls")
public RemoteViews buildUpdate(Context context) {
DependencyInjectionService.getInstance().inject(this);
RemoteViews views = null;
views = new RemoteViews(context.getPackageName(),
R.layout.widget_initialized);
int[] textIDs = TEXT_IDS;
int[] separatorIDs = SEPARATOR_IDS;
int numberOfTasks = 5;
Intent listIntent = new Intent(context, TaskListActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
listIntent, 0);
views.setOnClickPendingIntent(R.id.taskbody, pendingIntent);
TodorooCursor<Task> cursor = null;
try {
Filter inboxFilter = CoreFilterExposer.buildInboxFilter(getResources());
int flags = Preferences.getInt(SortSelectionActivity.PREF_SORT_FLAGS, 0);
int sort = Preferences.getInt(SortSelectionActivity.PREF_SORT_SORT, 0);
String query = SortSelectionActivity.adjustQueryForFlagsAndSort(
inboxFilter.sqlQuery, flags, sort) + " LIMIT " + numberOfTasks;
database.openForReading();
cursor = taskService.fetchFiltered(query, null, Task.TITLE, Task.DUE_DATE);
Task task = new Task();
for (int i = 0; i < cursor.getCount() && i < numberOfTasks; i++) {
cursor.moveToPosition(i);
task.readFromCursor(cursor);
String textContent = "";
int textColor = Color.WHITE;
textContent = task.getValue(Task.TITLE);
if(task.hasDueDate() && task.getValue(Task.DUE_DATE) < DateUtilities.now())
textColor = context.getResources().getColor(R.color.task_list_overdue);
if(i > 0)
views.setViewVisibility(separatorIDs[i-1], View.VISIBLE);
views.setTextViewText(textIDs[i], textContent);
views.setTextColor(textIDs[i], textColor);
}
for(int i = cursor.getCount() - 1; i < separatorIDs.length; i++) {
if(i >= 0)
views.setViewVisibility(separatorIDs[i], View.INVISIBLE);
if(i > cursor.getCount() - 1)
views.setViewVisibility(textIDs[i], View.INVISIBLE);
}
} catch (Exception e) {
// can happen if database is not ready
Log.e("WIDGET-UPDATE", "Error updating widget", e);
} finally {
if(cursor != null)
cursor.close();
}
Intent editIntent = new Intent(context, TaskEditActivity.class);
pendingIntent = PendingIntent.getActivity(context, 0,
editIntent, 0);
views.setOnClickPendingIntent(R.id.widget_button, pendingIntent);
return views;
}
}
}

Loading…
Cancel
Save