added border to user type icon

redesigning settings screen
removed staggered grid support, will use new implementation soon
redesigning direct message entries list
This commit is contained in:
Mariotaku Lee 2014-12-04 22:31:29 +08:00
parent 4cc47a3af1
commit 00c0740d38
143 changed files with 3142 additions and 4608 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -83,7 +83,6 @@ dependencies {
compile 'com.android.support:cardview-v7:21.0.2'
compile 'com.android.support:recyclerview-v7:21.0.2'
compile 'com.android.support:palette-v7:21.0.2'
compile 'com.etsy.android.grid:library:1.0.5'
compile 'com.sothree.slidinguppanel:library:2.0.0'
compile 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5'
compile 'com.twitter:twitter-text:1.9.9'

View File

@ -1,11 +1,11 @@
/**
* This is free and unencumbered software released into the public domain.
*
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
@ -21,7 +21,7 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
* For more information, please refer to <http://unlicense.org/>
*/
@ -29,19 +29,19 @@ package org.mariotaku.querybuilder;
public class AllColumns implements Selectable {
private final String table;
private final String table;
public AllColumns() {
this(null);
}
public AllColumns() {
this(null);
}
public AllColumns(final String table) {
this.table = table;
}
public AllColumns(final String table) {
this.table = table;
}
@Override
public String getSQL() {
return table != null ? table + ".*" : "*";
}
@Override
public String getSQL() {
return table != null ? table + ".*" : "*";
}
}

View File

@ -1,11 +1,11 @@
/**
* This is free and unencumbered software released into the public domain.
*
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
@ -21,7 +21,7 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
* For more information, please refer to <http://unlicense.org/>
*/
@ -29,64 +29,81 @@ package org.mariotaku.querybuilder;
public class Columns implements Selectable {
private final AbsColumn[] columns;
private final AbsColumn[] columns;
public Columns(final AbsColumn... columns) {
this.columns = columns;
}
public Columns(String... columns) {
this(Columns.fromStrings(columns));
}
@Override
public String getSQL() {
return Utils.toString(columns);
}
public Columns(final AbsColumn... columns) {
this.columns = columns;
}
public abstract static class AbsColumn implements Selectable {
private static Column[] fromStrings(String... columnsString) {
final Column[] columns = new Column[columnsString.length];
for (int i = 0, j = columnsString.length; i < j; i++) {
columns[i] = new Column(columnsString[i]);
}
return columns;
}
}
@Override
public String getSQL() {
return Utils.toString(columns, ',', true);
}
public static class AllColumn extends AbsColumn {
public abstract static class AbsColumn implements Selectable {
private final String table;
}
public AllColumn() {
this(null);
}
public static class AllColumn extends AbsColumn {
public AllColumn(final String table) {
this.table = table;
}
private final Table table;
@Override
public String getSQL() {
return table != null ? table + ".*" : "*";
}
public AllColumn() {
this(null);
}
}
public AllColumn(final Table table) {
this.table = table;
}
public static class Column extends AbsColumn {
@Override
public String getSQL() {
return table != null ? table.getSQL() + ".*" : "*";
}
private final String table, columnName, alias;
}
public Column(final String columnName) {
this(null, columnName, null);
}
public static class Column extends AbsColumn {
public Column(final String columnName, final String alias) {
this(null, columnName, alias);
}
private final Table table;
private final String columnName, alias;
public Column(final String table, final String columnName, final String alias) {
if (columnName == null) throw new IllegalArgumentException("");
this.table = table;
this.columnName = columnName;
this.alias = alias;
}
public Column(final String columnName) {
this(null, columnName, null);
}
@Override
public String getSQL() {
final String col = table != null ? table + "." + columnName : columnName;
return alias != null ? col + " AS " + alias : col;
}
}
public Column(final String columnName, final String alias) {
this(null, columnName, alias);
}
public Column(final Table table, final String columnName) {
this(table, columnName, null);
}
public Column(final Table table, final String columnName, final String alias) {
if (columnName == null) throw new IllegalArgumentException("");
this.table = table;
this.columnName = columnName;
this.alias = alias;
}
@Override
public String getSQL() {
final String col = table != null ? table.getSQL() + "." + columnName : columnName;
return alias != null ? col + " AS " + alias : col;
}
}
}

View File

@ -0,0 +1,124 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
import org.mariotaku.querybuilder.Columns.Column;
import java.util.Locale;
public class Expression implements SQLLang {
private final String expr;
public Expression(final String expr) {
this.expr = expr;
}
public Expression(SQLLang lang) {
this(lang.getSQL());
}
public static Expression and(final Expression... expressions) {
return new Expression(toExpr(expressions, "AND"));
}
public static Expression equals(final Column l, final Column r) {
return new Expression(String.format(Locale.US, "%s = %s", l.getSQL(), r.getSQL()));
}
public static Expression equals(final Column l, final long r) {
return new Expression(String.format(Locale.US, "%s = %d", l.getSQL(), r));
}
public static Expression equals(final Column l, final String r) {
return new Expression(String.format(Locale.US, "%s = '%s'", l.getSQL(), r));
}
public static Expression equals(final String l, final long r) {
return new Expression(String.format(Locale.US, "%s = %d", l, r));
}
public static Expression in(final Column column, final Selectable in) {
return new Expression(String.format("%s IN(%s)", column.getSQL(), in.getSQL()));
}
public static Expression notEquals(final String l, final long r) {
return new Expression(String.format(Locale.US, "%s != %d", l, r));
}
public static Expression notEquals(final String l, final String r) {
return new Expression(String.format("%s != %s", l, r));
}
public static Expression notIn(final Column column, final Selectable in) {
return new Expression(String.format("%s NOT IN(%s)", column.getSQL(), in.getSQL()));
}
public static Expression notNull(final Column column) {
return new Expression(String.format("%s NOT NULL", column.getSQL()));
}
public static Expression or(final Expression... expressions) {
return new Expression(toExpr(expressions, "OR"));
}
private static String toExpr(final Expression[] array, final String token) {
final StringBuilder builder = new StringBuilder();
builder.append('(');
final int length = array.length;
for (int i = 0; i < length; i++) {
if (i > 0) {
builder.append(String.format(" %s ", token));
}
builder.append(array[i].getSQL());
}
builder.append(')');
return builder.toString();
}
public static Expression equalsArgs(String l) {
return new Expression(String.format(Locale.US, "%s = ?", l));
}
public static Expression isNull(Column column) {
return new Expression(String.format(Locale.ROOT, "%s IS NULL", column.getSQL()));
}
public static Expression greaterThan(Column column1, Column column2) {
return new Expression(String.format(Locale.ROOT, "%s > %s", column1.getSQL(), column2.getSQL()));
}
public static Expression like(final Column l, final String r) {
return new Expression(String.format(Locale.US, "%s LIKE '%s'", l.getSQL(), r));
}
@Override
public String getSQL() {
return expr;
}
}

View File

@ -2,36 +2,37 @@ package org.mariotaku.querybuilder;
public class NewColumn implements SQLLang {
private final String name;
private final String type;
private final String name;
private final String type;
public NewColumn(final String name, final String type) {
this.name = name;
this.type = type;
}
public NewColumn(final String name, final String type) {
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public static NewColumn[] createNewColumns(final String[] colNames, final String[] colTypes) {
if (colNames == null || colTypes == null || colNames.length != colTypes.length)
throw new IllegalArgumentException("length of columns and types not match.");
final NewColumn[] newColumns = new NewColumn[colNames.length];
for (int i = 0, j = colNames.length; i < j; i++) {
newColumns[i] = new NewColumn(colNames[i], colTypes[i]);
}
return newColumns;
}
@Override
public String getSQL() {
if (name == null || type == null) throw new NullPointerException("name and type must not be null!");
return String.format("%s %s", name, type);
}
public String getName() {
return name;
}
public String getType() {
return type;
}
@Override
public String getSQL() {
if (name == null || type == null)
throw new NullPointerException("name and type must not be null!");
return String.format("%s %s", name, type);
}
public static NewColumn[] createNewColumns(final String[] colNames, final String[] colTypes) {
if (colNames == null || colTypes == null || colNames.length != colTypes.length)
throw new IllegalArgumentException("length of columns and types not match.");
final NewColumn[] newColumns = new NewColumn[colNames.length];
for (int i = 0, j = colNames.length; i < j; i++) {
newColumns[i] = new NewColumn(colNames[i], colTypes[i]);
}
return newColumns;
}
public String getType() {
return type;
}
}

View File

@ -0,0 +1,17 @@
package org.mariotaku.querybuilder;
/**
* Created by mariotaku on 14-8-7.
*/
public enum OnConflict {
ROLLBACK("ROLLBACK"), ABORT("ABORT"), REPLACE("REPLACE"), FAIL("FAIL"), IGNORE("IGNORE");
private final String action;
OnConflict(final String action) {
this.action = action;
}
public String getAction() {
return action;
}
}

View File

@ -1,11 +1,11 @@
/**
* This is free and unencumbered software released into the public domain.
*
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
@ -21,25 +21,26 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
import org.mariotaku.twidere.util.ArrayUtils;
public class OrderBy implements SQLLang {
private final String[] orderBy;
private final String[] orderBy;
public OrderBy(final String... orderBy) {
this.orderBy = orderBy;
}
public OrderBy(final String... orderBy) {
this.orderBy = orderBy;
}
@Override
public String getSQL() {
return ArrayUtils.toString(orderBy, ',', false);
}
@Override
public String getSQL() {
return ArrayUtils.toString(orderBy, ',', false);
}
}

View File

@ -2,23 +2,23 @@ package org.mariotaku.querybuilder;
public class RawItemArray implements Selectable {
private final Object[] array;
private final Object[] array;
public RawItemArray(final long[] array) {
final Long[] converted = new Long[array.length];
for (int i = 0, j = array.length; i < j; i++) {
converted[i] = array[i];
}
this.array = converted;
}
public RawItemArray(final long[] array) {
final Long[] converted = new Long[array.length];
for (int i = 0, j = array.length; i < j; i++) {
converted[i] = array[i];
}
this.array = converted;
}
public RawItemArray(final Object[] array) {
this.array = array;
}
public RawItemArray(final String[] array) {
this.array = array;
}
@Override
public String getSQL() {
return Utils.toString(array, ',', false);
}
@Override
public String getSQL() {
return Utils.toString(array, ',', false);
}
}

View File

@ -2,8 +2,12 @@ package org.mariotaku.querybuilder;
public class SQLFunctions {
public static String SUM(final String val) {
return String.format("SUM (%s)", val);
}
public static String SUM(final String val) {
return String.format("SUM (%s)", val);
}
public static String COUNT(final String val) {
return String.format("COUNT (%s)", val);
}
}

View File

@ -1,11 +1,11 @@
/**
* This is free and unencumbered software released into the public domain.
*
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
@ -21,7 +21,7 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
* For more information, please refer to <http://unlicense.org/>
*/
@ -29,10 +29,10 @@ package org.mariotaku.querybuilder;
public interface SQLLang extends Cloneable {
/**
* Build SQL query string
*
* @return SQL query
*/
public String getSQL();
/**
* Build SQL query string
*
* @return SQL query
*/
public String getSQL();
}

View File

@ -0,0 +1,7 @@
package org.mariotaku.querybuilder;
/**
* Created by mariotaku on 14-8-6.
*/
public interface SQLQuery extends SQLLang {
}

View File

@ -1,11 +1,11 @@
/**
* This is free and unencumbered software released into the public domain.
*
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
@ -21,7 +21,7 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
* For more information, please refer to <http://unlicense.org/>
*/
@ -29,70 +29,81 @@ package org.mariotaku.querybuilder;
import org.mariotaku.querybuilder.query.SQLAlterTableQuery;
import org.mariotaku.querybuilder.query.SQLCreateTableQuery;
import org.mariotaku.querybuilder.query.SQLCreateTriggerQuery;
import org.mariotaku.querybuilder.query.SQLCreateViewQuery;
import org.mariotaku.querybuilder.query.SQLDropTableQuery;
import org.mariotaku.querybuilder.query.SQLDropTriggerQuery;
import org.mariotaku.querybuilder.query.SQLDropViewQuery;
import org.mariotaku.querybuilder.query.SQLInsertIntoQuery;
import org.mariotaku.querybuilder.query.SQLInsertIntoQuery.OnConflict;
import org.mariotaku.querybuilder.query.SQLInsertQuery;
import org.mariotaku.querybuilder.query.SQLSelectQuery;
public class SQLQueryBuilder {
private SQLQueryBuilder() {
throw new AssertionError("You can't create instance for this class");
}
private SQLQueryBuilder() {
throw new AssertionError("You can't create instance for this class");
}
public static SQLAlterTableQuery.Builder alterTable(final String table) {
return new SQLAlterTableQuery.Builder().alterTable(table);
}
public static SQLAlterTableQuery.Builder alterTable(final String table) {
return new SQLAlterTableQuery.Builder().alterTable(table);
}
public static SQLCreateTableQuery.Builder createTable(final boolean temporary, final boolean createIfNotExists,
final String name) {
return new SQLCreateTableQuery.Builder().createTable(temporary, createIfNotExists, name);
}
public static SQLCreateTableQuery.Builder createTable(final boolean temporary, final boolean createIfNotExists,
final String name) {
return new SQLCreateTableQuery.Builder().createTable(temporary, createIfNotExists, name);
}
public static SQLCreateTableQuery.Builder createTable(final boolean createIfNotExists, final String name) {
return createTable(false, createIfNotExists, name);
}
public static SQLCreateTableQuery.Builder createTable(final boolean createIfNotExists, final String name) {
return createTable(false, createIfNotExists, name);
}
public static SQLCreateTableQuery.Builder createTable(final String name) {
return createTable(false, false, name);
}
public static SQLCreateTableQuery.Builder createTable(final String name) {
return createTable(false, false, name);
}
public static SQLCreateViewQuery.Builder createView(final boolean temporary, final boolean createIfNotExists,
final String name) {
return new SQLCreateViewQuery.Builder().createView(temporary, createIfNotExists, name);
}
public static SQLCreateViewQuery.Builder createView(final boolean temporary, final boolean createIfNotExists,
final String name) {
return new SQLCreateViewQuery.Builder().createView(temporary, createIfNotExists, name);
}
public static SQLCreateViewQuery.Builder createView(final boolean createIfNotExists, final String name) {
return createView(false, createIfNotExists, name);
}
public static SQLCreateViewQuery.Builder createView(final String name) {
return createView(false, false, name);
}
public static SQLCreateTriggerQuery.Builder createTrigger(final boolean temporary, final boolean createIfNotExists,
final String name) {
return new SQLCreateTriggerQuery.Builder().createTrigger(temporary, createIfNotExists, name);
}
public static SQLDropTableQuery dropTable(final boolean dropIfExists, final String table) {
return new SQLDropTableQuery(dropIfExists, table);
}
public static SQLCreateViewQuery.Builder createView(final boolean createIfNotExists, final String name) {
return createView(false, createIfNotExists, name);
}
public static SQLDropViewQuery dropView(final boolean dropIfExists, final String table) {
return new SQLDropViewQuery(dropIfExists, table);
}
public static SQLCreateViewQuery.Builder createView(final String name) {
return createView(false, false, name);
}
public static SQLInsertIntoQuery.Builder insertInto(final OnConflict onConflict, final String table) {
return new SQLInsertIntoQuery.Builder().insertInto(onConflict, table);
}
public static SQLDropTableQuery dropTable(final boolean dropIfExists, final String table) {
return new SQLDropTableQuery(dropIfExists, table);
}
public static SQLInsertIntoQuery.Builder insertInto(final String table) {
return insertInto(null, table);
}
public static SQLDropViewQuery dropView(final boolean dropIfExists, final String table) {
return new SQLDropViewQuery(dropIfExists, table);
}
public static SQLSelectQuery.Builder select(final boolean distinct, final Selectable select) {
return new SQLSelectQuery.Builder().select(distinct, select);
}
public static SQLDropTriggerQuery dropTrigger(final boolean dropIfExists, final String table) {
return new SQLDropTriggerQuery(dropIfExists, table);
}
public static SQLSelectQuery.Builder select(final Selectable select) {
return select(false, select);
}
public static SQLInsertQuery.Builder insertInto(final OnConflict onConflict, final String table) {
return new SQLInsertQuery.Builder().insertInto(onConflict, table);
}
public static SQLInsertQuery.Builder insertInto(final String table) {
return insertInto(null, table);
}
public static SQLSelectQuery.Builder select(final boolean distinct, final Selectable select) {
return new SQLSelectQuery.Builder().select(distinct, select);
}
public static SQLSelectQuery.Builder select(final Selectable select) {
return select(false, select);
}
}

View File

@ -1,11 +1,11 @@
/**
* This is free and unencumbered software released into the public domain.
*
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
@ -21,7 +21,7 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
* For more information, please refer to <http://unlicense.org/>
*/
@ -29,21 +29,21 @@ package org.mariotaku.querybuilder;
public class SQLQueryException extends RuntimeException {
private static final long serialVersionUID = 910158450604676104L;
private static final long serialVersionUID = 910158450604676104L;
public SQLQueryException() {
}
public SQLQueryException() {
}
public SQLQueryException(final String detailMessage) {
super(detailMessage);
}
public SQLQueryException(final String detailMessage) {
super(detailMessage);
}
public SQLQueryException(final String detailMessage, final Throwable throwable) {
super(detailMessage, throwable);
}
public SQLQueryException(final String detailMessage, final Throwable throwable) {
super(detailMessage, throwable);
}
public SQLQueryException(final Throwable throwable) {
super(throwable);
}
public SQLQueryException(final Throwable throwable) {
super(throwable);
}
}

View File

@ -1,11 +1,11 @@
/**
* This is free and unencumbered software released into the public domain.
*
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
@ -21,7 +21,7 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
* For more information, please refer to <http://unlicense.org/>
*/

View File

@ -0,0 +1,23 @@
package org.mariotaku.querybuilder;
import java.util.Locale;
/**
* Created by mariotaku on 14-8-7.
*/
public class SetValue implements SQLLang {
private final Columns.Column column;
private final Expression expression;
public SetValue(Columns.Column column, Expression expression) {
this.column = column;
this.expression = expression;
}
@Override
public String getSQL() {
return String.format(Locale.ROOT, "%s = %s", column.getSQL(), expression.getSQL());
}
}

View File

@ -0,0 +1,45 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public class Table implements Selectable {
public static final Table NEW = new Table("NEW");
private final String table;
public Table(final String table) {
this.table = table;
}
@Override
public String getSQL() {
return table;
}
}

View File

@ -1,11 +1,11 @@
/**
* This is free and unencumbered software released into the public domain.
*
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
@ -21,23 +21,24 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public class Tables implements Selectable {
public class Tables extends Table {
private final String[] tables;
private final String[] tables;
public Tables(final String... tables) {
this.tables = tables;
}
public Tables(final String... tables) {
super(null);
this.tables = tables;
}
@Override
public String getSQL() {
return Utils.toString(tables, ',', false);
}
@Override
public String getSQL() {
return Utils.toString(tables, ',', false);
}
}

View File

@ -1,11 +1,11 @@
/**
* This is free and unencumbered software released into the public domain.
*
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
@ -21,7 +21,7 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
* For more information, please refer to <http://unlicense.org/>
*/
@ -29,34 +29,25 @@ package org.mariotaku.querybuilder;
public class Utils {
public static String toString(final Object[] array, final char token, final boolean include_space) {
final StringBuilder builder = new StringBuilder();
final int length = array.length;
for (int i = 0; i < length; i++) {
final String id_string = String.valueOf(array[i]);
if (id_string != null) {
if (i > 0) {
builder.append(include_space ? token + " " : token);
}
builder.append(id_string);
}
}
return builder.toString();
}
public static String toString(final Object[] array, final char token, final boolean includeSpace) {
final StringBuilder builder = new StringBuilder();
final int length = array.length;
for (int i = 0; i < length; i++) {
final String string = objectToString(array[i]);
if (string != null) {
if (i > 0) {
builder.append(includeSpace ? token + " " : token);
}
builder.append(string);
}
}
return builder.toString();
}
public static String toString(final SQLLang[] array) {
final StringBuilder builder = new StringBuilder();
final int length = array.length;
for (int i = 0; i < length; i++) {
final String id_string = array[i].getSQL();
if (id_string != null) {
if (i > 0) {
builder.append(", ");
}
builder.append(id_string);
}
}
return builder.toString();
}
private static String objectToString(Object o) {
if (o instanceof SQLLang)
return ((SQLLang) o).getSQL();
return o != null ? o.toString() : null;
}
}

View File

@ -1,103 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
import org.mariotaku.querybuilder.Columns.Column;
import java.util.Locale;
public class Where implements SQLLang {
private final String expr;
public Where(final String expr) {
this.expr = expr;
}
@Override
public String getSQL() {
return expr;
}
public static Where and(final Where... expressions) {
return new Where(toExpr(expressions, "AND"));
}
public static Where equals(final Column l, final Column r) {
return new Where(String.format(Locale.ROOT, "%s = %s", l.getSQL(), r.getSQL()));
}
public static Where equals(final Column l, final long r) {
return new Where(String.format(Locale.ROOT, "%s = %d", l.getSQL(), r));
}
public static Where equals(final Column l, final String r) {
return new Where(String.format(Locale.ROOT, "%s = '%s'", l.getSQL(), r));
}
public static Where equals(final String l, final long r) {
return new Where(String.format(Locale.ROOT, "%s = %d", l, r));
}
public static Where in(final Column column, final Selectable in) {
return new Where(String.format("%s IN(%s)", column.getSQL(), in.getSQL()));
}
public static Where notEquals(final String l, final long r) {
return new Where(String.format(Locale.ROOT, "%s != %d", l, r));
}
public static Where notEquals(final String l, final String r) {
return new Where(String.format("%s != %s", l, r));
}
public static Where notIn(final Column column, final Selectable in) {
return new Where(String.format("%s NOT IN(%s)", column.getSQL(), in.getSQL()));
}
public static Where notNull(final Column column) {
return new Where(String.format("%s NOT NULL", column.getSQL()));
}
public static Where or(final Where... expressions) {
return new Where(toExpr(expressions, "OR"));
}
private static String toExpr(final Where[] array, final String token) {
final StringBuilder builder = new StringBuilder();
builder.append('(');
final int length = array.length;
for (int i = 0; i < length; i++) {
if (i > 0) {
builder.append(String.format(" %s ", token));
}
builder.append(array[i].getSQL());
}
builder.append(')');
return builder.toString();
}
}

View File

@ -4,13 +4,13 @@ import org.mariotaku.querybuilder.SQLLang;
public interface IBuilder<T extends SQLLang> {
public T build();
public T build();
/**
* Equivalent to {@link #build()}.{@link #SQLLang.getSQL()}
*
* @return
*/
public String buildSQL();
/**
* Equivalent to {@link #build()}.{@link SQLLang#getSQL()}
*
* @return
*/
public String buildSQL();
}

View File

@ -1,71 +1,70 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.NewColumn;
import org.mariotaku.querybuilder.SQLLang;
import org.mariotaku.querybuilder.SQLQuery;
public class SQLAlterTableQuery implements SQLLang {
public class SQLAlterTableQuery implements SQLQuery {
private String table;
private String renameTo;
private NewColumn addColumn;
private String table;
private String renameTo;
private NewColumn addColumn;
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("table must not be null!");
if (renameTo == null && addColumn == null) throw new NullPointerException();
if (renameTo != null) return String.format("ALTER TABLE %s RENAME TO %s", table, renameTo);
return String.format("ALTER TABLE %s ADD COLUMN %s", table, addColumn.getSQL());
}
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("table must not be null!");
if (renameTo == null && addColumn == null) throw new NullPointerException();
if (renameTo != null) return String.format("ALTER TABLE %s RENAME TO %s", table, renameTo);
return String.format("ALTER TABLE %s ADD COLUMN %s", table, addColumn.getSQL());
}
void setAddColumn(final NewColumn addColumn) {
this.addColumn = addColumn;
}
void setAddColumn(final NewColumn addColumn) {
this.addColumn = addColumn;
}
void setRenameTo(final String renameTo) {
this.renameTo = renameTo;
}
void setRenameTo(final String renameTo) {
this.renameTo = renameTo;
}
void setTable(final String table) {
this.table = table;
}
void setTable(final String table) {
this.table = table;
}
public static final class Builder implements IBuilder<SQLAlterTableQuery> {
public static final class Builder implements IBuilder<SQLAlterTableQuery> {
private boolean buildCalled;
private final SQLAlterTableQuery query = new SQLAlterTableQuery();
private boolean buildCalled;
private final SQLAlterTableQuery query = new SQLAlterTableQuery();
public Builder addColumn(final NewColumn addColumn) {
checkNotBuilt();
query.setAddColumn(addColumn);
return this;
}
public Builder addColumn(final NewColumn addColumn) {
checkNotBuilt();
query.setAddColumn(addColumn);
return this;
}
public Builder alterTable(final String table) {
checkNotBuilt();
query.setTable(table);
return this;
}
public Builder alterTable(final String table) {
checkNotBuilt();
query.setTable(table);
return this;
}
@Override
public SQLAlterTableQuery build() {
return query;
}
@Override
public SQLAlterTableQuery build() {
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder renameTo(final String renameTo) {
checkNotBuilt();
query.setRenameTo(renameTo);
return this;
}
public Builder renameTo(final String renameTo) {
checkNotBuilt();
query.setRenameTo(renameTo);
return this;
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -1,111 +1,111 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.NewColumn;
import org.mariotaku.querybuilder.SQLLang;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.Utils;
public class SQLCreateTableQuery implements SQLLang {
public class SQLCreateTableQuery implements SQLQuery {
private boolean temporary;
private boolean createIfNotExists;
private String table;
private NewColumn[] newColumns;
private SQLSelectQuery selectStmt;
private boolean temporary;
private boolean createIfNotExists;
private String table;
private NewColumn[] newColumns;
private SQLSelectQuery selectStmt;
SQLCreateTableQuery() {
}
SQLCreateTableQuery() {
}
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("NAME must not be null!");
if ((newColumns == null || newColumns.length == 0) && selectStmt == null)
throw new NullPointerException("Columns or AS must not be null!");
final StringBuilder sb = new StringBuilder("CREATE ");
if (temporary) {
sb.append("TEMPORARY ");
}
sb.append("TABLE ");
if (createIfNotExists) {
sb.append("IF NOT EXISTS ");
}
sb.append(String.format("%s ", table));
if (newColumns != null && newColumns.length > 0) {
sb.append(String.format("(%s)", Utils.toString(newColumns)));
} else {
sb.append(String.format("AS %s", selectStmt.getSQL()));
}
return sb.toString();
}
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("NAME must not be null!");
if ((newColumns == null || newColumns.length == 0) && selectStmt == null)
throw new NullPointerException("Columns or AS must not be null!");
final StringBuilder sb = new StringBuilder("CREATE ");
if (temporary) {
sb.append("TEMPORARY ");
}
sb.append("TABLE ");
if (createIfNotExists) {
sb.append("IF NOT EXISTS ");
}
sb.append(String.format("%s ", table));
if (newColumns != null && newColumns.length > 0) {
sb.append(String.format("(%s)", Utils.toString(newColumns, ',', true)));
} else {
sb.append(String.format("AS %s", selectStmt.getSQL()));
}
return sb.toString();
}
void setAs(final SQLSelectQuery selectStmt) {
this.selectStmt = selectStmt;
}
void setAs(final SQLSelectQuery selectStmt) {
this.selectStmt = selectStmt;
}
void setCreateIfNotExists(final boolean createIfNotExists) {
this.createIfNotExists = createIfNotExists;
}
void setCreateIfNotExists(final boolean createIfNotExists) {
this.createIfNotExists = createIfNotExists;
}
void setNewColumns(final NewColumn[] newColumns) {
this.newColumns = newColumns;
}
void setNewColumns(final NewColumn[] newColumns) {
this.newColumns = newColumns;
}
void setTable(final String table) {
this.table = table;
}
void setTable(final String table) {
this.table = table;
}
void setTemporary(final boolean temporary) {
this.temporary = temporary;
}
void setTemporary(final boolean temporary) {
this.temporary = temporary;
}
public static final class Builder implements IBuilder<SQLCreateTableQuery> {
public static final class Builder implements IBuilder<SQLCreateTableQuery> {
private final SQLCreateTableQuery query = new SQLCreateTableQuery();
private final SQLCreateTableQuery query = new SQLCreateTableQuery();
private boolean buildCalled;
private boolean buildCalled;
public Builder as(final SQLSelectQuery selectStmt) {
checkNotBuilt();
query.setAs(selectStmt);
return this;
}
public Builder as(final SQLSelectQuery selectStmt) {
checkNotBuilt();
query.setAs(selectStmt);
return this;
}
@Override
public SQLCreateTableQuery build() {
buildCalled = true;
return query;
}
@Override
public SQLCreateTableQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder columns(final NewColumn... newColumns) {
checkNotBuilt();
query.setNewColumns(newColumns);
return this;
}
public Builder columns(final NewColumn... newColumns) {
checkNotBuilt();
query.setNewColumns(newColumns);
return this;
}
public Builder createTable(final boolean temporary, final boolean createIfNotExists, final String table) {
checkNotBuilt();
query.setTemporary(temporary);
query.setCreateIfNotExists(createIfNotExists);
query.setTable(table);
return this;
}
public Builder createTable(final boolean temporary, final boolean createIfNotExists, final String table) {
checkNotBuilt();
query.setTemporary(temporary);
query.setCreateIfNotExists(createIfNotExists);
query.setTable(table);
return this;
}
public Builder createTable(final boolean createIfNotExists, final String table) {
return createTable(false, createIfNotExists, table);
}
public Builder createTable(final boolean createIfNotExists, final String table) {
return createTable(false, createIfNotExists, table);
}
public Builder createTemporaryTable(final boolean createIfNotExists, final String table) {
return createTable(true, createIfNotExists, table);
}
public Builder createTemporaryTable(final boolean createIfNotExists, final String table) {
return createTable(true, createIfNotExists, table);
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}
}

View File

@ -0,0 +1,201 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.Columns;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.SQLLang;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.Table;
import org.mariotaku.querybuilder.Utils;
import java.util.Locale;
/**
* Created by mariotaku on 14-8-6.
*/
public class SQLCreateTriggerQuery implements SQLQuery {
private boolean temporary;
private boolean createIfNotExists;
private boolean forEachRow;
private String name;
private Table on;
private Type type;
private Event event;
private Columns updateOf;
private SQLQuery[] actions;
private Expression when;
void setActions(SQLQuery[] actions) {
this.actions = actions;
}
void setForEachRow(boolean forEachRow) {
this.forEachRow = forEachRow;
}
void setOn(Table on) {
this.on = on;
}
void setUpdateOf(Columns updateOf) {
this.updateOf = updateOf;
}
void setType(Type type) {
this.type = type;
}
void setEvent(Event event) {
this.event = event;
}
void setWhen(Expression when) {
this.when = when;
}
@Override
public String getSQL() {
if (name == null) throw new NullPointerException("NAME must not be null!");
if (event == null) throw new NullPointerException("EVENT must not be null!");
if (on == null) throw new NullPointerException("ON must not be null!");
if (actions == null) throw new NullPointerException("ACTIONS must not be null!");
final StringBuilder sb = new StringBuilder("CREATE ");
if (temporary) {
sb.append("TEMPORARY ");
}
sb.append("TRIGGER ");
if (createIfNotExists) {
sb.append("IF NOT EXISTS ");
}
sb.append(name);
sb.append(' ');
if (type != null) {
sb.append(type.getSQL());
sb.append(' ');
}
sb.append(event.getSQL());
sb.append(' ');
if (event == Event.UPDATE) {
sb.append(String.format(Locale.ROOT, "%s ", updateOf.getSQL()));
}
sb.append(String.format(Locale.ROOT, "ON %s ", on.getSQL()));
if (forEachRow) {
sb.append("FOR EACH ROW ");
}
if (when != null) {
sb.append(String.format(Locale.ROOT, "WHEN %s ", when.getSQL()));
}
sb.append(String.format(Locale.ROOT, "BEGIN %s; END", Utils.toString(actions, ';', true)));
return sb.toString();
}
void setCreateIfNotExists(final boolean createIfNotExists) {
this.createIfNotExists = createIfNotExists;
}
void setName(final String name) {
this.name = name;
}
void setTemporary(final boolean temporary) {
this.temporary = temporary;
}
public static enum Type implements SQLLang {
BEFORE("BEFORE"), AFTER("AFTER"), INSTEAD_OF("INSTEAD OF");
private final String lang;
Type(String lang) {
this.lang = lang;
}
@Override
public String getSQL() {
return lang;
}
}
public static enum Event implements SQLLang {
INSERT("INSERT"), DELETE("DELETE"), UPDATE("UPDATE");
private final String lang;
Event(String lang) {
this.lang = lang;
}
@Override
public String getSQL() {
return lang;
}
}
public static class Builder implements IBuilder<SQLCreateTriggerQuery> {
private final SQLCreateTriggerQuery query = new SQLCreateTriggerQuery();
private boolean buildCalled;
public Builder forEachRow(final boolean forEachRow) {
checkNotBuilt();
query.setForEachRow(forEachRow);
return this;
}
public Builder on(final Table on) {
checkNotBuilt();
query.setOn(on);
return this;
}
public Builder event(Event event) {
checkNotBuilt();
query.setEvent(event);
return this;
}
public Builder type(Type type) {
checkNotBuilt();
query.setType(type);
return this;
}
public Builder updateOf(Columns updateOf) {
checkNotBuilt();
query.setUpdateOf(updateOf);
return this;
}
public Builder actions(SQLQuery... actions) {
checkNotBuilt();
query.setActions(actions);
return this;
}
public Builder when(Expression when) {
checkNotBuilt();
query.setWhen(when);
return this;
}
@Override
public SQLCreateTriggerQuery build() {
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
public Builder createTrigger(boolean temporary, boolean createIfNotExists, String name) {
checkNotBuilt();
query.setTemporary(temporary);
query.setCreateIfNotExists(createIfNotExists);
query.setName(name);
return this;
}
}
}

View File

@ -1,90 +1,90 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.SQLLang;
import org.mariotaku.querybuilder.SQLQuery;
public class SQLCreateViewQuery implements SQLLang {
public class SQLCreateViewQuery implements SQLQuery {
private boolean temporary;
private boolean createIfNotExists;
private String name;
private SQLSelectQuery selectStmt;
private boolean temporary;
private boolean createIfNotExists;
private String name;
private SQLSelectQuery selectStmt;
SQLCreateViewQuery() {
SQLCreateViewQuery() {
}
}
@Override
public String getSQL() {
if (name == null) throw new NullPointerException("NAME must not be null!");
if (selectStmt == null) throw new NullPointerException("SELECT statement must not be null!");
final StringBuilder sb = new StringBuilder("CREATE ");
if (temporary) {
sb.append("TEMPORARY ");
}
sb.append("VIEW ");
if (createIfNotExists) {
sb.append("IF NOT EXISTS ");
}
sb.append(String.format("%s AS %s", name, selectStmt.getSQL()));
return sb.toString();
}
@Override
public String getSQL() {
if (name == null) throw new NullPointerException("NAME must not be null!");
if (selectStmt == null)
throw new NullPointerException("SELECT statement must not be null!");
final StringBuilder sb = new StringBuilder("CREATE ");
if (temporary) {
sb.append("TEMPORARY ");
}
sb.append("VIEW ");
if (createIfNotExists) {
sb.append("IF NOT EXISTS ");
}
sb.append(String.format("%s AS %s", name, selectStmt.getSQL()));
return sb.toString();
}
void setAs(final SQLSelectQuery selectStmt) {
this.selectStmt = selectStmt;
}
void setAs(final SQLSelectQuery selectStmt) {
this.selectStmt = selectStmt;
}
void setCreateIfNotExists(final boolean createIfNotExists) {
this.createIfNotExists = createIfNotExists;
}
void setCreateIfNotExists(final boolean createIfNotExists) {
this.createIfNotExists = createIfNotExists;
}
void setName(final String name) {
this.name = name;
}
void setName(final String name) {
this.name = name;
}
void setTemporary(final boolean temporary) {
this.temporary = temporary;
}
void setTemporary(final boolean temporary) {
this.temporary = temporary;
}
public static final class Builder implements IBuilder<SQLCreateViewQuery> {
public static final class Builder implements IBuilder<SQLCreateViewQuery> {
private boolean buildCalled;
private final SQLCreateViewQuery query = new SQLCreateViewQuery();
private boolean buildCalled;
private final SQLCreateViewQuery query = new SQLCreateViewQuery();
public Builder as(final SQLSelectQuery selectStmt) {
checkNotBuilt();
query.setAs(selectStmt);
return this;
}
public Builder as(final SQLSelectQuery selectStmt) {
checkNotBuilt();
query.setAs(selectStmt);
return this;
}
@Override
public SQLCreateViewQuery build() {
return query;
}
@Override
public SQLCreateViewQuery build() {
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder createTemporaryView(final boolean createIfNotExists, final String name) {
return createView(true, createIfNotExists, name);
}
public Builder createTemporaryView(final boolean createIfNotExists, final String name) {
return createView(true, createIfNotExists, name);
}
public Builder createView(final boolean temporary, final boolean createIfNotExists, final String name) {
checkNotBuilt();
query.setTemporary(temporary);
query.setCreateIfNotExists(createIfNotExists);
query.setName(name);
return this;
}
public Builder createView(final boolean temporary, final boolean createIfNotExists, final String name) {
checkNotBuilt();
query.setTemporary(temporary);
query.setCreateIfNotExists(createIfNotExists);
query.setName(name);
return this;
}
public Builder createView(final boolean createIfNotExists, final String name) {
return createView(false, createIfNotExists, name);
}
public Builder createView(final boolean createIfNotExists, final String name) {
return createView(false, createIfNotExists, name);
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -1,57 +1,57 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.SQLLang;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.SQLQuery;
public class SQLDeleteQuery implements SQLLang {
public class SQLDeleteQuery implements SQLQuery {
private String table;
private Where where;
private String table;
private Expression where;
@Override
public String getSQL() {
if (where != null) return String.format("DELETE FROM %s", table);
return String.format("DELETE FROM %S WHERE %s", table, where.getSQL());
}
@Override
public String getSQL() {
if (where != null) return String.format("DELETE FROM %s", table);
return String.format("DELETE FROM %S WHERE %s", table, where.getSQL());
}
void setFrom(final String table) {
this.table = table;
}
void setFrom(final String table) {
this.table = table;
}
void setWhere(final Where where) {
this.where = where;
}
void setWhere(final Expression where) {
this.where = where;
}
public static final class Builder implements IBuilder<SQLDeleteQuery> {
private boolean buildCalled;
private final SQLDeleteQuery query = new SQLDeleteQuery();
public static final class Builder implements IBuilder<SQLDeleteQuery> {
private final SQLDeleteQuery query = new SQLDeleteQuery();
private boolean buildCalled;
@Override
public SQLDeleteQuery build() {
buildCalled = true;
return query;
}
@Override
public SQLDeleteQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder from(final String table) {
checkNotBuilt();
query.setFrom(table);
return this;
}
public Builder from(final String table) {
checkNotBuilt();
query.setFrom(table);
return this;
}
public Builder where(final Where where) {
checkNotBuilt();
query.setWhere(where);
return this;
}
public Builder where(final Expression where) {
checkNotBuilt();
query.setWhere(where);
return this;
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -1,19 +1,24 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.SQLLang;
import org.mariotaku.querybuilder.SQLQuery;
public class SQLDropQuery implements SQLLang {
public class SQLDropQuery implements SQLQuery {
private final String table;
private final boolean dropIfExists;
private final String type;
private final String target;
public SQLDropQuery(final String table) {
if (table == null) throw new NullPointerException();
this.table = table;
}
public SQLDropQuery(final boolean dropIfExists, final String type, final String target) {
if (target == null) throw new NullPointerException();
this.dropIfExists = dropIfExists;
this.type = type;
this.target = target;
}
@Override
public String getSQL() {
return String.format("DROP TABLE %s", table);
}
@Override
public final String getSQL() {
if (dropIfExists) return String.format("DROP %s IF EXISTS %s", type, target);
return String.format("DROP %s %s", type, target);
}
}

View File

@ -1,22 +1,9 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.SQLLang;
public class SQLDropTableQuery extends SQLDropQuery {
public class SQLDropTableQuery implements SQLLang {
private final boolean dropIfExists;
private final String table;
public SQLDropTableQuery(final boolean dropIfExists, final String table) {
if (table == null) throw new NullPointerException();
this.dropIfExists = dropIfExists;
this.table = table;
}
@Override
public String getSQL() {
if (dropIfExists) return String.format("DROP TABLE IF EXISTS %s", table);
return String.format("DROP TABLE %s", table);
}
public SQLDropTableQuery(final boolean dropIfExists, final String table) {
super(dropIfExists, "TABLE", table);
}
}

View File

@ -0,0 +1,9 @@
package org.mariotaku.querybuilder.query;
public class SQLDropTriggerQuery extends SQLDropQuery {
public SQLDropTriggerQuery(final boolean dropIfExists, final String table) {
super(dropIfExists, "TRIGGER", table);
}
}

View File

@ -1,22 +1,9 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.SQLLang;
public class SQLDropViewQuery extends SQLDropQuery {
public class SQLDropViewQuery implements SQLLang {
private final boolean dropIfExists;
private final String table;
public SQLDropViewQuery(final boolean dropIfExists, final String table) {
if (table == null) throw new NullPointerException();
this.dropIfExists = dropIfExists;
this.table = table;
}
@Override
public String getSQL() {
if (dropIfExists) return String.format("DROP VIEW IF EXISTS %s", table);
return String.format("DROP VIEW %s", table);
}
public SQLDropViewQuery(final boolean dropIfExists, final String table) {
super(dropIfExists, "VIEW", table);
}
}

View File

@ -1,106 +0,0 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.SQLLang;
import org.mariotaku.querybuilder.Utils;
public class SQLInsertIntoQuery implements SQLLang {
private OnConflict onConflict;
private String table;
private String[] columns;
private SQLSelectQuery select;
SQLInsertIntoQuery() {
}
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("table must not be null!");
final StringBuilder sb = new StringBuilder();
sb.append("INSERT ");
if (onConflict != null) {
sb.append(String.format("OR %s ", onConflict.getAction()));
}
sb.append(String.format("INTO %s ", table));
sb.append(String.format("(%s) ", Utils.toString(columns, ',', false)));
sb.append(String.format("%s ", select.getSQL()));
return sb.toString();
}
void setColumns(final String[] columns) {
this.columns = columns;
}
void setOnConflict(final OnConflict onConflict) {
this.onConflict = onConflict;
}
void setSelect(final SQLSelectQuery select) {
this.select = select;
}
void setTable(final String table) {
this.table = table;
}
public static final class Builder implements IBuilder<SQLInsertIntoQuery> {
private final SQLInsertIntoQuery query = new SQLInsertIntoQuery();
private boolean buildCalled;
@Override
public SQLInsertIntoQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder columns(final String[] columns) {
checkNotBuilt();
query.setColumns(columns);
return this;
}
public Builder insertInto(final OnConflict onConflict, final String table) {
checkNotBuilt();
query.setOnConflict(onConflict);
query.setTable(table);
return this;
}
public Builder insertInto(final String table) {
return insertInto(null, table);
}
public Builder select(final SQLSelectQuery select) {
checkNotBuilt();
query.setSelect(select);
return this;
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
public static enum OnConflict {
ROLLBACK("ROLLBACK"), ABORT("ABORT"), REPLACE("REPLACE"), FAIL("FAIL"), IGNORE("IGNORE");
private final String action;
private OnConflict(final String action) {
this.action = action;
}
public String getAction() {
return action;
}
}
}

View File

@ -0,0 +1,94 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.OnConflict;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.Utils;
public class SQLInsertQuery implements SQLQuery {
private OnConflict onConflict;
private String table;
private String[] columns;
private SQLSelectQuery select;
SQLInsertQuery() {
}
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("table must not be null!");
final StringBuilder sb = new StringBuilder();
sb.append("INSERT ");
if (onConflict != null) {
sb.append(String.format("OR %s ", onConflict.getAction()));
}
sb.append(String.format("INTO %s ", table));
sb.append(String.format("(%s) ", Utils.toString(columns, ',', false)));
sb.append(String.format("%s ", select.getSQL()));
return sb.toString();
}
void setColumns(final String[] columns) {
this.columns = columns;
}
void setOnConflict(final OnConflict onConflict) {
this.onConflict = onConflict;
}
void setSelect(final SQLSelectQuery select) {
this.select = select;
}
void setTable(final String table) {
this.table = table;
}
public static final class Builder implements IBuilder<SQLInsertQuery> {
private final SQLInsertQuery query = new SQLInsertQuery();
private boolean buildCalled;
@Override
public SQLInsertQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder columns(final String[] columns) {
checkNotBuilt();
query.setColumns(columns);
return this;
}
public Builder insertInto(final OnConflict onConflict, final String table) {
checkNotBuilt();
query.setOnConflict(onConflict);
query.setTable(table);
return this;
}
public Builder insertInto(final String table) {
return insertInto(null, table);
}
public Builder select(final SQLSelectQuery select) {
checkNotBuilt();
query.setSelect(select);
return this;
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -1,11 +1,11 @@
/**
* This is free and unencumbered software released into the public domain.
*
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
@ -21,240 +21,241 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.OrderBy;
import org.mariotaku.querybuilder.SQLLang;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.SQLQueryException;
import org.mariotaku.querybuilder.Selectable;
import org.mariotaku.querybuilder.Where;
import java.util.ArrayList;
import java.util.List;
public class SQLSelectQuery implements Selectable {
public class SQLSelectQuery implements SQLQuery, Selectable {
private final List<InternalQuery> internalQueries = new ArrayList<InternalQuery>();
private final List<InternalQuery> internalQueries = new ArrayList<InternalQuery>();
private InternalQuery currentInternalQuery;
private OrderBy orderBy;
private Integer limit = null, offset = null;
private InternalQuery currentInternalQuery;
private OrderBy orderBy;
private Integer limit = null, offset = null;
SQLSelectQuery() {
initCurrentQuery();
}
SQLSelectQuery() {
initCurrentQuery();
}
@Override
public String getSQL() {
final StringBuilder sb = new StringBuilder();
final int size = internalQueries.size();
for (int i = 0; i < size; i++) {
if (i != 0) {
sb.append("UNION ");
}
final InternalQuery query = internalQueries.get(i);
sb.append(query.getSQL());
@Override
public String getSQL() {
final StringBuilder sb = new StringBuilder();
final int size = internalQueries.size();
for (int i = 0; i < size; i++) {
if (i != 0) {
sb.append("UNION ");
}
final InternalQuery query = internalQueries.get(i);
sb.append(query.getSQL());
}
if (orderBy != null) {
sb.append(String.format("ORDER BY %s ", orderBy.getSQL()));
}
if (limit != null) {
sb.append(String.format("LIMIT %s ", limit));
if (offset != null) {
sb.append(String.format("OFFSET %s ", offset));
}
}
return sb.toString();
}
}
if (orderBy != null) {
sb.append(String.format("ORDER BY %s ", orderBy.getSQL()));
}
if (limit != null) {
sb.append(String.format("LIMIT %s ", limit));
if (offset != null) {
sb.append(String.format("OFFSET %s ", offset));
}
}
return sb.toString();
}
private void initCurrentQuery() {
currentInternalQuery = new InternalQuery();
internalQueries.add(currentInternalQuery);
}
private void initCurrentQuery() {
currentInternalQuery = new InternalQuery();
internalQueries.add(currentInternalQuery);
}
void setDistinct(final boolean distinct) {
currentInternalQuery.setDistinct(distinct);
}
void setDistinct(final boolean distinct) {
currentInternalQuery.setDistinct(distinct);
}
void setFrom(final Selectable from) {
currentInternalQuery.setFrom(from);
}
void setFrom(final Selectable from) {
currentInternalQuery.setFrom(from);
}
void setGroupBy(final Selectable groupBy) {
currentInternalQuery.setGroupBy(groupBy);
}
void setGroupBy(final Selectable groupBy) {
currentInternalQuery.setGroupBy(groupBy);
}
void setHaving(final Where having) {
currentInternalQuery.setHaving(having);
}
void setHaving(final Expression having) {
currentInternalQuery.setHaving(having);
}
void setLimit(final int limit) {
this.limit = limit;
}
void setLimit(final int limit) {
this.limit = limit;
}
void setOffset(final int offset) {
this.offset = offset;
}
void setOffset(final int offset) {
this.offset = offset;
}
void setOrderBy(final OrderBy orderBy) {
this.orderBy = orderBy;
}
void setOrderBy(final OrderBy orderBy) {
this.orderBy = orderBy;
}
void setSelect(final Selectable select) {
currentInternalQuery.setSelect(select);
}
void setSelect(final Selectable select) {
currentInternalQuery.setSelect(select);
}
void setWhere(final Where where) {
currentInternalQuery.setWhere(where);
}
void setWhere(final Expression where) {
currentInternalQuery.setWhere(where);
}
void union() {
initCurrentQuery();
}
void union() {
initCurrentQuery();
}
public static final class Builder implements IBuilder<SQLSelectQuery> {
private boolean buildCalled;
private final SQLSelectQuery query = new SQLSelectQuery();
public static final class Builder implements IBuilder<SQLSelectQuery> {
private final SQLSelectQuery query = new SQLSelectQuery();
private boolean buildCalled;
@Override
public SQLSelectQuery build() {
buildCalled = true;
return query;
}
@Override
public SQLSelectQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder from(final Selectable from) {
checkNotBuilt();
query.setFrom(from);
return this;
}
public Builder from(final Selectable from) {
checkNotBuilt();
query.setFrom(from);
return this;
}
public Builder groupBy(final Selectable groupBy) {
checkNotBuilt();
query.setGroupBy(groupBy);
return this;
}
public Builder groupBy(final Selectable groupBy) {
checkNotBuilt();
query.setGroupBy(groupBy);
return this;
}
public Builder having(final Where having) {
checkNotBuilt();
query.setHaving(having);
return this;
}
public Builder having(final Expression having) {
checkNotBuilt();
query.setHaving(having);
return this;
}
public Builder limit(final int limit) {
checkNotBuilt();
query.setLimit(limit);
return this;
}
public Builder limit(final int limit) {
checkNotBuilt();
query.setLimit(limit);
return this;
}
public Builder offset(final int offset) {
query.setOffset(offset);
return this;
}
public Builder offset(final int offset) {
query.setOffset(offset);
return this;
}
public Builder orderBy(final OrderBy orderBy) {
checkNotBuilt();
query.setOrderBy(orderBy);
return this;
}
public Builder orderBy(final OrderBy orderBy) {
checkNotBuilt();
query.setOrderBy(orderBy);
return this;
}
public Builder select(final boolean distinct, final Selectable select) {
checkNotBuilt();
query.setSelect(select);
query.setDistinct(distinct);
return this;
}
public Builder select(final boolean distinct, final Selectable select) {
checkNotBuilt();
query.setSelect(select);
query.setDistinct(distinct);
return this;
}
public Builder select(final Selectable select) {
checkNotBuilt();
select(false, select);
return this;
}
public Builder select(final Selectable select) {
checkNotBuilt();
select(false, select);
return this;
}
public Builder union() {
checkNotBuilt();
query.union();
return this;
}
public Builder union() {
checkNotBuilt();
query.union();
return this;
}
public Builder where(final Where where) {
checkNotBuilt();
query.setWhere(where);
return this;
}
public Builder where(final Expression where) {
checkNotBuilt();
query.setWhere(where);
return this;
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}
private static class InternalQuery implements SQLLang {
private static class InternalQuery implements SQLLang {
private boolean distinct;
private Selectable select, from, groupBy;
private Where where, having;
private boolean distinct;
private Selectable select, from, groupBy;
private Expression where, having;
@Override
public String getSQL() {
if (select == null) throw new SQLQueryException("selectable is null");
final StringBuilder sb = new StringBuilder("SELECT ");
if (distinct) {
sb.append("DISTINCT ");
}
sb.append(String.format("%s ", select.getSQL()));
if (!(select instanceof SQLSelectQuery) && from == null)
throw new SQLQueryException("FROM not specified");
else if (from != null) {
if (from instanceof SQLSelectQuery) {
sb.append(String.format("FROM (%s) ", from.getSQL()));
} else {
sb.append(String.format("FROM %s ", from.getSQL()));
}
}
if (where != null) {
sb.append(String.format("WHERE %s ", where.getSQL()));
}
if (groupBy != null) {
sb.append(String.format("GROUP BY %s ", groupBy.getSQL()));
if (having != null) {
sb.append(String.format("HAVING %s ", having.getSQL()));
}
}
return sb.toString();
}
@Override
public String getSQL() {
if (select == null) throw new SQLQueryException("selectable is null");
final StringBuilder sb = new StringBuilder("SELECT ");
if (distinct) {
sb.append("DISTINCT ");
}
sb.append(String.format("%s ", select.getSQL()));
if (!(select instanceof SQLSelectQuery) && from == null)
throw new SQLQueryException("FROM not specified");
else if (from != null) {
if (from instanceof SQLSelectQuery) {
sb.append(String.format("FROM (%s) ", from.getSQL()));
} else {
sb.append(String.format("FROM %s ", from.getSQL()));
}
}
if (where != null) {
sb.append(String.format("WHERE %s ", where.getSQL()));
}
if (groupBy != null) {
sb.append(String.format("GROUP BY %s ", groupBy.getSQL()));
if (having != null) {
sb.append(String.format("HAVING %s ", having.getSQL()));
}
}
return sb.toString();
}
void setDistinct(final boolean distinct) {
this.distinct = distinct;
}
void setDistinct(final boolean distinct) {
this.distinct = distinct;
}
void setFrom(final Selectable from) {
this.from = from;
}
void setFrom(final Selectable from) {
this.from = from;
}
void setGroupBy(final Selectable groupBy) {
this.groupBy = groupBy;
}
void setGroupBy(final Selectable groupBy) {
this.groupBy = groupBy;
}
void setHaving(final Where having) {
this.having = having;
}
void setHaving(final Expression having) {
this.having = having;
}
void setSelect(final Selectable select) {
this.select = select;
}
void setSelect(final Selectable select) {
this.select = select;
}
void setWhere(final Where where) {
this.where = where;
}
}
void setWhere(final Expression where) {
this.where = where;
}
}
}

View File

@ -0,0 +1,100 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.OnConflict;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.SetValue;
import org.mariotaku.querybuilder.Utils;
import java.util.Locale;
public class SQLUpdateQuery implements SQLQuery {
private OnConflict onConflict;
private String table;
private SetValue[] values;
private Expression where;
SQLUpdateQuery() {
}
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("table must not be null!");
final StringBuilder sb = new StringBuilder();
sb.append("UPDATE ");
if (onConflict != null) {
sb.append(String.format(Locale.ROOT, "OR %s ", onConflict.getAction()));
}
sb.append(String.format(Locale.ROOT, "%s ", table));
sb.append(String.format(Locale.ROOT, "SET %s ", Utils.toString(values, ',', false)));
if (where != null) {
sb.append(String.format(Locale.ROOT, "WHERE %s ", where.getSQL()));
}
return sb.toString();
}
void setWhere(final Expression where) {
this.where = where;
}
void setValues(final SetValue[] columns) {
this.values = columns;
}
void setOnConflict(final OnConflict onConflict) {
this.onConflict = onConflict;
}
void setTable(final String table) {
this.table = table;
}
public static final class Builder implements IBuilder<SQLUpdateQuery> {
private final SQLUpdateQuery query = new SQLUpdateQuery();
private boolean buildCalled;
@Override
public SQLUpdateQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder set(final SetValue... values) {
checkNotBuilt();
query.setValues(values);
return this;
}
public Builder where(final Expression where) {
checkNotBuilt();
query.setWhere(where);
return this;
}
public Builder update(final OnConflict onConflict, final String table) {
checkNotBuilt();
query.setOnConflict(onConflict);
query.setTable(table);
return this;
}
public Builder update(final String table) {
return update(null, table);
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -175,7 +175,7 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
public static final int VIRTUAL_TABLE_ID_UNREAD_COUNTS_BY_TYPE = 109;
public static final int NOTIFICATION_ID_HOME_TIMELINE = 1;
public static final int NOTIFICATION_ID_MENTIONS = 2;
public static final int NOTIFICATION_ID_MENTIONS_TIMELINE = 2;
public static final int NOTIFICATION_ID_DIRECT_MESSAGES = 3;
public static final int NOTIFICATION_ID_DRAFTS = 4;
public static final int NOTIFICATION_ID_DATA_PROFILING = 5;

View File

@ -33,6 +33,7 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@ -45,7 +46,7 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.AutoCompleteTextView;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.BaseSupportActivity;
import org.mariotaku.twidere.activity.support.UserListSelectorActivity;
@ -83,25 +84,19 @@ public class FiltersActivity extends BaseSupportActivity implements TabListener,
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
setContentView(R.layout.activity_filters);
mActionBar = getActionBar();
mAdapter = new SupportTabsAdapter(this, getSupportFragmentManager(), null);
mActionBar.setDisplayHomeAsUpEnabled(true);
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
addTab(FilteredUsersFragment.class, R.string.users, 0);
addTab(FilteredKeywordsFragment.class, R.string.keywords, 1);
addTab(FilteredSourcesFragment.class, R.string.sources, 2);
addTab(FilteredLinksFragment.class, R.string.links, 3);
mViewPager.setAdapter(mAdapter);
mViewPager.setOnPageChangeListener(this);
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.menu_filters, menu);
return true;
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.menu_filters, menu);
public boolean onPrepareOptionsMenu(final Menu menu) {
final boolean enable_in_home_timeline = mPreferences.getBoolean(KEY_FILTERS_IN_HOME_TIMELINE, true);
final boolean enable_in_mentions = mPreferences.getBoolean(KEY_FILTERS_IN_MENTIONS_TIMELINE, true);
final boolean enable_for_rts = mPreferences.getBoolean(KEY_FILTERS_FOR_RTS, true);
menu.findItem(R.id.enable_in_home_timeline).setChecked(enable_in_home_timeline);
menu.findItem(R.id.enable_in_mentions).setChecked(enable_in_mentions);
menu.findItem(R.id.enable_for_rts).setChecked(enable_for_rts);
return true;
}
@ -140,7 +135,7 @@ public class FiltersActivity extends BaseSupportActivity implements TabListener,
}
case R.id.enable_in_mentions: {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(KEY_FILTERS_IN_MENTIONS, !item.isChecked());
editor.putBoolean(KEY_FILTERS_IN_MENTIONS_TIMELINE, !item.isChecked());
editor.apply();
break;
}
@ -155,12 +150,29 @@ public class FiltersActivity extends BaseSupportActivity implements TabListener,
}
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
setContentView(R.layout.activity_filters);
mActionBar = getActionBar();
mAdapter = new SupportTabsAdapter(this, getSupportFragmentManager(), null);
mActionBar.setDisplayHomeAsUpEnabled(true);
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
addTab(FilteredUsersFragment.class, R.string.users, 0);
addTab(FilteredKeywordsFragment.class, R.string.keywords, 1);
addTab(FilteredSourcesFragment.class, R.string.sources, 2);
addTab(FilteredLinksFragment.class, R.string.links, 3);
mViewPager.setAdapter(mAdapter);
mViewPager.setOnPageChangeListener(this);
}
@Override
public void onPageScrollStateChanged(final int state) {
public boolean getSystemWindowsInsets(Rect insets) {
return false;
}
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
}
@Override
@ -170,18 +182,7 @@ public class FiltersActivity extends BaseSupportActivity implements TabListener,
}
@Override
public boolean onPrepareOptionsMenu(final Menu menu) {
final boolean enable_in_home_timeline = mPreferences.getBoolean(KEY_FILTERS_IN_HOME_TIMELINE, true);
final boolean enable_in_mentions = mPreferences.getBoolean(KEY_FILTERS_IN_MENTIONS, true);
final boolean enable_for_rts = mPreferences.getBoolean(KEY_FILTERS_FOR_RTS, true);
menu.findItem(R.id.enable_in_home_timeline).setChecked(enable_in_home_timeline);
menu.findItem(R.id.enable_in_mentions).setChecked(enable_in_mentions);
menu.findItem(R.id.enable_for_rts).setChecked(enable_for_rts);
return true;
}
@Override
public void onTabReselected(final Tab tab, final FragmentTransaction ft) {
public void onPageScrollStateChanged(final int state) {
}
@ -195,6 +196,11 @@ public class FiltersActivity extends BaseSupportActivity implements TabListener,
}
@Override
public void onTabReselected(final Tab tab, final FragmentTransaction ft) {
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
@ -205,7 +211,7 @@ public class FiltersActivity extends BaseSupportActivity implements TabListener,
final ParcelableUser user = data.getParcelableExtra(EXTRA_USER);
final ContentValues values = ContentValuesCreator.makeFilteredUserContentValues(user);
final ContentResolver resolver = getContentResolver();
resolver.delete(Filters.Users.CONTENT_URI, Where.equals(Filters.Users.USER_ID, user.id).getSQL(), null);
resolver.delete(Filters.Users.CONTENT_URI, Expression.equals(Filters.Users.USER_ID, user.id).getSQL(), null);
resolver.insert(Filters.Users.CONTENT_URI, values);
break;
}

View File

@ -41,6 +41,7 @@ import android.view.ViewGroup.MarginLayoutParams;
import android.view.ViewParent;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
@ -235,7 +236,6 @@ public class SettingsActivity extends BasePreferenceActivity {
static final int HEADER_TYPE_CATEGORY = 1;
static final int HEADER_TYPE_SPACE = 2;
private final Context mContext;
private final Resources mResources;
private final int mActionIconColor;
private final ArrayList<Header> mHeaders;
@ -244,7 +244,6 @@ public class SettingsActivity extends BasePreferenceActivity {
private boolean mFirstItemIsCategory;
public HeaderAdapter(final Context context) {
mContext = context;
mInflater = LayoutInflater.from(context);
mHeaders = new ArrayList<>();
mResources = context.getResources();
@ -385,6 +384,13 @@ public class SettingsActivity extends BasePreferenceActivity {
holder.icon.setImageDrawable(null);
}
holder.icon.setColorFilter(mActionIconColor, Mode.SRC_ATOP);
if (position > 0 && position <= getCount() - 1) {
final boolean prevCategory = getItemViewType(position - 1) == HEADER_TYPE_CATEGORY;
holder.content.setShowDividers(prevCategory ? LinearLayout.SHOW_DIVIDER_NONE : LinearLayout.SHOW_DIVIDER_END);
} else {
holder.content.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE);
}
}
private View inflateItemView(int viewType, ViewGroup parent) {
@ -424,12 +430,14 @@ public class SettingsActivity extends BasePreferenceActivity {
private static class HeaderViewHolder extends ViewHolder {
private final TextView title, summary;
private final ImageView icon;
private final LinearLayout content;
HeaderViewHolder(final View view) {
super(view);
title = (TextView) findViewById(android.R.id.title);
summary = (TextView) findViewById(android.R.id.summary);
icon = (ImageView) findViewById(android.R.id.icon);
content = (LinearLayout) findViewById(android.R.id.content);
}
}

View File

@ -83,8 +83,8 @@ import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.BaseArrayAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.support.BaseSupportDialogFragment;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.DraftItem;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableLocation;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableMediaUpdate;
@ -186,7 +186,7 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
private boolean mIsPossiblySensitive, mShouldSaveAccounts;
private long[] mAccountIds, mSendAccountIds;
private long[] mSendAccountIds;
private Uri mTempPhotoUri;
private boolean mImageUploaderUsed, mStatusShortenerUsed;
@ -537,7 +537,7 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
public void saveToDrafts() {
final String text = mEditText != null ? ParseUtils.parseString(mEditText.getText()) : null;
final ParcelableStatusUpdate.Builder builder = new ParcelableStatusUpdate.Builder();
builder.accounts(Account.getAccounts(this, mSendAccountIds));
builder.accounts(ParcelableAccount.getAccounts(this, mSendAccountIds));
builder.text(text);
builder.inReplyToStatusId(mInReplyToStatusId);
builder.location(mRecentLocation);
@ -561,8 +561,8 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
setContentView(R.layout.activity_compose);
setProgressBarIndeterminateVisibility(false);
setFinishOnTouchOutside(false);
mAccountIds = getAccountIds(this);
if (mAccountIds.length <= 0) {
final long[] defaultAccountIds = getAccountIds(this);
if (defaultAccountIds.length <= 0) {
final Intent intent = new Intent(INTENT_ACTION_TWITTER_LOGIN);
intent.setClass(this, SignInActivity.class);
startActivity(intent);
@ -574,7 +574,7 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
mEditText.setOnEditorActionListener(mPreferences.getBoolean(KEY_QUICK_SEND, false) ? this : null);
mEditText.addTextChangedListener(this);
final AccountSelectorAdapter accountAdapter = new AccountSelectorAdapter(mMenuBar.getPopupContext());
accountAdapter.addAll(Account.getAccountsList(this, false));
accountAdapter.addAll(ParcelableAccount.getAccountsList(this, false));
mAccountSelectorPopup = IListPopupWindow.InstanceHelper.getInstance(mMenuBar.getPopupContext());
mAccountSelectorPopup.setInputMethodMode(IListPopupWindow.INPUT_METHOD_NOT_NEEDED);
mAccountSelectorPopup.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
@ -621,8 +621,8 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
if (mSendAccountIds == null || mSendAccountIds.length == 0) {
final long[] idsInPrefs = ArrayUtils.parseLongArray(
mPreferences.getString(KEY_COMPOSE_ACCOUNTS, null), ',');
final long[] intersection = ArrayUtils.intersection(idsInPrefs, mAccountIds);
mSendAccountIds = intersection.length > 0 ? intersection : mAccountIds;
final long[] intersection = ArrayUtils.intersection(idsInPrefs, defaultAccountIds);
mSendAccountIds = intersection.length > 0 ? intersection : defaultAccountIds;
}
mOriginalText = ParseUtils.parseString(mEditText.getText());
}
@ -732,7 +732,18 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
private boolean handleDefaultIntent(final Intent intent) {
if (intent == null) return false;
final String action = intent.getAction();
mShouldSaveAccounts = !Intent.ACTION_SEND.equals(action) && !Intent.ACTION_SEND_MULTIPLE.equals(action);
final boolean hasAccountIds;
if (intent.hasExtra(EXTRA_ACCOUNT_IDS)) {
mSendAccountIds = intent.getLongArrayExtra(EXTRA_ACCOUNT_IDS);
hasAccountIds = true;
} else if (intent.hasExtra(EXTRA_ACCOUNT_ID)) {
mSendAccountIds = new long[]{intent.getLongExtra(EXTRA_ACCOUNT_ID, -1)};
hasAccountIds = true;
} else {
hasAccountIds = false;
}
mShouldSaveAccounts = !Intent.ACTION_SEND.equals(action)
&& !Intent.ACTION_SEND_MULTIPLE.equals(action) && !hasAccountIds;
final Uri data = intent.getData();
final CharSequence extraSubject = intent.getCharSequenceExtra(Intent.EXTRA_SUBJECT);
final CharSequence extraText = intent.getCharSequenceExtra(Intent.EXTRA_TEXT);
@ -1265,7 +1276,7 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
}
private static class AccountSelectorAdapter extends BaseArrayAdapter<Account> {
private static class AccountSelectorAdapter extends BaseArrayAdapter<ParcelableAccount> {
public AccountSelectorAdapter(final Context context) {
super(context, android.R.layout.simple_list_item_multiple_choice);
@ -1284,7 +1295,7 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view = super.getView(position, convertView, parent);
final Account account = getItem(position);
final ParcelableAccount account = getItem(position);
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
text1.setText(Utils.getAccountDisplayName(getContext(), account.account_id, isDisplayNameFirst()));
return view;

View File

@ -48,7 +48,7 @@ import org.mariotaku.twidere.adapter.AccountsSpinnerAdapter;
import org.mariotaku.twidere.adapter.ArrayAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.support.BaseSupportDialogFragment;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.CustomTabConfiguration;
import org.mariotaku.twidere.model.CustomTabConfiguration.ExtraConfiguration;
import org.mariotaku.twidere.model.ParcelableUser;
@ -303,10 +303,10 @@ public class CustomTabEditorActivity extends BaseSupportDialogActivity implement
mSecondaryFieldContainer.setVisibility(has_secondary_field ? View.VISIBLE : View.GONE);
final boolean accountIdRequired = conf.getAccountRequirement() == CustomTabConfiguration.ACCOUNT_REQUIRED;
if (!accountIdRequired) {
mAccountsAdapter.add(Account.dummyInstance());
mAccountsAdapter.add(ParcelableAccount.dummyInstance());
}
final boolean officialKeyOnly = intent.getBooleanExtra(EXTRA_OFFICIAL_KEY_ONLY, false);
mAccountsAdapter.addAll(Account.getAccountsList(this, false, officialKeyOnly));
mAccountsAdapter.addAll(ParcelableAccount.getAccountsList(this, false, officialKeyOnly));
switch (conf.getSecondaryFieldType()) {
case CustomTabConfiguration.FIELD_TYPE_USER: {
mSecondaryFieldLabel.setText(R.string.user);

View File

@ -50,8 +50,8 @@ import android.widget.ListView;
import org.mariotaku.menucomponent.widget.PopupMenu;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.DraftsAdapter;
import org.mariotaku.twidere.fragment.support.BaseSupportDialogFragment;
@ -106,7 +106,7 @@ public class DraftsActivity extends BaseSupportActivity implements LoaderCallbac
}
}
if (sendDrafts(list)) {
final Where where = Where.in(new Column(Drafts._ID),
final Expression where = Expression.in(new Column(Drafts._ID),
new RawItemArray(mListView.getCheckedItemIds()));
mResolver.delete(Drafts.CONTENT_URI, where.getSQL(), null);
}
@ -237,7 +237,7 @@ public class DraftsActivity extends BaseSupportActivity implements LoaderCallbac
final Bundle bundle = new Bundle();
bundle.putParcelable(EXTRA_DRAFT, draft);
intent.putExtras(bundle);
mResolver.delete(Drafts.CONTENT_URI, Where.equals(Drafts._ID, draft._id).getSQL(), null);
mResolver.delete(Drafts.CONTENT_URI, Expression.equals(Drafts._ID, draft._id).getSQL(), null);
startActivityForResult(intent, REQUEST_COMPOSE);
}
@ -307,7 +307,7 @@ public class DraftsActivity extends BaseSupportActivity implements LoaderCallbac
@Override
protected Integer doInBackground(final Void... params) {
final ContentResolver resolver = mActivity.getContentResolver();
final Where where = Where.in(new Column(Drafts._ID), new RawItemArray(mIds));
final Expression where = Expression.in(new Column(Drafts._ID), new RawItemArray(mIds));
final String[] projection = {Drafts.MEDIA};
final Cursor c = resolver.query(Drafts.CONTENT_URI, projection, where.getSQL(), null, null);
final int idxMedia = c.getColumnIndex(Drafts.MEDIA);

View File

@ -77,7 +77,7 @@ import org.mariotaku.twidere.fragment.support.AccountsDashboardFragment;
import org.mariotaku.twidere.fragment.support.DirectMessagesFragment;
import org.mariotaku.twidere.fragment.support.TrendsSuggectionsFragment;
import org.mariotaku.twidere.graphic.EmptyDrawable;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.SupportTabSpec;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.task.AsyncTask;
@ -146,7 +146,7 @@ public class HomeActivity extends BaseSupportActivity implements OnClickListener
private final ArrayList<SupportTabSpec> mCustomTabs = new ArrayList<SupportTabSpec>();
private final SparseArray<Fragment> mAttachedFragments = new SparseArray<Fragment>();
private Account mSelectedAccountToSearch;
private ParcelableAccount mSelectedAccountToSearch;
private SharedPreferences mPreferences;
@ -424,7 +424,7 @@ public class HomeActivity extends BaseSupportActivity implements OnClickListener
}
}
public void openSearchView(final Account account) {
public void openSearchView(final ParcelableAccount account) {
mSelectedAccountToSearch = account;
onSearchRequested();
}

View File

@ -210,8 +210,7 @@ public class LinkHandlerActivity extends BaseSupportActivity implements OnClickL
break;
}
case LINK_ID_STATUS: {
// transitionRes = R.transition.transition_status;
transitionRes = 0;
transitionRes = R.transition.transition_status;
break;
}
default: {
@ -221,7 +220,7 @@ public class LinkHandlerActivity extends BaseSupportActivity implements OnClickL
}
if (transitionRes != 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
&& !ThemeUtils.isTransparentBackground(this)) {
Utils.setSharedElementTransition(this, window, R.transition.transition_status);
Utils.setSharedElementTransition(this, window, transitionRes);
}
}

View File

@ -14,7 +14,6 @@ import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.support.StatusFragment;
import org.mariotaku.twidere.fragment.support.StatusMenuDialogFragment;
import org.mariotaku.twidere.fragment.support.UserFragment;
import org.mariotaku.twidere.model.ParcelableStatus;
@ -42,6 +41,8 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
private final int mCardLayoutResource;
private boolean mLoadMoreIndicatorEnabled;
private EventListener mEventListener;
public AbsStatusesAdapter(Context context, boolean compact) {
mContext = context;
mInflater = LayoutInflater.from(context);
@ -59,7 +60,7 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
switch (viewType) {
case ITEM_VIEW_TYPE_STATUS: {
final View view = mInflater.inflate(mCardLayoutResource, parent, false);
return new StatusViewHolder<>(this, view);
return new StatusViewHolder(this, view);
}
case ITEM_VIEW_TYPE_GAP: {
final View view = mInflater.inflate(R.layout.card_item_gap, parent, false);
@ -126,16 +127,10 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
}
@Override
public void onStatusClick(StatusViewHolder holder, int position) {
final Context context = getContext();
// final View cardView = holder.getCardView();
// if (cardView != null && context instanceof FragmentActivity) {
// final Bundle options = Utils.makeSceneTransitionOption((FragmentActivity) context,
// new Pair<>(cardView, StatusFragment.TRANSITION_NAME_CARD));
// Utils.openStatus(context, getStatus(position), options);
// } else {
Utils.openStatus(context, getStatus(position), null);
// }
public final void onStatusClick(StatusViewHolder holder, int position) {
if (mEventListener != null) {
mEventListener.onStatusClick(holder, position);
}
}
@Override
@ -153,18 +148,42 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
}
@Override
public void onItemMenuClick(StatusViewHolder holder, int position) {
final Context context = getContext();
if (!(context instanceof FragmentActivity)) return;
final Bundle args = new Bundle();
args.putParcelable(EXTRA_STATUS, getStatus(position));
final StatusMenuDialogFragment f = new StatusMenuDialogFragment();
f.setArguments(args);
f.show(((FragmentActivity) context).getSupportFragmentManager(), "status_menu");
public void onItemActionClick(ViewHolder holder, int id, int position) {
if (mEventListener != null) {
mEventListener.onStatusActionClick((StatusViewHolder) holder, id, position);
}
}
@Override
public void onItemMenuClick(ViewHolder holder, int position) {
if (mEventListener != null) {
mEventListener.onStatusMenuClick((StatusViewHolder) holder, position);
}
}
public abstract void setData(D data);
public abstract D getData();
public void setEventListener(EventListener listener) {
mEventListener = listener;
}
@Override
public final void onGapClick(ViewHolder holder, int position) {
if (mEventListener != null) {
mEventListener.onGapClick((GapViewHolder) holder, position);
}
}
public static interface EventListener {
void onStatusActionClick(StatusViewHolder holder, int id, int position);
void onStatusClick(StatusViewHolder holder, int position);
void onGapClick(GapViewHolder holder, int position);
void onStatusMenuClick(StatusViewHolder holder, int position);
}
}

View File

@ -32,8 +32,8 @@ import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IBaseAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.Account.Indices;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableAccount.Indices;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.view.holder.AccountViewHolder;
@ -58,10 +58,10 @@ public class AccountsAdapter extends SimpleDragSortCursorAdapter implements Cons
mPreferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
public Account getAccount(int position) {
public ParcelableAccount getAccount(int position) {
final Cursor c = getCursor();
if (c == null || c.isClosed() || !c.moveToPosition(position)) return null;
return new Account(c, mIndices);
return new ParcelableAccount(c, mIndices);
}
@Override

View File

@ -20,7 +20,6 @@
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.graphics.PorterDuff.Mode;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@ -29,13 +28,12 @@ import android.widget.TextView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.support.DirectMessagesConversationFragment;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import java.util.Collection;
public class AccountsSpinnerAdapter extends ArrayAdapter<Account> {
public class AccountsSpinnerAdapter extends ArrayAdapter<ParcelableAccount> {
private final ImageLoaderWrapper mImageLoader;
private final boolean mDisplayProfileImage;
@ -48,7 +46,7 @@ public class AccountsSpinnerAdapter extends ArrayAdapter<Account> {
Context.MODE_PRIVATE).getBoolean(DirectMessagesConversationFragment.KEY_DISPLAY_PROFILE_IMAGE, true);
}
public AccountsSpinnerAdapter(final Context context, final Collection<Account> accounts) {
public AccountsSpinnerAdapter(final Context context, final Collection<ParcelableAccount> accounts) {
this(context);
addAll(accounts);
}
@ -67,7 +65,7 @@ public class AccountsSpinnerAdapter extends ArrayAdapter<Account> {
return view;
}
private void bindView(final View view, final Account item) {
private void bindView(final View view, final ParcelableAccount item) {
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
final TextView text2 = (TextView) view.findViewById(android.R.id.text2);
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);

View File

@ -73,11 +73,6 @@ public class CursorStatusesAdapter extends AbsStatusesAdapter<Cursor> {
notifyDataSetChanged();
}
@Override
public void onGapClick(StatusViewHolder holder, int position) {
}
@Override
public Cursor getData() {
return mCursor;

View File

@ -25,6 +25,7 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v4.util.Pair;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@ -121,7 +122,12 @@ public class CursorStatusesListAdapter extends BaseCursorAdapter implements ISta
}
@Override
public void onItemMenuClick(StatusViewHolder holder, int position) {
public void onItemActionClick(ViewHolder holder, int id, int position) {
}
@Override
public void onItemMenuClick(ViewHolder holder, int position) {
}
@ -364,7 +370,7 @@ public class CursorStatusesListAdapter extends BaseCursorAdapter implements ISta
}
@Override
public void onGapClick(StatusViewHolder holder, int position) {
public void onGapClick(ViewHolder holder, int position) {
}
}

View File

@ -33,7 +33,6 @@ import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages.ConversationEntries;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.DirectMessageEntryViewHolder;
import static org.mariotaku.twidere.provider.TweetStore.DirectMessages.ConversationEntries.IDX_ACCOUNT_ID;
@ -55,15 +54,8 @@ public class DirectMessageConversationEntriesAdapter extends BaseCursorAdapter i
private final ImageLoaderWrapper mImageLoader;
private final MultiSelectManager mMultiSelectManager;
private boolean mAnimationEnabled;
private int mMaxAnimationPosition;
public DirectMessageConversationEntriesAdapter(final Context context) {
this(context, Utils.isCompactCards(context));
}
public DirectMessageConversationEntriesAdapter(final Context context, final boolean compactCards) {
super(context, getItemResource(compactCards), null, new String[0], new int[0], 0);
super(context, R.layout.list_item_message_entry, null, new String[0], new int[0], 0);
final TwidereApplication app = TwidereApplication.getInstance(context);
mMultiSelectManager = app.getMultiSelectManager();
mImageLoader = app.getImageLoaderWrapper();
@ -96,8 +88,6 @@ public class DirectMessageConversationEntriesAdapter extends BaseCursorAdapter i
final String nick = getUserNickname(context, conversationId);
holder.name.setText(TextUtils.isEmpty(nick) ? name : isNicknameOnly() ? nick : context.getString(
R.string.name_with_nickname, name, nick));
holder.screen_name.setText("@" + screenName);
holder.screen_name.setVisibility(View.VISIBLE);
holder.text.setText(toPlainText(cursor.getString(IDX_TEXT)));
holder.time.setTime(timestamp);
holder.setIsOutgoing(isOutgoing);
@ -110,12 +100,6 @@ public class DirectMessageConversationEntriesAdapter extends BaseCursorAdapter i
} else {
mImageLoader.cancelDisplayTask(holder.profile_image);
}
if (position > mMaxAnimationPosition) {
if (mAnimationEnabled) {
view.startAnimation(holder.item_animation);
}
mMaxAnimationPosition = position;
}
super.bindView(view, context, cursor);
}
@ -175,20 +159,14 @@ public class DirectMessageConversationEntriesAdapter extends BaseCursorAdapter i
@Override
public void setAnimationEnabled(final boolean anim) {
if (mAnimationEnabled == anim) return;
mAnimationEnabled = anim;
}
@Override
public void setMaxAnimationPosition(final int position) {
mMaxAnimationPosition = position;
}
@Override
public void setMenuButtonClickListener(final MenuButtonClickListener listener) {
}
private static int getItemResource(final boolean compactCards) {
return compactCards ? R.layout.card_item_message_entry_compact : R.layout.card_item_message_entry;
}
}

View File

@ -23,11 +23,6 @@ public class ParcelableStatusesAdapter extends AbsStatusesAdapter<List<Parcelabl
return getStatus(position).is_gap;
}
@Override
public void onGapClick(StatusViewHolder holder, int position) {
}
@Override
protected void bindStatus(StatusViewHolder holder, int position) {
holder.displayStatus(getStatus(position));

View File

@ -22,6 +22,7 @@ package org.mariotaku.twidere.adapter;
import android.app.Activity;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@ -105,7 +106,12 @@ public class ParcelableStatusesListAdapter extends BaseArrayAdapter<ParcelableSt
}
@Override
public void onItemMenuClick(StatusViewHolder holder, int position) {
public void onItemActionClick(ViewHolder holder, int id, int position) {
}
@Override
public void onItemMenuClick(ViewHolder holder, int position) {
}
@ -184,7 +190,7 @@ public class ParcelableStatusesListAdapter extends BaseArrayAdapter<ParcelableSt
}
@Override
public void onGapClick(StatusViewHolder holder, int position) {
public void onGapClick(ViewHolder holder, int position) {
}

View File

@ -33,8 +33,8 @@ import android.widget.ImageView;
import android.widget.TextView;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.app.TwidereApplication;
@ -169,7 +169,7 @@ public class UserHashtagAutoCompleteAdapter extends SimpleCursorAdapter implemen
builder.append(" OR ");
builder.append(CachedUsers.NAME + " LIKE ?||'%' ESCAPE '^'");
builder.append(" OR ");
builder.append(Where.in(new Column(CachedUsers.USER_ID),
builder.append(Expression.in(new Column(CachedUsers.USER_ID),
new RawItemArray(getMatchedNicknameIds(ParseUtils.parseString(constraint)))).getSQL());
final String selection = constraint_escaped != null ? builder.toString() : null;
final String[] selectionArgs = constraint_escaped != null ? new String[]{constraint_escaped,

View File

@ -24,6 +24,8 @@ import android.support.v7.widget.RecyclerView.ViewHolder;
/**
* Created by mariotaku on 14/12/3.
*/
public interface IItemMenuSupportedAdapter<VH extends ViewHolder> {
void onItemMenuClick(VH holder, int position);
public interface ICardSupportedAdapter {
void onItemActionClick(ViewHolder holder, int id, int position);
void onItemMenuClick(ViewHolder holder, int position);
}

View File

@ -24,10 +24,10 @@ import android.support.v7.widget.RecyclerView.ViewHolder;
/**
* Created by mariotaku on 14/12/3.
*/
public interface IGapSupportedAdapter<VH extends ViewHolder> {
public interface IGapSupportedAdapter {
boolean isGapItem(int position);
void onGapClick(VH holder, int position);
void onGapClick(ViewHolder holder, int position);
}

View File

@ -10,8 +10,7 @@ import org.mariotaku.twidere.view.holder.StatusViewHolder;
/**
* Created by mariotaku on 14/11/18.
*/
public interface IStatusesAdapter<Data> extends IGapSupportedAdapter<StatusViewHolder>,
IItemMenuSupportedAdapter<StatusViewHolder> {
public interface IStatusesAdapter<Data> extends IGapSupportedAdapter, ICardSupportedAdapter {
ImageLoaderWrapper getImageLoader();

View File

@ -85,7 +85,7 @@ public interface IntentConstants {
public static final String BROADCAST_FRIENDSHIP_DENIED = INTENT_PACKAGE_PREFIX + "FRIENDSHIP_DENIED";
public static final String BROADCAST_FAVORITE_CHANGED = INTENT_PACKAGE_PREFIX + "FAVORITE_CHANGED";
public static final String BROADCAST_RETWEET_CHANGED = INTENT_PACKAGE_PREFIX + "RETWEET_CHANGED";
public static final String BROADCAST_STATUS_RETWEETED = INTENT_PACKAGE_PREFIX + "STATUS_RETWEETED";
public static final String BROADCAST_STATUS_DESTROYED = INTENT_PACKAGE_PREFIX + "STATUS_DESTROYED";
public static final String BROADCAST_USER_LIST_MEMBERS_DELETED = INTENT_PACKAGE_PREFIX + "USER_LIST_MEMBER_DELETED";
public static final String BROADCAST_USER_LIST_MEMBERS_ADDED = INTENT_PACKAGE_PREFIX + "USER_LIST_MEMBER_ADDED";

View File

@ -253,7 +253,7 @@ public interface SharedPreferenceConstants {
@Preference(type = STRING, hasDefault = true, defaultString = TwidereConstants.TWITTER_CONSUMER_SECRET_3)
public static final String KEY_CONSUMER_SECRET = "consumer_secret";
public static final String KEY_FILTERS_IN_HOME_TIMELINE = "filters_in_home_timeline";
public static final String KEY_FILTERS_IN_MENTIONS = "filters_in_mentions";
public static final String KEY_FILTERS_IN_MENTIONS_TIMELINE = "filters_in_mentions";
public static final String KEY_FILTERS_FOR_RTS = "filters_for_rts";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_NICKNAME_ONLY = "nickname_only";

View File

@ -23,7 +23,7 @@ import android.os.Bundle;
import android.preference.Preference;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
public class AccountNotificationSettingsFragment extends BaseAccountPreferenceFragment {
@ -31,7 +31,7 @@ public class AccountNotificationSettingsFragment extends BaseAccountPreferenceFr
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final Preference preference = findPreference(KEY_NOTIFICATION_LIGHT_COLOR);
final Account account = getAccount();
final ParcelableAccount account = getAccount();
if (preference != null && account != null) {
preference.setDefaultValue(account.color);
}

View File

@ -39,7 +39,7 @@ import android.widget.Switch;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
public abstract class BaseAccountPreferenceFragment extends PreferenceFragment implements Constants,
OnCheckedChangeListener, OnSharedPreferenceChangeListener {
@ -49,7 +49,7 @@ public abstract class BaseAccountPreferenceFragment extends PreferenceFragment i
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
final PreferenceManager pm = getPreferenceManager();
final Account account = getArguments().getParcelable(EXTRA_ACCOUNT);
final ParcelableAccount account = getArguments().getParcelable(EXTRA_ACCOUNT);
final String preferenceName = ACCOUNT_PREFERENCES_NAME_PREFIX
+ (account != null ? account.account_id : "unknown");
pm.setSharedPreferencesName(preferenceName);
@ -93,7 +93,7 @@ public abstract class BaseAccountPreferenceFragment extends PreferenceFragment i
}
}
protected Account getAccount() {
protected ParcelableAccount getAccount() {
final Bundle args = getArguments();
if (args == null) return null;
return args.getParcelable(EXTRA_ACCOUNT);

View File

@ -45,8 +45,8 @@ import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.support.BaseSupportListFragment;
import org.mariotaku.twidere.provider.TweetStore.Filters;
@ -83,7 +83,7 @@ public abstract class BaseFiltersFragment extends BaseSupportListFragment implem
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
switch (item.getItemId()) {
case MENU_DELETE: {
final Where where = Where.in(new Column(Filters._ID), new RawItemArray(mListView.getCheckedItemIds()));
final Expression where = Expression.in(new Column(Filters._ID), new RawItemArray(mListView.getCheckedItemIds()));
mResolver.delete(getContentUri(), where.getSQL(), null);
break;
}

View File

@ -52,8 +52,8 @@ import com.mobeta.android.dslv.SimpleDragSortCursorAdapter;
import org.mariotaku.menucomponent.widget.PopupMenu;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.CustomTabEditorActivity;
import org.mariotaku.twidere.model.CustomTabConfiguration;
@ -101,7 +101,7 @@ public class CustomTabsFragment extends BaseListFragment implements LoaderCallba
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
switch (item.getItemId()) {
case MENU_DELETE: {
final Where where = Where.in(new Column(Tabs._ID), new RawItemArray(mListView.getCheckedItemIds()));
final Expression where = Expression.in(new Column(Tabs._ID), new RawItemArray(mListView.getCheckedItemIds()));
mResolver.delete(Tabs.CONTENT_URI, where.getSQL(), null);
break;
}
@ -150,7 +150,7 @@ public class CustomTabsFragment extends BaseListFragment implements LoaderCallba
values.put(Tabs.NAME, data.getStringExtra(EXTRA_NAME));
values.put(Tabs.ICON, data.getStringExtra(EXTRA_ICON));
values.put(Tabs.EXTRAS, data.getStringExtra(EXTRA_EXTRAS));
final String where = Where.equals(Tabs._ID, data.getLongExtra(EXTRA_ID, -1)).getSQL();
final String where = Expression.equals(Tabs._ID, data.getLongExtra(EXTRA_ID, -1)).getSQL();
mResolver.update(Tabs.CONTENT_URI, values, where, null);
}
break;

View File

@ -1,11 +1,13 @@
package org.mariotaku.twidere.fragment.support;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v4.widget.SwipeRefreshLayout;
@ -19,27 +21,77 @@ import android.view.ViewGroup;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.AbsStatusesAdapter;
import org.mariotaku.twidere.adapter.AbsStatusesAdapter.EventListener;
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
import org.mariotaku.twidere.constant.IntentConstants;
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.SimpleDrawerCallback;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback;
import org.mariotaku.twidere.view.holder.GapViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
/**
* Created by mariotaku on 14/11/5.
*/
public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment
implements LoaderCallbacks<Data>, OnRefreshListener, DrawerCallback {
public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment implements LoaderCallbacks<Data>,
OnRefreshListener, DrawerCallback, RefreshScrollTopInterface, EventListener {
private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
if (getActivity() == null || !isAdded() || isDetached()) return;
onReceivedBroadcast(intent, intent.getAction());
}
};
private View mContentView;
private SharedPreferences mPreferences;
private View mProgressContainer;
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerView;
private AbsStatusesAdapter<Data> mAdapter;
private SimpleDrawerCallback mDrawerCallback;
private OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (isRefreshing()) return;
if (layoutManager.findLastVisibleItemPosition() == mAdapter.getItemCount() - 1) {
onLoadMoreStatuses();
}
}
};
@Override
public boolean canScroll(float dy) {
return mDrawerCallback.canScroll(dy);
}
@Override
public void cancelTouch() {
mDrawerCallback.cancelTouch();
}
@Override
public void fling(float velocity) {
mDrawerCallback.fling(velocity);
}
public abstract int getStatuses(long[] accountIds, long[] maxIds, long[] sinceIds);
@Override
public boolean isScrollContent(float x, float y) {
return mDrawerCallback.isScrollContent(x, y);
}
@Override
public void scrollBy(float dy) {
@ -51,51 +103,34 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment
return mDrawerCallback.shouldLayoutHeaderBottom();
}
@Override
public boolean canScroll(float dy) {
return mDrawerCallback.canScroll(dy);
}
@Override
public boolean isScrollContent(float x, float y) {
return mDrawerCallback.isScrollContent(x, y);
}
@Override
public void cancelTouch() {
mDrawerCallback.cancelTouch();
}
@Override
public void topChanged(int offset) {
mDrawerCallback.topChanged(offset);
}
private View mProgressContainer;
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerView;
public AbsStatusesAdapter<Data> getAdapter() {
return mAdapter;
}
private AbsStatusesAdapter<Data> mAdapter;
public SharedPreferences getSharedPreferences() {
if (mPreferences != null) return mPreferences;
return mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
private SimpleDrawerCallback mDrawerCallback;
public abstract int getStatuses(long[] accountIds, long[] maxIds, long[] sinceIds);
private OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
public boolean isRefreshing() {
return mSwipeRefreshLayout.isRefreshing();
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
final LoaderManager lm = getLoaderManager();
if (lm.hasRunningLoaders()) return;
if (layoutManager.findLastVisibleItemPosition() == mAdapter.getItemCount() - 1) {
final long[] maxIds = new long[]{mAdapter.getStatus(mAdapter.getStatusCount() - 1).id};
getStatuses(null, maxIds, null);
}
}
};
public void setRefreshing(boolean refreshing) {
mSwipeRefreshLayout.setRefreshing(refreshing);
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recycler_view, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
@ -116,17 +151,86 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment
}
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setOnScrollListener(mOnScrollListener);
mAdapter.setEventListener(this);
getLoaderManager().initLoader(0, getArguments(), this);
setListShown(false);
}
protected abstract AbsStatusesAdapter<Data> onCreateAdapter(Context context, boolean compact);
private void setListShown(boolean shown) {
mProgressContainer.setVisibility(shown ? View.GONE : View.VISIBLE);
mSwipeRefreshLayout.setVisibility(shown ? View.VISIBLE : View.GONE);
@Override
public void onStart() {
super.onStart();
final IntentFilter filter = new IntentFilter();
onSetIntentFilter(filter);
registerReceiver(mStateReceiver, filter);
}
@Override
public void onStop() {
unregisterReceiver(mStateReceiver);
super.onStop();
}
@Override
public void onLoadFinished(Loader<Data> loader, Data data) {
setRefreshing(false);
mAdapter.setData(data);
setListShown(true);
}
@Override
public void onLoaderReset(Loader<Data> loader) {
}
@Override
public void onRefresh() {
triggerRefresh();
}
@Override
public void onStatusActionClick(StatusViewHolder holder, int id, int position) {
switch (id) {
case R.id.reply_count: {
final Context context = getActivity();
final Intent intent = new Intent(IntentConstants.INTENT_ACTION_REPLY);
intent.setPackage(context.getPackageName());
intent.putExtra(IntentConstants.EXTRA_STATUS, mAdapter.getStatus(position));
context.startActivity(intent);
break;
}
}
}
@Override
public void onStatusClick(StatusViewHolder holder, int position) {
Utils.openStatus(getActivity(), mAdapter.getStatus(position), null);
// final View cardView = holder.getCardView();
// if (cardView != null && context instanceof FragmentActivity) {
// final Bundle options = Utils.makeSceneTransitionOption((FragmentActivity) context,
// new Pair<>(cardView, StatusFragment.TRANSITION_NAME_CARD));
// Utils.openStatus(context, getStatus(position), options);
// } else {
// Utils.openStatus(context, getStatus(position), null);
// }
}
@Override
public void onGapClick(GapViewHolder holder, int position) {
final ParcelableStatus status = mAdapter.getStatus(position);
final long sinceId = position + 1 < mAdapter.getStatusCount() ? mAdapter.getStatus(position + 1).id : -1;
final long[] accountIds = {status.account_id};
final long[] maxIds = {status.id};
final long[] sinceIds = {sinceId};
getStatuses(accountIds, maxIds, sinceIds);
}
@Override
public void onStatusMenuClick(StatusViewHolder holder, int position) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_STATUS, mAdapter.getStatus(position));
final StatusMenuDialogFragment f = new StatusMenuDialogFragment();
f.setArguments(args);
f.show(getActivity().getSupportFragmentManager(), "status_menu");
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
@ -144,44 +248,36 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recycler_view, container, false);
public boolean scrollToStart() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
final int tabPosition = getTabPosition();
if (twitter != null && tabPosition != -1) {
twitter.clearUnreadCountAsync(tabPosition);
}
mRecyclerView.smoothScrollToPosition(0);
return true;
}
protected abstract long[] getAccountIds();
protected Data getAdapterData() {
return mAdapter.getData();
}
public void setRefreshing(boolean refreshing) {
mSwipeRefreshLayout.setRefreshing(refreshing);
}
@Override
public void onLoadFinished(Loader<Data> loader, Data data) {
setRefreshing(false);
protected void setAdapterData(Data data) {
mAdapter.setData(data);
setListShown(true);
}
@Override
public void onLoaderReset(Loader<Data> loader) {
protected abstract AbsStatusesAdapter<Data> onCreateAdapter(Context context, boolean compact);
protected abstract void onLoadMoreStatuses();
protected abstract void onReceivedBroadcast(Intent intent, String action);
protected abstract void onSetIntentFilter(IntentFilter filter);
private void setListShown(boolean shown) {
mProgressContainer.setVisibility(shown ? View.GONE : View.VISIBLE);
mSwipeRefreshLayout.setVisibility(shown ? View.VISIBLE : View.GONE);
}
@Override
public void onRefresh() {
if (mAdapter.getStatusCount() > 0) {
final long[] sinceIds = new long[]{mAdapter.getStatus(0).id};
getStatuses(null, null, sinceIds);
} else {
getStatuses(null, null, null);
}
}
public SharedPreferences getSharedPreferences() {
if (mPreferences != null) return mPreferences;
return mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
}

View File

@ -28,6 +28,7 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.os.Bundle;
@ -54,20 +55,24 @@ import android.widget.Switch;
import android.widget.TextView;
import com.commonsware.cwac.merge.MergeAdapter;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.FiltersActivity;
import org.mariotaku.twidere.activity.SettingsActivity;
import org.mariotaku.twidere.activity.iface.IThemedActivity;
import org.mariotaku.twidere.activity.support.AccountsManagerActivity;
import org.mariotaku.twidere.activity.support.ComposeActivity;
import org.mariotaku.twidere.activity.support.DraftsActivity;
import org.mariotaku.twidere.activity.support.HomeActivity;
import org.mariotaku.twidere.activity.support.UserProfileEditorActivity;
import org.mariotaku.twidere.adapter.ArrayAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.Account.Indices;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableAccount.Indices;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.util.CompareUtils;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
@ -76,13 +81,11 @@ import org.mariotaku.twidere.util.content.SupportFragmentReloadCursorObserver;
import java.util.ArrayList;
import static org.mariotaku.twidere.util.Utils.openUserFavorites;
import static org.mariotaku.twidere.util.Utils.openUserListMemberships;
import static org.mariotaku.twidere.util.Utils.openUserLists;
import static org.mariotaku.twidere.util.Utils.openUserProfile;
import static org.mariotaku.twidere.util.Utils.openUserTimeline;
public class AccountsDashboardFragment extends BaseSupportListFragment implements LoaderCallbacks<Cursor>,
OnSharedPreferenceChangeListener, OnCheckedChangeListener {
OnSharedPreferenceChangeListener, OnCheckedChangeListener, ImageLoadingListener, OnClickListener {
private final SupportFragmentReloadCursorObserver mReloadContentObserver = new SupportFragmentReloadCursorObserver(
this, 0, this);
@ -106,48 +109,6 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
private Context mThemedContext;
private ImageLoaderWrapper mImageLoader;
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mResolver = getContentResolver();
final Context context = getView().getContext();
mImageLoader = TwidereApplication.getInstance(context).getImageLoaderWrapper();
final LayoutInflater inflater = LayoutInflater.from(context);
final ListView listView = getListView();
mAdapter = new MergeAdapter();
mAccountsAdapter = new AccountSelectorAdapter(context, this);
mAccountOptionsAdapter = new AccountOptionsAdapter(context);
mAppMenuAdapter = new AppMenuAdapter(context);
mAppMenuSectionView = newSectionView(context, R.string.more);
mAccountSelectorView = inflater.inflate(R.layout.header_drawer_account_selector, listView, false);
mAccountsSelector = (RecyclerView) mAccountSelectorView.findViewById(R.id.other_accounts_list);
final LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
layoutManager.setStackFromEnd(true);
mAccountsSelector.setLayoutManager(layoutManager);
mAccountsSelector.setAdapter(mAccountsAdapter);
mAccountProfileContainer = mAccountSelectorView.findViewById(R.id.profile_container);
mAccountProfileImageView = (ImageView) mAccountSelectorView.findViewById(R.id.profile_image);
mAccountProfileBannerView = (ImageView) mAccountSelectorView.findViewById(R.id.account_profile_banner);
mAccountProfileNameView = (TextView) mAccountSelectorView.findViewById(R.id.name);
mAccountProfileScreenNameView = (TextView) mAccountSelectorView.findViewById(R.id.screen_name);
mAccountsToggle = (Switch) mAccountSelectorView.findViewById(R.id.toggle);
mAccountsToggle.setOnCheckedChangeListener(this);
mAdapter.addView(mAccountSelectorView, false);
mAdapter.addAdapter(mAccountOptionsAdapter);
mAdapter.addView(mAppMenuSectionView, false);
mAdapter.addAdapter(mAppMenuAdapter);
setListAdapter(mAdapter);
mPreferences.registerOnSharedPreferenceChangeListener(this);
getLoaderManager().initLoader(0, null, this);
}
@Override
protected void fitSystemWindows(Rect insets) {
// No-op
}
@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
@ -163,14 +124,57 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onResume() {
super.onResume();
updateDefaultAccountState();
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
final ParcelableAccount account = mAccountsAdapter.getSelectedAccount();
if (account == null) return;
final ContentValues values = new ContentValues();
values.put(Accounts.IS_ACTIVATED, isChecked);
final String where = Accounts.ACCOUNT_ID + " = " + account.account_id;
mResolver.update(Accounts.CONTENT_URI, values, where, null);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.profile_container: {
final ParcelableAccount account = mAccountsAdapter.getSelectedAccount();
if (account == null) return;
final FragmentActivity activity = getActivity();
final Bundle activityOption = Utils.makeSceneTransitionOption(activity,
new Pair<View, String>(mAccountProfileImageView, UserFragment.TRANSITION_NAME_PROFILE_IMAGE));
openUserProfile(activity, account.account_id, account.account_id,
account.screen_name, activityOption);
break;
}
}
}
@Override
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
return new CursorLoader(getActivity(), Accounts.CONTENT_URI, Accounts.COLUMNS, null, null, Accounts.SORT_POSITION);
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return LayoutInflater.from(getThemedContext()).inflate(R.layout.fragment_accounts_drawer, container, false);
public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) {
if (data != null && data.getCount() > 0 && mAccountsAdapter.getSelectedAccountId() <= 0) {
data.moveToFirst();
mAccountsAdapter.setSelectedAccountId(data.getLong(data.getColumnIndex(Accounts.ACCOUNT_ID)));
}
mAccountsAdapter.changeCursor(data);
updateAccountOptionsSeparatorLabel();
updateDefaultAccountState();
}
@Override
public void onLoaderReset(final Loader<Cursor> loader) {
mAccountsAdapter.changeCursor(null);
}
@Override
@ -178,18 +182,10 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
final ListAdapter adapter = mAdapter.getAdapter(position);
final Object item = mAdapter.getItem(position);
if (adapter instanceof AccountOptionsAdapter) {
final Account account = mAccountsAdapter.getSelectedAccount();
final ParcelableAccount account = mAccountsAdapter.getSelectedAccount();
if (account == null || !(item instanceof OptionItem)) return;
final OptionItem option = (OptionItem) item;
switch (option.id) {
case MENU_VIEW_PROFILE: {
final FragmentActivity activity = getActivity();
final Bundle activityOption = Utils.makeSceneTransitionOption(activity,
new Pair<View, String>(mAccountProfileImageView, UserFragment.TRANSITION_NAME_PROFILE_IMAGE));
openUserProfile(activity, account.account_id, account.account_id,
account.screen_name, activityOption);
break;
}
case MENU_SEARCH: {
final FragmentActivity a = getActivity();
if (a instanceof HomeActivity) {
@ -200,8 +196,11 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
closeAccountsDrawer();
break;
}
case MENU_STATUSES: {
openUserTimeline(getActivity(), account.account_id, account.account_id, account.screen_name);
case MENU_COMPOSE: {
final Intent composeIntent = new Intent(INTENT_ACTION_COMPOSE);
composeIntent.setClass(getActivity(), ComposeActivity.class);
composeIntent.putExtra(EXTRA_ACCOUNT_IDS, new long[]{account.account_id});
startActivity(composeIntent);
break;
}
case MENU_FAVORITES: {
@ -212,10 +211,6 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
openUserLists(getActivity(), account.account_id, account.account_id, account.screen_name);
break;
}
case MENU_LIST_MEMBERSHIPS: {
openUserListMemberships(getActivity(), account.account_id, account.account_id, account.screen_name);
break;
}
case MENU_EDIT: {
final Bundle bundle = new Bundle();
bundle.putLong(EXTRA_ACCOUNT_ID, account.account_id);
@ -259,25 +254,23 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
}
@Override
public void onLoaderReset(final Loader<Cursor> loader) {
mAccountsAdapter.changeCursor(null);
public void onLoadingStarted(String imageUri, View view) {
}
@Override
public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) {
if (data != null && data.getCount() > 0 && mAccountsAdapter.getSelectedAccountId() <= 0) {
data.moveToFirst();
mAccountsAdapter.setSelectedAccountId(data.getLong(data.getColumnIndex(Accounts.ACCOUNT_ID)));
}
mAccountsAdapter.changeCursor(data);
updateAccountOptionsSeparatorLabel();
updateDefaultAccountState();
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
}
@Override
public void onResume() {
super.onResume();
updateDefaultAccountState();
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
view.setTag(imageUri);
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
@Override
@ -287,6 +280,59 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
}
}
public void setStatusBarHeight(int height) {
mAccountProfileContainer.setPadding(0, height, 0, 0);
}
@Override
protected void fitSystemWindows(Rect insets) {
// No-op
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mResolver = getContentResolver();
final Context context = getView().getContext();
mImageLoader = TwidereApplication.getInstance(context).getImageLoaderWrapper();
final LayoutInflater inflater = LayoutInflater.from(context);
final ListView listView = getListView();
mAdapter = new MergeAdapter();
mAccountsAdapter = new AccountSelectorAdapter(context, this);
mAccountOptionsAdapter = new AccountOptionsAdapter(context);
mAppMenuAdapter = new AppMenuAdapter(context);
mAppMenuSectionView = newSectionView(context, R.string.more);
mAccountSelectorView = inflater.inflate(R.layout.header_drawer_account_selector, listView, false);
mAccountsSelector = (RecyclerView) mAccountSelectorView.findViewById(R.id.other_accounts_list);
final LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
layoutManager.setStackFromEnd(true);
mAccountsSelector.setLayoutManager(layoutManager);
mAccountsSelector.setAdapter(mAccountsAdapter);
mAccountProfileContainer = mAccountSelectorView.findViewById(R.id.profile_container);
mAccountProfileImageView = (ImageView) mAccountSelectorView.findViewById(R.id.profile_image);
mAccountProfileBannerView = (ImageView) mAccountSelectorView.findViewById(R.id.account_profile_banner);
mAccountProfileNameView = (TextView) mAccountSelectorView.findViewById(R.id.name);
mAccountProfileScreenNameView = (TextView) mAccountSelectorView.findViewById(R.id.screen_name);
mAccountsToggle = (Switch) mAccountSelectorView.findViewById(R.id.toggle);
mAccountProfileContainer.setOnClickListener(this);
mAccountsToggle.setOnCheckedChangeListener(this);
mAdapter.addView(mAccountSelectorView, false);
mAdapter.addAdapter(mAccountOptionsAdapter);
mAdapter.addView(mAppMenuSectionView, false);
mAdapter.addAdapter(mAppMenuAdapter);
setListAdapter(mAdapter);
mPreferences.registerOnSharedPreferenceChangeListener(this);
getLoaderManager().initLoader(0, null, this);
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return LayoutInflater.from(getThemedContext()).inflate(R.layout.fragment_accounts_drawer, container, false);
}
@Override
public void onStart() {
super.onStart();
@ -316,8 +362,21 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
return mThemedContext = new ContextThemeWrapper(context, themeResource);
}
private static TextView newSectionView(final Context context, final int titleRes) {
final TextView textView = new TextView(context, null, android.R.attr.listSeparatorTextViewStyle);
if (titleRes != 0) {
textView.setText(titleRes);
}
return textView;
}
private void onAccountSelected(ParcelableAccount account) {
mAccountsAdapter.setSelectedAccountId(account.account_id);
updateAccountOptionsSeparatorLabel();
}
private void updateAccountOptionsSeparatorLabel() {
final Account account = mAccountsAdapter.getSelectedAccount();
final ParcelableAccount account = mAccountsAdapter.getSelectedAccount();
if (account == null) {
return;
}
@ -329,43 +388,23 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
final Resources res = getResources();
final int defWidth = res.getDisplayMetrics().widthPixels;
final int width = bannerWidth > 0 ? bannerWidth : defWidth;
mImageLoader.displayProfileBanner(mAccountProfileBannerView, account.profile_banner_url, width);
final String bannerUrl = Utils.getBestBannerUrl(account.profile_banner_url, width);
final ImageView bannerView = mAccountProfileBannerView;
if (bannerView.getDrawable() == null || !CompareUtils.objectEquals(bannerUrl, bannerView.getTag())) {
mImageLoader.displayProfileBanner(mAccountProfileBannerView, bannerUrl, this);
}
}
private void updateDefaultAccountState() {
}
private static TextView newSectionView(final Context context, final int titleRes) {
final TextView textView = new TextView(context, null, android.R.attr.listSeparatorTextViewStyle);
if (titleRes != 0) {
textView.setText(titleRes);
}
return textView;
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
final Account account = mAccountsAdapter.getSelectedAccount();
if (account == null) return;
final ContentValues values = new ContentValues();
values.put(Accounts.IS_ACTIVATED, isChecked);
final String where = Accounts.ACCOUNT_ID + " = " + account.account_id;
mResolver.update(Accounts.CONTENT_URI, values, where, null);
}
public void setStatusBarHeight(int height) {
mAccountProfileContainer.setPadding(0, height, 0, 0);
}
private static final class AccountOptionsAdapter extends OptionItemsAdapter {
private static final ArrayList<OptionItem> sOptions = new ArrayList<>();
static {
sOptions.add(new OptionItem(R.string.profile, R.drawable.ic_action_profile, MENU_VIEW_PROFILE));
sOptions.add(new OptionItem(android.R.string.search_go, R.drawable.ic_action_search, MENU_SEARCH));
sOptions.add(new OptionItem(R.string.statuses, R.drawable.ic_action_quote, MENU_STATUSES));
sOptions.add(new OptionItem(R.string.compose, R.drawable.ic_action_status_compose, MENU_COMPOSE));
sOptions.add(new OptionItem(R.string.favorites, R.drawable.ic_action_star, MENU_FAVORITES));
sOptions.add(new OptionItem(R.string.lists, R.drawable.ic_action_list, MENU_LISTS));
}
@ -423,6 +462,36 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
mFragment = fragment;
}
public void changeCursor(Cursor cursor) {
mCursor = cursor;
if (cursor != null) {
mIndices = new Indices(cursor);
}
notifyDataSetChanged();
}
public ParcelableAccount getSelectedAccount() {
final Cursor c = mCursor;
final Indices i = mIndices;
if (c != null && i != null && c.moveToFirst()) {
while (!c.isAfterLast()) {
if (c.getLong(mIndices.account_id) == mSelectedAccountId)
return new ParcelableAccount(c, mIndices);
c.moveToNext();
}
}
return null;
}
public long getSelectedAccountId() {
return mSelectedAccountId;
}
public void setSelectedAccountId(long accountId) {
mSelectedAccountId = accountId;
notifyDataSetChanged();
}
@Override
public AccountProfileImageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = mInflater.inflate(R.layout.adapter_item_compose_account, parent, false);
@ -446,50 +515,15 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
return Math.max(mCursor.getCount() - 1, 0);
}
public void changeCursor(Cursor cursor) {
mCursor = cursor;
if (cursor != null) {
mIndices = new Indices(cursor);
}
notifyDataSetChanged();
}
public void setSelectedAccountId(long accountId) {
mSelectedAccountId = accountId;
notifyDataSetChanged();
}
public Account getSelectedAccount() {
final Cursor c = mCursor;
final Indices i = mIndices;
if (c != null && i != null && c.moveToFirst()) {
while (!c.isAfterLast()) {
if (c.getLong(mIndices.account_id) == mSelectedAccountId)
return new Account(c, mIndices);
c.moveToNext();
}
}
return null;
}
public long getSelectedAccountId() {
return mSelectedAccountId;
}
private void dispatchItemSelected(int position) {
final Cursor c = mCursor;
c.moveToPosition(position);
if (c.getLong(mIndices.account_id) != mSelectedAccountId || c.moveToNext()) {
mFragment.onAccountSelected(new Account(c, mIndices));
mFragment.onAccountSelected(new ParcelableAccount(c, mIndices));
}
}
}
private void onAccountSelected(Account account) {
mAccountsAdapter.setSelectedAccountId(account.account_id);
updateAccountOptionsSeparatorLabel();
}
private static class OptionItem {
private final int name, icon, id;

View File

@ -35,12 +35,12 @@ import android.widget.ListView;
import com.mobeta.android.dslv.DragSortListView;
import com.mobeta.android.dslv.DragSortListView.DropListener;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.ColorPickerDialogActivity;
import org.mariotaku.twidere.activity.support.SignInActivity;
import org.mariotaku.twidere.adapter.AccountsAdapter;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages.Inbox;
@ -61,7 +61,7 @@ public class AccountsManagerFragment extends BaseSupportListFragment implements
private AccountsAdapter mAdapter;
private SharedPreferences mPreferences;
private Account mSelectedAccount;
private ParcelableAccount mSelectedAccount;
@Override
public boolean onOptionsItemSelected(MenuItem item) {
@ -178,7 +178,7 @@ public class AccountsManagerFragment extends BaseSupportListFragment implements
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
if (!(menuInfo instanceof AdapterContextMenuInfo)) return;
final AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
final Account account = mAdapter.getAccount(info.position);
final ParcelableAccount account = mAdapter.getAccount(info.position);
menu.setHeaderTitle(account.name);
final MenuInflater inflater = new MenuInflater(v.getContext());
inflater.inflate(R.menu.action_manager_account, menu);
@ -258,7 +258,7 @@ public class AccountsManagerFragment extends BaseSupportListFragment implements
final long id = c.getLong(idIdx);
final ContentValues values = new ContentValues();
values.put(Accounts.SORT_POSITION, i);
final Where where = Where.equals(Accounts._ID, id);
final Expression where = Expression.equals(Accounts._ID, id);
cr.update(Accounts.CONTENT_URI, values, where.getSQL(), null);
}
}

View File

@ -1,211 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.mariotaku.refreshnow.widget.OnRefreshListener;
import org.mariotaku.refreshnow.widget.RefreshMode;
import org.mariotaku.refreshnow.widget.RefreshNowConfig;
import org.mariotaku.refreshnow.widget.RefreshNowProgressIndicator;
import org.mariotaku.refreshnow.widget.RefreshNowProgressIndicator.IndicatorConfig;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.iface.IBasePullToRefreshFragment;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.view.RefreshNowStaggeredGridView;
public abstract class BasePullToRefreshStaggeredGridFragment extends BaseSupportStaggeredGridFragment implements
IBasePullToRefreshFragment, OnTouchListener {
@Override
public RefreshNowStaggeredGridView getListView() {
return (RefreshNowStaggeredGridView) super.getListView();
}
@Override
public RefreshMode getRefreshMode() {
if (getView() == null) return RefreshMode.NONE;
return getListView().getRefreshMode();
}
@Override
public boolean isRefreshing() {
if (getView() == null) return false;
return getListView().isRefreshing();
}
/**
* Provide default implementation to return a simple list view. Subclasses
* can override to replace with their own layout. If doing so, the returned
* view hierarchy <em>must</em> have a ListView whose id is
* {@link android.R.id#list android.R.id.list} and can optionally have a
* sibling view id {@link android.R.id#empty android.R.id.empty} that is to
* be shown when the list is empty.
* <p>
* If you are overriding this method with your own custom content, consider
* including the standard layout {@link android.R.layout#list_content} in
* your layout file, so that you continue to retain all of the standard
* behavior of ListFragment. In particular, this is currently the only way
* to have the built-in indeterminant progress state be shown.
*/
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final Context context = getActivity();
final FrameLayout root = new FrameLayout(context);
// ------------------------------------------------------------------
final LinearLayout pframe = new LinearLayout(context);
pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID);
pframe.setOrientation(LinearLayout.VERTICAL);
pframe.setVisibility(View.GONE);
pframe.setGravity(Gravity.CENTER);
final ProgressBar progress = new ProgressBar(context, null, android.R.attr.progressBarStyleLarge);
pframe.addView(progress, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
root.addView(pframe, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
// ------------------------------------------------------------------
final FrameLayout lframe = new FrameLayout(context);
lframe.setId(INTERNAL_LIST_CONTAINER_ID);
final TextView tv = new TextView(getActivity());
tv.setId(INTERNAL_EMPTY_ID);
tv.setGravity(Gravity.CENTER);
lframe.addView(tv, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
final RefreshNowStaggeredGridView lv = (RefreshNowStaggeredGridView) inflater.inflate(
R.layout.refreshnow_staggered_gridview, lframe, false);
lv.setId(android.R.id.list);
lv.setDrawSelectorOnTop(false);
lv.setOnRefreshListener(this);
lv.setOnTouchListener(this);
lframe.addView(lv, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
final RefreshNowProgressIndicator indicator = new RefreshNowProgressIndicator(context);
final IndicatorConfig config = ThemeUtils.buildRefreshIndicatorConfig(context);
indicator.setConfig(config);
final int indicatorHeight = Math.round(3 * getResources().getDisplayMetrics().density);
lframe.addView(indicator, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, indicatorHeight,
Gravity.TOP));
lv.setRefreshIndicatorView(indicator);
root.addView(lframe, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
// ------------------------------------------------------------------
root.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
return root;
}
@Override
public void onRefreshComplete() {
}
@Override
public final void onRefreshStart(final RefreshMode mode) {
if (mode.hasStart()) {
onRefreshFromStart();
} else if (mode.hasEnd()) {
onRefreshFromEnd();
}
}
@Override
public final boolean onTouch(final View v, final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
onListTouched();
break;
}
}
return false;
}
@Override
public void setConfig(final RefreshNowConfig config) {
if (getView() == null) return;
getListView().setConfig(config);
}
@Override
public void setOnRefreshListener(final OnRefreshListener listener) {
}
@Override
public void setRefreshComplete() {
if (getView() == null) return;
getListView().setRefreshComplete();
}
@Override
public void setRefreshIndicatorView(final View view) {
if (getView() == null) return;
getListView().setRefreshIndicatorView(view);
}
@Override
public void setRefreshing(final boolean refresh) {
if (getView() == null) return;
getListView().setRefreshing(refresh);
}
@Override
public void setRefreshMode(final RefreshMode mode) {
if (getView() == null) return;
getListView().setRefreshMode(mode);
}
@Override
public boolean triggerRefresh() {
onRefreshFromStart();
setRefreshing(true);
return true;
}
protected void onListTouched() {
}
}

View File

@ -40,8 +40,8 @@ import android.widget.ListView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IBaseCardAdapter.MenuButtonClickListener;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.Account.AccountWithCredentials;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableAccount.ParcelableAccountWithCredentials;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.task.AsyncTask;
import org.mariotaku.twidere.util.AsyncTaskManager;
@ -345,9 +345,9 @@ abstract class BaseStatusesListFragment<Data> extends BasePullToRefreshListFragm
break;
}
case MENU_TRANSLATE: {
final AccountWithCredentials account = Account.getAccountWithCredentials(getActivity(),
final ParcelableAccountWithCredentials account = ParcelableAccount.getAccountWithCredentials(getActivity(),
status.account_id);
if (AccountWithCredentials.isOfficialCredentials(getActivity(), account)) {
if (ParcelableAccountWithCredentials.isOfficialCredentials(getActivity(), account)) {
StatusTranslateDialogFragment.show(getFragmentManager(), status);
} else {

View File

@ -1,578 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import com.etsy.android.grid.StaggeredGridView;
import org.mariotaku.menucomponent.widget.PopupMenu;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IBaseCardAdapter.MenuButtonClickListener;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.task.AsyncTask;
import org.mariotaku.twidere.util.AsyncTaskManager;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ClipboardUtils;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.PositionManager;
import org.mariotaku.twidere.util.TwitterWrapper;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.collection.NoDuplicatesCopyOnWriteArrayList;
import org.mariotaku.twidere.view.holder.StatusListViewHolder;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.mariotaku.twidere.util.Utils.cancelRetweet;
import static org.mariotaku.twidere.util.Utils.clearListViewChoices;
import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.isMyRetweet;
import static org.mariotaku.twidere.util.Utils.openStatus;
import static org.mariotaku.twidere.util.Utils.setMenuForStatus;
import static org.mariotaku.twidere.util.Utils.showOkMessage;
import static org.mariotaku.twidere.util.Utils.startStatusShareChooser;
abstract class BaseStatusesStaggeredGridFragment<Data> extends BasePullToRefreshStaggeredGridFragment implements
LoaderCallbacks<Data>, OnItemLongClickListener, OnMenuItemClickListener,
MultiSelectManager.Callback, MenuButtonClickListener {
private AsyncTaskManager mAsyncTaskManager;
private SharedPreferences mPreferences;
private StaggeredGridView mListView;
private IStatusesListAdapter<Data> mAdapter;
private PopupMenu mPopupMenu;
private Data mData;
private ParcelableStatus mSelectedStatus;
private boolean mLoadMoreAutomatically;
private int mListScrollOffset;
private MultiSelectManager mMultiSelectManager;
private PositionManager mPositionManager;
private int mFirstVisibleItem;
private int mSelectedPosition;
private final Map<Long, Set<Long>> mUnreadCountsToRemove = Collections
.synchronizedMap(new HashMap<Long, Set<Long>>());
private final List<Integer> mReadPositions = new NoDuplicatesCopyOnWriteArrayList<Integer>();
private RemoveUnreadCountsTask<Data> mRemoveUnreadCountsTask;
public AsyncTaskManager getAsyncTaskManager() {
return mAsyncTaskManager;
}
public final Data getData() {
return mData;
}
@Override
public IStatusesListAdapter<Data> getListAdapter() {
return mAdapter;
}
public ParcelableStatus getSelectedStatus() {
return mSelectedStatus;
}
public SharedPreferences getSharedPreferences() {
return mPreferences;
}
public abstract int getStatuses(long[] account_ids, long[] max_ids, long[] since_ids);
public final Map<Long, Set<Long>> getUnreadCountsToRemove() {
return mUnreadCountsToRemove;
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAsyncTaskManager = getAsyncTaskManager();
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mPositionManager = new PositionManager(getActivity());
mMultiSelectManager = getMultiSelectManager();
mListView = getListView();
mAdapter = newAdapterInstance();
mAdapter.setMenuButtonClickListener(this);
setListAdapter(null);
setListHeaderFooters(mListView);
setListAdapter(mAdapter);
mListView.setSelector(android.R.color.transparent);
mListView.setOnItemLongClickListener(this);
setListShown(false);
getLoaderManager().initLoader(0, getArguments(), this);
}
@Override
public abstract Loader<Data> onCreateLoader(int id, Bundle args);
@Override
public boolean onItemLongClick(final AdapterView<?> parent, final View view, final int position, final long id) {
final Object tag = view.getTag();
if (tag instanceof StatusListViewHolder) {
final StatusListViewHolder holder = (StatusListViewHolder) tag;
final ParcelableStatus status = mAdapter.getStatus(position - mListView.getHeaderViewsCount());
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter != null) {
TwitterWrapper.removeUnreadCounts(getActivity(), getTabPosition(), status.account_id, status.id);
}
if (holder.show_as_gap) return false;
if (mPreferences.getBoolean(KEY_LONG_CLICK_TO_OPEN_MENU, false)) {
openMenu(holder.content.getFakeOverflowButton(), status, position);
} else {
setItemSelected(status, position, !mMultiSelectManager.isSelected(status));
}
return true;
}
return false;
}
@Override
public void onItemsCleared() {
clearListViewChoices(mListView);
}
@Override
public void onItemSelected(final Object item) {
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
@Override
public void onItemUnselected(final Object item) {
}
@Override
public void onListItemClick(final StaggeredGridView l, final View v, final int position, final long id) {
final Object tag = v.getTag();
if (tag instanceof StatusListViewHolder) {
final int pos = position - l.getHeaderViewsCount();
final ParcelableStatus status = mAdapter.getStatus(pos);
if (status == null) return;
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter != null) {
TwitterWrapper.removeUnreadCounts(getActivity(), getTabPosition(), status.account_id, status.id);
}
if (((StatusListViewHolder) tag).show_as_gap) {
final long since_id = position + 1 < mAdapter.getStatusCount() ? mAdapter.getStatus(pos + 1).id : -1;
getStatuses(new long[]{status.account_id}, new long[]{status.id}, new long[]{since_id});
mListView.setItemChecked(position, false);
} else {
if (mMultiSelectManager.isActive()) {
setItemSelected(status, position, !mMultiSelectManager.isSelected(status));
return;
}
openStatus(getActivity(), status, null);
}
}
}
@Override
public final void onLoaderReset(final Loader<Data> loader) {
mAdapter.setData(mData = null);
}
@Override
public final void onLoadFinished(final Loader<Data> loader, final Data data) {
if (getActivity() == null || getView() == null) return;
setListShown(true);
setRefreshComplete();
setProgressBarIndeterminateVisibility(false);
setData(data);
mFirstVisibleItem = -1;
mReadPositions.clear();
final int listVisiblePosition, savedChildIndex;
final boolean rememberPosition = mPreferences.getBoolean(KEY_REMEMBER_POSITION, true);
if (rememberPosition) {
listVisiblePosition = mListView.getLastVisiblePosition();
final int childCount = mListView.getChildCount();
savedChildIndex = childCount - 1;
if (childCount > 0) {
final View lastChild = mListView.getChildAt(savedChildIndex);
mListScrollOffset = lastChild != null ? lastChild.getTop() : 0;
}
} else {
listVisiblePosition = mListView.getFirstVisiblePosition();
savedChildIndex = 0;
if (mListView.getChildCount() > 0) {
final View firstChild = mListView.getChildAt(savedChildIndex);
mListScrollOffset = firstChild != null ? firstChild.getTop() : 0;
}
}
final long lastViewedId = mAdapter.getStatusId(listVisiblePosition);
mAdapter.setData(data);
mAdapter.setShowAccountColor(shouldShowAccountColor());
final int currFirstVisiblePosition = mListView.getFirstVisiblePosition();
final long currViewedId = mAdapter.getStatusId(currFirstVisiblePosition);
final long statusId;
if (lastViewedId <= 0) {
if (!rememberPosition) return;
statusId = mPositionManager.getPosition(getPositionKey());
} else if ((listVisiblePosition > 0 || rememberPosition) && currViewedId > 0 && lastViewedId != currViewedId) {
statusId = lastViewedId;
} else {
if (listVisiblePosition == 0 && mAdapter.getStatusId(0) != lastViewedId) {
mAdapter.setMaxAnimationPosition(mListView.getLastVisiblePosition());
}
return;
}
final int position = mAdapter.findPositionByStatusId(statusId);
if (position > -1 && position < mListView.getCount()) {
mAdapter.setMaxAnimationPosition(mListView.getLastVisiblePosition());
// mListView.setSelectionFromTop(position, mListScrollOffset);
mListView.setSelection(position);
mListScrollOffset = 0;
}
}
@Override
public void onMenuButtonClick(final View button, final int position, final long id) {
if (mMultiSelectManager.isActive()) return;
final ParcelableStatus status = mAdapter.getStatus(position);
if (status == null) return;
openMenu(button, status, position);
}
@Override
public final boolean onMenuItemClick(final MenuItem item) {
final ParcelableStatus status = mSelectedStatus;
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (status == null || twitter == null) return false;
switch (item.getItemId()) {
case MENU_VIEW: {
openStatus(getActivity(), status, null);
break;
}
case MENU_SHARE: {
startStatusShareChooser(getActivity(), status);
break;
}
case MENU_COPY: {
if (ClipboardUtils.setText(getActivity(), status.text_plain)) {
showOkMessage(getActivity(), R.string.text_copied, false);
}
break;
}
case MENU_RETWEET: {
if (isMyRetweet(status)) {
cancelRetweet(twitter, status);
} else {
final long id_to_retweet = status.retweet_id > 0 ? status.retweet_id : status.id;
twitter.retweetStatus(status.account_id, id_to_retweet);
}
break;
}
case MENU_QUOTE: {
final Intent intent = new Intent(INTENT_ACTION_QUOTE);
final Bundle bundle = new Bundle();
bundle.putParcelable(EXTRA_STATUS, status);
intent.putExtras(bundle);
startActivity(intent);
break;
}
case MENU_REPLY: {
final Intent intent = new Intent(INTENT_ACTION_REPLY);
final Bundle bundle = new Bundle();
bundle.putParcelable(EXTRA_STATUS, status);
intent.putExtras(bundle);
startActivity(intent);
break;
}
case MENU_FAVORITE: {
if (status.is_favorite) {
twitter.destroyFavoriteAsync(status.account_id, status.id);
} else {
twitter.createFavoriteAsync(status.account_id, status.id);
}
break;
}
case MENU_DELETE: {
twitter.destroyStatusAsync(status.account_id, status.id);
break;
}
case MENU_ADD_TO_FILTER: {
AddStatusFilterDialogFragment.show(getFragmentManager(), status);
break;
}
case MENU_MULTI_SELECT: {
final boolean isSelected = !mMultiSelectManager.isSelected(status);
setItemSelected(status, mSelectedPosition, isSelected);
break;
}
default: {
if (item.getIntent() != null) {
try {
startActivity(item.getIntent());
} catch (final ActivityNotFoundException e) {
Log.w(LOGTAG, e);
return false;
}
}
break;
}
}
return true;
}
@Override
public void onRefreshFromEnd() {
if (mLoadMoreAutomatically) return;
loadMoreStatuses();
}
@Override
public void onResume() {
super.onResume();
mListView.setFastScrollEnabled(mPreferences.getBoolean(KEY_FAST_SCROLL_THUMB, false));
configBaseCardAdapter(getActivity(), mAdapter);
final boolean display_image_preview = mPreferences.getBoolean(KEY_DISPLAY_IMAGE_PREVIEW, false);
final boolean display_sensitive_contents = mPreferences.getBoolean(KEY_DISPLAY_SENSITIVE_CONTENTS, false);
final boolean indicate_my_status = mPreferences.getBoolean(KEY_INDICATE_MY_STATUS, true);
mAdapter.setDisplayImagePreview(display_image_preview);
mAdapter.setDisplaySensitiveContents(display_sensitive_contents);
mAdapter.setIndicateMyStatusDisabled(isMyTimeline() || !indicate_my_status);
mLoadMoreAutomatically = mPreferences.getBoolean(KEY_LOAD_MORE_AUTOMATICALLY, false);
}
@Override
public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,
final int totalItemCount) {
super.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
addReadPosition(firstVisibleItem);
}
@Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
super.onScrollStateChanged(view, scrollState);
switch (scrollState) {
case SCROLL_STATE_IDLE:
for (int i = mListView.getFirstVisiblePosition(), j = mListView.getLastVisiblePosition(); i < j; i++) {
mReadPositions.add(i);
}
removeUnreadCounts();
break;
default:
break;
}
}
@Override
public void onStart() {
super.onStart();
mMultiSelectManager.registerCallback(this);
final int choiceMode = mListView.getChoiceMode();
if (mMultiSelectManager.isActive()) {
if (choiceMode != ListView.CHOICE_MODE_MULTIPLE) {
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
} else {
if (choiceMode != ListView.CHOICE_MODE_NONE) {
Utils.clearListViewChoices(mListView);
}
}
}
@Override
public void onStop() {
savePosition();
mMultiSelectManager.unregisterCallback(this);
if (mPopupMenu != null) {
mPopupMenu.dismiss();
}
super.onStop();
}
@Override
public boolean scrollToStart() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
final int tab_position = getTabPosition();
if (twitter != null && tab_position >= 0) {
twitter.clearUnreadCountAsync(tab_position);
}
return super.scrollToStart();
}
@Override
public void setUserVisibleHint(final boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
updateRefreshState();
}
protected final int getListScrollOffset() {
return mListScrollOffset;
}
protected abstract long[] getNewestStatusIds();
protected abstract long[] getOldestStatusIds();
protected abstract String getPositionKey();
protected boolean isMyTimeline() {
return false;
}
protected abstract void loadMoreStatuses();
protected abstract IStatusesListAdapter<Data> newAdapterInstance();
@Override
protected void onReachedBottom() {
if (!mLoadMoreAutomatically) return;
loadMoreStatuses();
}
protected void savePosition() {
final int first_visible_position = mListView.getFirstVisiblePosition();
if (mListView.getChildCount() > 0) {
final View first_child = mListView.getChildAt(0);
mListScrollOffset = first_child != null ? first_child.getTop() : 0;
}
final long status_id = mAdapter.getStatusId(first_visible_position);
mPositionManager.setPosition(getPositionKey(), status_id);
}
protected final void setData(final Data data) {
mData = data;
}
protected void setItemSelected(final ParcelableStatus status, final int position, final boolean selected) {
if (selected) {
mMultiSelectManager.selectItem(status);
} else {
mMultiSelectManager.unselectItem(status);
}
if (position >= 0) {
mListView.setItemChecked(position, selected);
}
}
protected void setListHeaderFooters(final StaggeredGridView list) {
}
protected boolean shouldEnablePullToRefresh() {
return true;
}
protected abstract boolean shouldShowAccountColor();
protected abstract void updateRefreshState();
private void addReadPosition(final int firstVisibleItem) {
if (mFirstVisibleItem != firstVisibleItem) {
mReadPositions.add(firstVisibleItem);
}
mFirstVisibleItem = firstVisibleItem;
}
private void addUnreadCountsToRemove(final long account_id, final long id) {
if (mUnreadCountsToRemove.containsKey(account_id)) {
final Set<Long> counts = mUnreadCountsToRemove.get(account_id);
counts.add(id);
} else {
final Set<Long> counts = new HashSet<Long>();
counts.add(id);
mUnreadCountsToRemove.put(account_id, counts);
}
}
private void openMenu(final View view, final ParcelableStatus status, final int position) {
mSelectedStatus = status;
mSelectedPosition = position;
if (view == null || status == null) return;
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter != null) {
TwitterWrapper.removeUnreadCounts(getActivity(), getTabPosition(), status.account_id, status.id);
}
if (mPopupMenu != null && mPopupMenu.isShowing()) {
mPopupMenu.dismiss();
}
mPopupMenu = PopupMenu.getInstance(getActivity(), view);
mPopupMenu.inflate(R.menu.action_status);
final boolean longclickToOpenMenu = mPreferences.getBoolean(KEY_LONG_CLICK_TO_OPEN_MENU, false);
final Menu menu = mPopupMenu.getMenu();
setMenuForStatus(getActivity(), menu, status);
Utils.setMenuItemAvailability(menu, MENU_MULTI_SELECT, longclickToOpenMenu);
mPopupMenu.setOnMenuItemClickListener(this);
mPopupMenu.show();
}
private void removeUnreadCounts() {
if (mRemoveUnreadCountsTask != null && mRemoveUnreadCountsTask.getStatus() == AsyncTask.Status.RUNNING)
return;
mRemoveUnreadCountsTask = new RemoveUnreadCountsTask<Data>(mReadPositions, this);
mRemoveUnreadCountsTask.execute();
}
static class RemoveUnreadCountsTask<T> extends AsyncTask<Void, Void, Void> {
private final List<Integer> read_positions;
private final IStatusesListAdapter<T> adapter;
private final BaseStatusesStaggeredGridFragment<T> fragment;
RemoveUnreadCountsTask(final List<Integer> read_positions, final BaseStatusesStaggeredGridFragment<T> fragment) {
this.read_positions = read_positions;
this.fragment = fragment;
this.adapter = fragment.getListAdapter();
}
@Override
protected Void doInBackground(final Void... params) {
for (final int pos : read_positions) {
final long id = adapter.getStatusId(pos), account_id = adapter.getAccountId(pos);
fragment.addUnreadCountsToRemove(account_id, id);
}
return null;
}
@Override
protected void onPostExecute(final Void result) {
final AsyncTwitterWrapper twitter = fragment.getTwitterWrapper();
if (twitter != null) {
twitter.removeUnreadCountsAsync(fragment.getTabPosition(), fragment.getUnreadCountsToRemove());
}
}
}
}

View File

@ -114,7 +114,8 @@ public class BaseSupportFragment extends Fragment implements IBaseFragment, Cons
@Override
public int getTabPosition() {
return 0;
final Bundle args = getArguments();
return args != null ? args.getInt(EXTRA_TAB_POSITION, -1) : -1;
}
@Override

View File

@ -1,277 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import com.etsy.android.grid.StaggeredGridView;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.activity.support.HomeActivity;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.iface.IBaseFragment;
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.Utils;
public class BaseSupportStaggeredGridFragment extends StaggeredGridFragment implements IBaseFragment, Constants,
OnScrollListener, RefreshScrollTopInterface {
private boolean mActivityFirstCreated;
private boolean mIsInstanceStateSaved;
private boolean mReachedBottom, mNotReachedBottomBefore = true;
@Override
public void requestFitSystemWindows() {
final Activity activity = getActivity();
final Fragment parentFragment = getParentFragment();
final SystemWindowsInsetsCallback callback;
if (parentFragment instanceof SystemWindowsInsetsCallback) {
callback = (SystemWindowsInsetsCallback) parentFragment;
} else if (activity instanceof SystemWindowsInsetsCallback) {
callback = (SystemWindowsInsetsCallback) activity;
} else {
return;
}
final Rect insets = new Rect();
if (callback.getSystemWindowsInsets(insets)) {
fitSystemWindows(insets);
}
}
protected void fitSystemWindows(Rect insets) {
}
public final TwidereApplication getApplication() {
return TwidereApplication.getInstance(getActivity());
}
public final ContentResolver getContentResolver() {
final Activity activity = getActivity();
if (activity != null) return activity.getContentResolver();
return null;
}
@Override
public Bundle getExtraConfiguration() {
final Bundle args = getArguments();
final Bundle extras = new Bundle();
if (args != null && args.containsKey(EXTRA_EXTRAS)) {
extras.putAll(args.getBundle(EXTRA_EXTRAS));
}
return extras;
}
public final MultiSelectManager getMultiSelectManager() {
return getApplication() != null ? getApplication().getMultiSelectManager() : null;
}
public final SharedPreferences getSharedPreferences(final String name, final int mode) {
final Activity activity = getActivity();
if (activity != null) return activity.getSharedPreferences(name, mode);
return null;
}
public final Object getSystemService(final String name) {
final Activity activity = getActivity();
if (activity != null) return activity.getSystemService(name);
return null;
}
@Override
public final int getTabPosition() {
final Bundle args = getArguments();
return args != null ? args.getInt(EXTRA_TAB_POSITION, -1) : -1;
}
public AsyncTwitterWrapper getTwitterWrapper() {
return getApplication() != null ? getApplication().getTwitterWrapper() : null;
}
public void invalidateOptionsMenu() {
final Activity activity = getActivity();
if (activity == null) return;
activity.invalidateOptionsMenu();
}
public boolean isActivityFirstCreated() {
return mActivityFirstCreated;
}
public boolean isInstanceStateSaved() {
return mIsInstanceStateSaved;
}
public boolean isReachedBottom() {
return mReachedBottom;
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mIsInstanceStateSaved = savedInstanceState != null;
final StaggeredGridView lv = getListView();
lv.setOnScrollListener(this);
}
@Override
public void onAttach(final Activity activity) {
super.onAttach(activity);
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivityFirstCreated = true;
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onDestroy() {
super.onDestroy();
mActivityFirstCreated = true;
}
@Override
public void onDetach() {
super.onDetach();
final Fragment fragment = getParentFragment();
if (fragment instanceof SupportFragmentCallback) {
((SupportFragmentCallback) fragment).onDetachFragment(this);
}
final Activity activity = getActivity();
if (activity instanceof SupportFragmentCallback) {
((SupportFragmentCallback) activity).onDetachFragment(this);
}
}
public void onPostStart() {
}
@Override
public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,
final int totalItemCount) {
final boolean reached = firstVisibleItem + visibleItemCount >= totalItemCount
&& totalItemCount >= visibleItemCount;
if (mReachedBottom != reached) {
mReachedBottom = reached;
if (mReachedBottom && mNotReachedBottomBefore) {
mNotReachedBottomBefore = false;
return;
}
if (mReachedBottom && getListAdapter().getCount() > visibleItemCount) {
onReachedBottom();
}
}
}
@Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
}
@Override
public void onStart() {
super.onStart();
onPostStart();
}
@Override
public void onStop() {
mActivityFirstCreated = false;
super.onStop();
}
public void registerReceiver(final BroadcastReceiver receiver, final IntentFilter filter) {
final Activity activity = getActivity();
if (activity == null) return;
activity.registerReceiver(receiver, filter);
}
@Override
public boolean scrollToStart() {
if (!isAdded() || getActivity() == null) return false;
Utils.scrollListToTop(getListView());
return true;
}
public void setProgressBarIndeterminateVisibility(final boolean visible) {
final Activity activity = getActivity();
if (activity == null) return;
activity.setProgressBarIndeterminateVisibility(visible);
if (activity instanceof HomeActivity) {
((HomeActivity) activity).setHomeProgressBarIndeterminateVisibility(visible);
}
}
@Override
public void setSelection(final int position) {
Utils.scrollListToPosition(getListView(), position);
}
@Override
public void setUserVisibleHint(final boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
final Activity activity = getActivity();
final Fragment fragment = getParentFragment();
if (fragment instanceof SupportFragmentCallback) {
((SupportFragmentCallback) fragment).onSetUserVisibleHint(this, isVisibleToUser);
}
if (activity instanceof SupportFragmentCallback) {
((SupportFragmentCallback) activity).onSetUserVisibleHint(this, isVisibleToUser);
}
}
@Override
public boolean triggerRefresh() {
return false;
}
public void unregisterReceiver(final BroadcastReceiver receiver) {
final Activity activity = getActivity();
if (activity == null) return;
activity.unregisterReceiver(receiver);
}
protected void onReachedBottom() {
}
}

View File

@ -20,18 +20,134 @@
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.twidere.adapter.CursorStatusesAdapter;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.task.AsyncTask;
import org.mariotaku.twidere.util.Utils;
import static org.mariotaku.twidere.util.Utils.buildStatusFilterWhereClause;
import static org.mariotaku.twidere.util.Utils.getNewestStatusIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getOldestStatusIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getTableNameByUri;
import static org.mariotaku.twidere.util.Utils.shouldEnableFiltersForRTs;
/**
* Created by mariotaku on 14/12/3.
*/
public abstract class CursorStatusesFragment extends AbsStatusesFragment<Cursor> {
public abstract Uri getContentUri();
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
final Context context = getActivity();
final Uri uri = getContentUri();
final String table = getTableNameByUri(uri);
final String sortOrder = getSortOrder();
final long[] accountIds = getAccountIds();
final Expression accountWhere = Expression.in(new Column(Statuses.ACCOUNT_ID), new RawItemArray(accountIds));
final Expression filterWhere = getFiltersWhere(table), where;
if (filterWhere != null) {
where = Expression.and(accountWhere, filterWhere);
} else {
where = accountWhere;
}
final String selection = processWhere(where).getSQL();
return new CursorLoader(context, uri, Statuses.COLUMNS, selection, null, sortOrder);
}
@Override
public boolean triggerRefresh() {
new AsyncTask<Void, Void, long[][]>() {
@Override
protected long[][] doInBackground(final Void... params) {
final long[][] result = new long[3][];
result[0] = getAccountIds();
result[2] = getNewestStatusIds(result[0]);
return result;
}
@Override
protected void onPostExecute(final long[][] result) {
getStatuses(result[0], result[1], result[2]);
}
}.execute();
return true;
}
@Override
protected long[] getAccountIds() {
final Bundle args = getArguments();
if (args != null && args.getLong(EXTRA_ACCOUNT_ID) > 0) {
return new long[]{args.getLong(EXTRA_ACCOUNT_ID)};
}
return Utils.getActivatedAccountIds(getActivity());
}
protected abstract int getNotificationType();
@Override
protected CursorStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new CursorStatusesAdapter(context, compact);
}
@Override
protected void onLoadMoreStatuses() {
new AsyncTask<Void, Void, long[][]>() {
@Override
protected long[][] doInBackground(final Void... params) {
final long[][] result = new long[3][];
result[0] = getAccountIds();
result[1] = getOldestStatusIds(result[0]);
return result;
}
@Override
protected void onPostExecute(final long[][] result) {
getStatuses(result[0], result[1], result[2]);
}
}.execute();
}
protected Expression getFiltersWhere(String table) {
if (!isFilterEnabled()) return null;
return buildStatusFilterWhereClause(table, null, shouldEnableFiltersForRTs(getActivity()));
}
protected abstract boolean isFilterEnabled();
protected long[] getNewestStatusIds(long[] accountIds) {
return getNewestStatusIdsFromDatabase(getActivity(), getContentUri(), accountIds);
}
protected long[] getOldestStatusIds(long[] accountIds) {
return getOldestStatusIdsFromDatabase(getActivity(), getContentUri(), accountIds);
}
protected Expression processWhere(final Expression where) {
return where;
}
private String getSortOrder() {
final SharedPreferences preferences = getSharedPreferences();
final boolean sortById = preferences.getBoolean(KEY_SORT_TIMELINE_BY_ID, false);
return sortById ? Statuses.SORT_ORDER_STATUS_ID_DESC : Statuses.SORT_ORDER_TIMESTAMP_DESC;
}
}

View File

@ -1,229 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.widget.AbsListView;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.HomeActivity;
import org.mariotaku.twidere.adapter.CursorStatusesListAdapter;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.provider.TweetStore.Filters;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.task.AsyncTask;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.content.SupportFragmentReloadCursorObserver;
import static org.mariotaku.twidere.util.Utils.buildStatusFilterWhereClause;
import static org.mariotaku.twidere.util.Utils.getActivatedAccountIds;
import static org.mariotaku.twidere.util.Utils.getNewestStatusIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getOldestStatusIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getTableNameByUri;
import static org.mariotaku.twidere.util.Utils.shouldEnableFiltersForRTs;
public abstract class CursorStatusesListFragment extends BaseStatusesListFragment<Cursor> {
private final SupportFragmentReloadCursorObserver mReloadContentObserver = new SupportFragmentReloadCursorObserver(
this, 0, this);
public HomeActivity getHomeActivity() {
final Activity activity = getActivity();
if (activity instanceof HomeActivity) return (HomeActivity) activity;
return null;
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListAdapter().setFiltersEnabled(isFiltersEnabled());
}
@Override
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
final Context context = getActivity();
final SharedPreferences preferences = getSharedPreferences();
final boolean sortById = preferences.getBoolean(KEY_SORT_TIMELINE_BY_ID, false);
final Uri uri = getContentUri();
final String table = getTableNameByUri(uri);
final String sortOrder = sortById ? Statuses.SORT_ORDER_STATUS_ID_DESC : Statuses.SORT_ORDER_TIMESTAMP_DESC;
final long accountId = getAccountId();
final long[] accountIds = accountId > 0 ? new long[]{accountId} : getActivatedAccountIds(context);
final boolean noAccountSelected = accountIds.length == 0;
setEmptyText(noAccountSelected ? getString(R.string.no_account_selected) : null);
if (!noAccountSelected) {
getListView().setEmptyView(null);
}
final Where accountWhere = Where.in(new Column(Statuses.ACCOUNT_ID), new RawItemArray(accountIds));
final Where where;
if (isFiltersEnabled()) {
final Where filterWhere = new Where(buildStatusFilterWhereClause(table, null,
shouldEnableFiltersForRTs(context)));
where = Where.and(accountWhere, filterWhere);
} else {
where = accountWhere;
}
final String selection = processWhere(where).getSQL();
return new CursorLoader(context, uri, CursorStatusesListAdapter.CURSOR_COLS, selection, null, sortOrder);
}
@Override
public void onRefreshFromStart() {
if (isRefreshing()) return;
savePosition();
new AsyncTask<Void, Void, long[][]>() {
@Override
protected long[][] doInBackground(final Void... params) {
final long[][] result = new long[3][];
final long account_id = getAccountId();
result[0] = account_id > 0 ? new long[]{account_id} : getActivatedAccountIds(getActivity());
result[2] = getNewestStatusIds();
return result;
}
@Override
protected void onPostExecute(final long[][] result) {
getStatuses(result[0], result[1], result[2]);
}
}.execute();
}
@Override
public void onRestart() {
super.onRestart();
getLoaderManager().restartLoader(0, getArguments(), this);
}
@Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
super.onScrollStateChanged(view, scrollState);
switch (scrollState) {
case SCROLL_STATE_FLING:
case SCROLL_STATE_TOUCH_SCROLL: {
break;
}
case SCROLL_STATE_IDLE: {
savePosition();
break;
}
}
}
@Override
public void onStart() {
super.onStart();
final ContentResolver resolver = getContentResolver();
resolver.registerContentObserver(Filters.CONTENT_URI, true, mReloadContentObserver);
if (getAccountId() <= 0) {
resolver.registerContentObserver(Accounts.CONTENT_URI, true, mReloadContentObserver);
}
}
@Override
public void onStop() {
savePosition();
final ContentResolver resolver = getContentResolver();
resolver.unregisterContentObserver(mReloadContentObserver);
super.onStop();
}
protected long getAccountId() {
final Bundle args = getArguments();
return args != null ? args.getLong(EXTRA_ACCOUNT_ID, -1) : -1;
}
protected abstract Uri getContentUri();
@Override
protected long[] getNewestStatusIds() {
final long account_id = getAccountId();
final long[] account_ids = account_id > 0 ? new long[]{account_id} : getActivatedAccountIds(getActivity());
return getNewestStatusIdsFromDatabase(getActivity(), getContentUri(), account_ids);
}
protected abstract int getNotificationType();
@Override
protected long[] getOldestStatusIds() {
final long account_id = getAccountId();
final long[] account_ids = account_id > 0 ? new long[]{account_id} : getActivatedAccountIds(getActivity());
return getOldestStatusIdsFromDatabase(getActivity(), getContentUri(), account_ids);
}
protected abstract boolean isFiltersEnabled();
@Override
protected void loadMoreStatuses() {
if (isRefreshing()) return;
savePosition();
new AsyncTask<Void, Void, long[][]>() {
@Override
protected long[][] doInBackground(final Void... params) {
final long[][] result = new long[3][];
final long account_id = getAccountId();
result[0] = account_id > 0 ? new long[]{account_id} : getActivatedAccountIds(getActivity());
result[1] = getOldestStatusIds();
return result;
}
@Override
protected void onPostExecute(final long[][] result) {
getStatuses(result[0], result[1], result[2]);
}
}.execute();
}
@Override
protected CursorStatusesListAdapter newAdapterInstance(final boolean compact) {
return new CursorStatusesListAdapter(getActivity(), compact);
}
@Override
protected void onListTouched() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter != null) {
twitter.clearNotificationAsync(getNotificationType(), getAccountId());
}
}
protected Where processWhere(final Where where) {
return where;
}
@Override
protected boolean shouldShowAccountColor() {
return getAccountId() <= 0 && getActivatedAccountIds(getActivity()).length > 1;
}
}

View File

@ -1,213 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import static org.mariotaku.twidere.util.Utils.buildStatusFilterWhereClause;
import static org.mariotaku.twidere.util.Utils.getActivatedAccountIds;
import static org.mariotaku.twidere.util.Utils.getNewestStatusIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getOldestStatusIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getTableNameByUri;
import static org.mariotaku.twidere.util.Utils.shouldEnableFiltersForRTs;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.widget.AbsListView;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.HomeActivity;
import org.mariotaku.twidere.adapter.CursorStatusesListAdapter;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.provider.TweetStore.Filters;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.task.AsyncTask;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.content.SupportFragmentReloadCursorObserver;
public abstract class CursorStatusesStaggeredGridFragment extends BaseStatusesStaggeredGridFragment<Cursor> {
private final SupportFragmentReloadCursorObserver mReloadContentObserver = new SupportFragmentReloadCursorObserver(
this, 0, this);
public HomeActivity getHomeActivity() {
final Activity activity = getActivity();
if (activity instanceof HomeActivity) return (HomeActivity) activity;
return null;
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListAdapter().setFiltersEnabled(isFiltersEnabled());
}
@Override
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
final Uri uri = getContentUri();
final String table = getTableNameByUri(uri);
final String sort_by = Statuses.DEFAULT_SORT_ORDER;
final long account_id = getAccountId();
final long[] account_ids = account_id > 0 ? new long[] { account_id } : getActivatedAccountIds(getActivity());
final boolean no_account_selected = account_ids.length == 0;
setEmptyText(no_account_selected ? getString(R.string.no_account_selected) : null);
if (!no_account_selected) {
getListView().setEmptyView(null);
}
final Where accountWhere = Where.in(new Column(Statuses.ACCOUNT_ID), new RawItemArray(account_ids));
final Where where;
if (isFiltersEnabled()) {
final Where filterWhere = new Where(buildStatusFilterWhereClause(table, null,
shouldEnableFiltersForRTs(getActivity())));
where = Where.and(accountWhere, filterWhere);
} else {
where = accountWhere;
}
return new CursorLoader(getActivity(), uri, CursorStatusesListAdapter.CURSOR_COLS, where.getSQL(), null, sort_by);
}
@Override
public void onRefreshFromStart() {
if (isRefreshing()) return;
savePosition();
new AsyncTask<Void, Void, long[][]>() {
@Override
protected long[][] doInBackground(final Void... params) {
final long[][] result = new long[3][];
final long account_id = getAccountId();
result[0] = account_id > 0 ? new long[] { account_id } : getActivatedAccountIds(getActivity());
result[2] = getNewestStatusIds();
return result;
}
@Override
protected void onPostExecute(final long[][] result) {
getStatuses(result[0], result[1], result[2]);
}
}.execute();
}
@Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
super.onScrollStateChanged(view, scrollState);
switch (scrollState) {
case SCROLL_STATE_FLING:
case SCROLL_STATE_TOUCH_SCROLL: {
break;
}
case SCROLL_STATE_IDLE: {
savePosition();
break;
}
}
}
@Override
public void onStart() {
super.onStart();
final ContentResolver resolver = getContentResolver();
resolver.registerContentObserver(Filters.CONTENT_URI, true, mReloadContentObserver);
if (getAccountId() <= 0) {
resolver.registerContentObserver(Accounts.CONTENT_URI, true, mReloadContentObserver);
}
}
@Override
public void onStop() {
savePosition();
final ContentResolver resolver = getContentResolver();
resolver.unregisterContentObserver(mReloadContentObserver);
super.onStop();
}
protected long getAccountId() {
final Bundle args = getArguments();
return args != null ? args.getLong(EXTRA_ACCOUNT_ID, -1) : -1;
}
protected abstract Uri getContentUri();
@Override
protected long[] getNewestStatusIds() {
final long account_id = getAccountId();
final long[] account_ids = account_id > 0 ? new long[] { account_id } : getActivatedAccountIds(getActivity());
return getNewestStatusIdsFromDatabase(getActivity(), getContentUri(), account_ids);
}
protected abstract int getNotificationType();
@Override
protected long[] getOldestStatusIds() {
final long account_id = getAccountId();
final long[] account_ids = account_id > 0 ? new long[] { account_id } : getActivatedAccountIds(getActivity());
return getOldestStatusIdsFromDatabase(getActivity(), getContentUri(), account_ids);
}
protected abstract boolean isFiltersEnabled();
@Override
protected void loadMoreStatuses() {
if (isRefreshing()) return;
savePosition();
new AsyncTask<Void, Void, long[][]>() {
@Override
protected long[][] doInBackground(final Void... params) {
final long[][] result = new long[3][];
final long account_id = getAccountId();
result[0] = account_id > 0 ? new long[] { account_id } : getActivatedAccountIds(getActivity());
result[1] = getOldestStatusIds();
return result;
}
@Override
protected void onPostExecute(final long[][] result) {
getStatuses(result[0], result[1], result[2]);
}
}.execute();
}
@Override
protected CursorStatusesListAdapter newAdapterInstance() {
return new CursorStatusesListAdapter(getActivity());
}
@Override
protected void onListTouched() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter != null) {
twitter.clearNotificationAsync(getNotificationType(), getAccountId());
}
}
@Override
protected boolean shouldShowAccountColor() {
return getAccountId() <= 0 && getActivatedAccountIds(getActivity()).length > 1;
}
}

View File

@ -64,7 +64,7 @@ import org.mariotaku.twidere.adapter.AccountsSpinnerAdapter;
import org.mariotaku.twidere.adapter.DirectMessagesConversationAdapter;
import org.mariotaku.twidere.adapter.iface.IBaseCardAdapter.MenuButtonClickListener;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableDirectMessage;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.provider.TweetStore;
@ -134,7 +134,7 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
}
};
private Account mSender;
private ParcelableAccount mSender;
private ParcelableUser mRecipient;
private ImageLoaderWrapper mImageLoader;
private IColorLabelView mProfileImageContainer;
@ -174,7 +174,7 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
}
mEditText.addTextChangedListener(this);
final List<Account> accounts = Account.getAccountsList(getActivity(), false);
final List<ParcelableAccount> accounts = ParcelableAccount.getAccountsList(getActivity(), false);
mAccountSpinner.setAdapter(new AccountsSpinnerAdapter(getActivity(), accounts));
mAccountSpinner.setOnItemSelectedListener(this);
@ -331,7 +331,7 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
@Override
public void onItemSelected(final AdapterView<?> parent, final View view, final int pos, final long id) {
final Account account = (Account) mAccountSpinner.getSelectedItem();
final ParcelableAccount account = (ParcelableAccount) mAccountSpinner.getSelectedItem();
if (account != null) {
mAccountId = account.account_id;
mSender = account;
@ -487,7 +487,7 @@ public class DirectMessagesConversationFragment extends BasePullToRefreshListFra
mAccountId = accountId;
mRecipientId = recipientId;
final Context context = getActivity();
mSender = Account.getAccount(context, accountId);
mSender = ParcelableAccount.getAccount(context, accountId);
mRecipient = Utils.getUserForConversation(context, accountId, recipientId);
final LoaderManager lm = getLoaderManager();
final Bundle args = new Bundle();

View File

@ -37,8 +37,8 @@ import android.widget.AbsListView;
import android.widget.ListView;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.DirectMessageConversationEntriesAdapter;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
@ -112,10 +112,7 @@ public class DirectMessagesFragment extends BasePullToRefreshListFragment implem
mAdapter = new DirectMessageConversationEntriesAdapter(getActivity());
setListAdapter(mAdapter);
mListView = getListView();
if (!mPreferences.getBoolean(KEY_COMPACT_CARDS, false)) {
mListView.setDivider(null);
}
mListView.setSelector(android.R.color.transparent);
mListView.setDivider(null);
getLoaderManager().initLoader(0, null, this);
setListShown(false);
}
@ -130,7 +127,7 @@ public class DirectMessagesFragment extends BasePullToRefreshListFragment implem
if (!no_account_selected) {
getListView().setEmptyView(null);
}
final Where account_where = Where.in(new Column(Statuses.ACCOUNT_ID), new RawItemArray(account_ids));
final Expression account_where = Expression.in(new Column(Statuses.ACCOUNT_ID), new RawItemArray(account_ids));
return new CursorLoader(getActivity(), uri, null, account_where.getSQL(), null, null);
}

View File

@ -19,33 +19,61 @@
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import org.mariotaku.twidere.adapter.CursorStatusesListAdapter;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
/**
* Created by mariotaku on 14/12/3.
*/
public class HomeTimelineFragment extends CursorStatusesFragment {
@Override
public int getStatuses(long[] accountIds, long[] maxIds, long[] sinceIds) {
return 0;
public Uri getContentUri() {
return Statuses.CONTENT_URI;
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
final Context context = getActivity();
final Uri uri = Statuses.CONTENT_URI;
final SharedPreferences preferences = getSharedPreferences();
final boolean sortById = preferences.getBoolean(KEY_SORT_TIMELINE_BY_ID, false);
final String sortOrder = sortById ? Statuses.SORT_ORDER_STATUS_ID_DESC : Statuses.SORT_ORDER_TIMESTAMP_DESC;
return new CursorLoader(context, uri, CursorStatusesListAdapter.CURSOR_COLS, null, null, sortOrder);
protected int getNotificationType() {
return NOTIFICATION_ID_HOME_TIMELINE;
}
@Override
protected boolean isFilterEnabled() {
final SharedPreferences pref = getSharedPreferences();
return pref != null && pref.getBoolean(KEY_FILTERS_IN_HOME_TIMELINE, true);
}
@Override
public int getStatuses(long[] accountIds, long[] maxIds, long[] sinceIds) {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null) return -1;
return twitter.getHomeTimelineAsync(accountIds, maxIds, sinceIds);
}
@Override
protected void onReceivedBroadcast(Intent intent, String action) {
switch (action) {
case BROADCAST_TASK_STATE_CHANGED: {
updateRefreshState();
break;
}
}
}
@Override
protected void onSetIntentFilter(IntentFilter filter) {
filter.addAction(BROADCAST_TASK_STATE_CHANGED);
}
private void updateRefreshState() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null) return;
setRefreshing(twitter.isHomeTimelineRefreshing());
}
}

View File

@ -1,98 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class HomeTimelineListFragment extends CursorStatusesListFragment {
private final BroadcastReceiver mStatusReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
if (getActivity() == null || !isAdded() || isDetached()) return;
final String action = intent.getAction();
if (BROADCAST_HOME_TIMELINE_REFRESHED.equals(action)) {
setRefreshComplete();
} else if (BROADCAST_TASK_STATE_CHANGED.equals(action)) {
updateRefreshState();
}
}
};
@Override
public int getStatuses(final long[] accountIds, final long[] maxIds, final long[] sinceIds) {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null) return 0;
if (maxIds == null) return twitter.refreshAll(accountIds);
return twitter.getHomeTimelineAsync(accountIds, maxIds, sinceIds);
}
@Override
public void onStart() {
super.onStart();
final IntentFilter filter = new IntentFilter(BROADCAST_HOME_TIMELINE_REFRESHED);
filter.addAction(BROADCAST_TASK_STATE_CHANGED);
registerReceiver(mStatusReceiver, filter);
}
@Override
public void onStop() {
unregisterReceiver(mStatusReceiver);
super.onStop();
}
@Override
protected Uri getContentUri() {
return Statuses.CONTENT_URI;
}
@Override
protected int getNotificationType() {
return NOTIFICATION_ID_HOME_TIMELINE;
}
@Override
protected String getPositionKey() {
return "home_timeline" + getTabPosition();
}
@Override
protected boolean isFiltersEnabled() {
final SharedPreferences pref = getSharedPreferences();
return pref != null && pref.getBoolean(KEY_FILTERS_IN_HOME_TIMELINE, true);
}
@Override
protected void updateRefreshState() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null || !getUserVisibleHint() || getActivity() == null) return;
setRefreshing(twitter.isHomeTimelineRefreshing());
}
}

View File

@ -5,8 +5,8 @@ import android.view.Menu;
import android.view.MenuInflater;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.Account.AccountWithCredentials;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableAccount.ParcelableAccountWithCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
public class IncomingFriendshipsMenuDialogFragment extends UserMenuDialogFragment {
@ -14,8 +14,8 @@ public class IncomingFriendshipsMenuDialogFragment extends UserMenuDialogFragmen
@Override
protected void onPrepareItemMenu(final Menu menu, final ParcelableUser user) {
final Context context = getThemedContext();
final AccountWithCredentials account = Account.getAccountWithCredentials(context, user.account_id);
if (AccountWithCredentials.isOfficialCredentials(context, account)) {
final ParcelableAccountWithCredentials account = ParcelableAccount.getAccountWithCredentials(context, user.account_id);
if (ParcelableAccountWithCredentials.isOfficialCredentials(context, account)) {
final MenuInflater inflater = new MenuInflater(context);
inflater.inflate(R.menu.action_incoming_friendship, menu);
}

View File

@ -1,18 +1,18 @@
/*
* Twidere - Twitter client for Android
*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@ -25,89 +25,57 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.twidere.provider.TweetStore.Mentions;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class MentionsTimelineFragment extends CursorStatusesListFragment {
/**
* Created by mariotaku on 14/12/3.
*/
public class MentionsTimelineFragment extends CursorStatusesFragment {
private final BroadcastReceiver mStatusReceiver = new BroadcastReceiver() {
@Override
public Uri getContentUri() {
return Mentions.CONTENT_URI;
}
@Override
public void onReceive(final Context context, final Intent intent) {
if (getActivity() == null || !isAdded() || isDetached()) return;
final String action = intent.getAction();
if (BROADCAST_MENTIONS_REFRESHED.equals(action)) {
setRefreshComplete();
} else if (BROADCAST_TASK_STATE_CHANGED.equals(action)) {
updateRefreshState();
}
}
};
@Override
protected int getNotificationType() {
return NOTIFICATION_ID_MENTIONS_TIMELINE;
}
@Override
public int getStatuses(final long[] account_ids, final long[] max_ids, final long[] since_ids) {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null) return -1;
return twitter.getMentionsAsync(account_ids, max_ids, since_ids);
}
@Override
protected boolean isFilterEnabled() {
final SharedPreferences pref = getSharedPreferences();
return pref != null && pref.getBoolean(KEY_FILTERS_IN_MENTIONS_TIMELINE, true);
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListAdapter().setMentionsHightlightDisabled(true);
}
@Override
public int getStatuses(long[] accountIds, long[] maxIds, long[] sinceIds) {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null) return -1;
return twitter.getMentionsTimelineAsync(accountIds, maxIds, sinceIds);
}
@Override
public void onStart() {
super.onStart();
final IntentFilter filter = new IntentFilter(BROADCAST_MENTIONS_REFRESHED);
filter.addAction(BROADCAST_TASK_STATE_CHANGED);
registerReceiver(mStatusReceiver, filter);
}
@Override
protected void onReceivedBroadcast(Intent intent, String action) {
switch (action) {
case BROADCAST_TASK_STATE_CHANGED: {
updateRefreshState();
break;
}
}
}
@Override
public void onStop() {
unregisterReceiver(mStatusReceiver);
super.onStop();
}
@Override
protected void onSetIntentFilter(IntentFilter filter) {
filter.addAction(BROADCAST_TASK_STATE_CHANGED);
}
@Override
protected Uri getContentUri() {
return Mentions.CONTENT_URI;
}
@Override
protected int getNotificationType() {
return NOTIFICATION_ID_MENTIONS;
}
@Override
protected String getPositionKey() {
return "mentions_timeline" + getTabPosition();
}
@Override
protected boolean isFiltersEnabled() {
final SharedPreferences pref = getSharedPreferences();
return pref != null && pref.getBoolean(KEY_FILTERS_IN_MENTIONS, true);
}
@Override
protected Where processWhere(final Where where) {
final Bundle extras = getExtraConfiguration();
if (extras.getBoolean(EXTRA_MY_FOLLOWING_ONLY))
return Where.and(where, Where.equals(Mentions.IS_FOLLOWING, 1));
return where;
}
@Override
protected void updateRefreshState() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null || !getUserVisibleHint()) return;
setRefreshing(twitter.isMentionsRefreshing());
}
private void updateRefreshState() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null) return;
setRefreshing(twitter.isMentionsTimelineRefreshing());
}
}

View File

@ -20,11 +20,15 @@
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.model.ParcelableStatus;
import java.util.ArrayList;
import java.util.List;
/**
@ -33,8 +37,31 @@ import java.util.List;
public abstract class ParcelableStatusesFragment extends AbsStatusesFragment<List<ParcelableStatus>> {
@Override
protected ParcelableStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new ParcelableStatusesAdapter(context, compact);
protected void onSetIntentFilter(IntentFilter filter) {
filter.addAction(BROADCAST_STATUS_DESTROYED);
}
@Override
protected void onReceivedBroadcast(Intent intent, String action) {
switch (action) {
case BROADCAST_STATUS_DESTROYED: {
deleteStatus(intent.getLongExtra(EXTRA_STATUS_ID, -1));
break;
}
}
}
public final void deleteStatus(final long statusId) {
final List<ParcelableStatus> data = getAdapterData();
if (statusId <= 0 || data == null) return;
final ArrayList<ParcelableStatus> dataToRemove = new ArrayList<>();
for (final ParcelableStatus status : data) {
if (status.id == statusId || status.retweet_id > 0 && status.retweet_id == statusId) {
dataToRemove.add(status);
}
}
data.removeAll(dataToRemove);
setAdapterData(data);
}
@Override
@ -50,4 +77,39 @@ public abstract class ParcelableStatusesFragment extends AbsStatusesFragment<Lis
return -1;
}
@Override
protected long[] getAccountIds() {
return new long[]{getAccountId()};
}
@Override
protected ParcelableStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new ParcelableStatusesAdapter(context, compact);
}
@Override
protected void onLoadMoreStatuses() {
final IStatusesAdapter<List<ParcelableStatus>> adapter = getAdapter();
final long[] maxIds = new long[]{adapter.getStatus(adapter.getStatusCount() - 1).id};
getStatuses(null, maxIds, null);
}
@Override
public boolean triggerRefresh() {
final IStatusesAdapter<List<ParcelableStatus>> adapter = getAdapter();
final long[] accountIds = getAccountIds();
if (adapter.getStatusCount() > 0) {
final long[] sinceIds = new long[]{adapter.getStatus(0).id};
getStatuses(accountIds, null, sinceIds);
} else {
getStatuses(accountIds, null, null);
}
return true;
}
protected long getAccountId() {
final Bundle args = getArguments();
return args != null ? args.getLong(EXTRA_ACCOUNT_ID, -1) : -1;
}
}

View File

@ -58,7 +58,7 @@ public abstract class ParcelableStatusesListFragment extends BaseStatusesListFra
if (statusId > 0) {
deleteStatus(statusId);
}
} else if (BROADCAST_RETWEET_CHANGED.equals(action)) {
} else if (BROADCAST_STATUS_RETWEETED.equals(action)) {
final long status_id = intent.getLongExtra(EXTRA_STATUS_ID, -1);
final boolean retweeted = intent.getBooleanExtra(EXTRA_RETWEETED, false);
if (status_id > 0 && !retweeted) {
@ -158,7 +158,7 @@ public abstract class ParcelableStatusesListFragment extends BaseStatusesListFra
public void onStart() {
super.onStart();
final IntentFilter filter = new IntentFilter(BROADCAST_STATUS_DESTROYED);
filter.addAction(BROADCAST_RETWEET_CHANGED);
filter.addAction(BROADCAST_STATUS_RETWEETED);
registerReceiver(mStateReceiver, filter);
}

View File

@ -54,6 +54,15 @@ public class SearchFragment extends BaseSupportFragment implements RefreshScroll
private Fragment mCurrentVisibleFragment;
@Override
protected void fitSystemWindows(Rect insets) {
super.fitSystemWindows(insets);
final View view = getView();
if (view != null) {
view.setPadding(insets.left, insets.top, insets.right, insets.bottom);
}
}
@Override
public Fragment getCurrentVisibleFragment() {
return mCurrentVisibleFragment;

View File

@ -1,364 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.etsy.android.grid.StaggeredGridView;
import org.mariotaku.twidere.R;
/**
* Static library support version of the framework's
* {@link android.app.ListFragment}. Used to write apps that run on platforms
* prior to Android 3.0. When running on Android 3.0 or above, this
* implementation is still used; it does not try to switch to the framework's
* implementation. See the framework SDK documentation for a class overview.
*/
public class StaggeredGridFragment extends Fragment {
static final int INTERNAL_EMPTY_ID = 0x00ff0001;
static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002;
static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003;
final private Handler mHandler = new Handler();
final private Runnable mRequestFocus = new Runnable() {
@Override
public void run() {
mList.focusableViewAvailable(mList);
}
};
final private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(final AdapterView<?> parent, final View v, final int position, final long id) {
onListItemClick((StaggeredGridView) parent, v, position, id);
}
};
ListAdapter mAdapter;
StaggeredGridView mList;
View mEmptyView;
TextView mStandardEmptyView;
View mProgressContainer;
View mListContainer;
CharSequence mEmptyText;
boolean mListShown;
public StaggeredGridFragment() {
}
/**
* Get the ListAdapter associated with this activity's ListView.
*/
public ListAdapter getListAdapter() {
return mAdapter;
}
/**
* Get the activity's list view widget.
*/
public StaggeredGridView getListView() {
ensureList();
return mList;
}
/**
* Get the cursor row ID of the currently selected list item.
*/
public long getSelectedItemId() {
ensureList();
return mList.getSelectedItemId();
}
/**
* Get the position of the currently selected list item.
*/
public int getSelectedItemPosition() {
ensureList();
return mList.getSelectedItemPosition();
}
/**
* Provide default implementation to return a simple list view. Subclasses
* can override to replace with their own layout. If doing so, the returned
* view hierarchy <em>must</em> have a ListView whose id is
* {@link android.R.id#list android.R.id.list} and can optionally have a
* sibling view id {@link android.R.id#empty android.R.id.empty} that is to
* be shown when the list is empty.
*
* <p>
* If you are overriding this method with your own custom content, consider
* including the standard layout {@link android.R.layout#list_content} in
* your layout file, so that you continue to retain all of the standard
* behavior of ListFragment. In particular, this is currently the only way
* to have the built-in indeterminant progress state be shown.
*/
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final Context context = getActivity();
final FrameLayout root = new FrameLayout(context);
// ------------------------------------------------------------------
final LinearLayout pframe = new LinearLayout(context);
pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID);
pframe.setOrientation(LinearLayout.VERTICAL);
pframe.setVisibility(View.GONE);
pframe.setGravity(Gravity.CENTER);
final ProgressBar progress = new ProgressBar(context, null, android.R.attr.progressBarStyleLarge);
pframe.addView(progress, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
root.addView(pframe, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
// ------------------------------------------------------------------
final FrameLayout lframe = new FrameLayout(context);
lframe.setId(INTERNAL_LIST_CONTAINER_ID);
final TextView tv = new TextView(getActivity());
tv.setId(INTERNAL_EMPTY_ID);
tv.setGravity(Gravity.CENTER);
lframe.addView(tv, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
final StaggeredGridView lv = (StaggeredGridView) inflater.inflate(R.layout.staggered_gridview, lframe, false);
lv.setId(android.R.id.list);
lv.setDrawSelectorOnTop(false);
lframe.addView(lv, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
root.addView(lframe, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
// ------------------------------------------------------------------
root.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
return root;
}
/**
* Detach from list view.
*/
@Override
public void onDestroyView() {
mHandler.removeCallbacks(mRequestFocus);
mList = null;
mListShown = false;
mEmptyView = mProgressContainer = mListContainer = null;
mStandardEmptyView = null;
super.onDestroyView();
}
/**
* This method will be called when an item in the list is selected.
* Subclasses should override. Subclasses can call
* getListView().getItemAtPosition(position) if they need to access the data
* associated with the selected item.
*
* @param l The ListView where the click happened
* @param v The view that was clicked within the ListView
* @param position The position of the view in the list
* @param id The row id of the item that was clicked
*/
public void onListItemClick(final StaggeredGridView l, final View v, final int position, final long id) {
}
/**
* Attach to list view once the view hierarchy has been created.
*/
@Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ensureList();
}
/**
* The default content for a ListFragment has a TextView that can be shown
* when the list is empty. If you would like to have it shown, call this
* method to supply the text it should use.
*/
public void setEmptyText(final CharSequence text) {
ensureList();
if (mStandardEmptyView == null) throw new IllegalStateException("Can't be used with a custom content view");
mStandardEmptyView.setText(text);
if (mEmptyText == null) {
mList.setEmptyView(mStandardEmptyView);
}
mEmptyText = text;
}
/**
* Provide the cursor for the list view.
*/
public void setListAdapter(final ListAdapter adapter) {
final boolean hadAdapter = mAdapter != null;
mAdapter = adapter;
if (mList != null) {
mList.setAdapter(adapter);
if (!mListShown && !hadAdapter) {
// The list was hidden, and previously didn't have an
// adapter. It is now time to show it.
setListShown(true, getView().getWindowToken() != null);
}
}
}
/**
* Control whether the list is being displayed. You can make it not
* displayed if you are waiting for the initial data to show in it. During
* this time an indeterminant progress indicator will be shown instead.
*
* <p>
* Applications do not normally need to use this themselves. The default
* behavior of ListFragment is to start with the list not being shown, only
* showing it once an adapter is given with
* {@link #setListAdapter(ListAdapter)}. If the list at that point had not
* been shown, when it does get shown it will be do without the user ever
* seeing the hidden state.
*
* @param shown If true, the list view is shown; if false, the progress
* indicator. The initial value is true.
*/
public void setListShown(final boolean shown) {
setListShown(shown, true);
}
/**
* Like {@link #setListShown(boolean)}, but no animation is used when
* transitioning from the previous state.
*/
public void setListShownNoAnimation(final boolean shown) {
setListShown(shown, false);
}
/**
* Set the currently selected list item to the specified position with the
* adapter's data
*
* @param position
*/
public void setSelection(final int position) {
ensureList();
mList.setSelection(position);
}
private void ensureList() {
if (mList != null) return;
final View root = getView();
if (root == null) throw new IllegalStateException("Content view not yet created");
if (root instanceof StaggeredGridView) {
mList = (StaggeredGridView) root;
} else {
mStandardEmptyView = (TextView) root.findViewById(INTERNAL_EMPTY_ID);
if (mStandardEmptyView == null) {
mEmptyView = root.findViewById(android.R.id.empty);
} else {
mStandardEmptyView.setVisibility(View.GONE);
}
mProgressContainer = root.findViewById(INTERNAL_PROGRESS_CONTAINER_ID);
mListContainer = root.findViewById(INTERNAL_LIST_CONTAINER_ID);
final View rawListView = root.findViewById(android.R.id.list);
if (!(rawListView instanceof StaggeredGridView)) {
if (rawListView == null)
throw new RuntimeException("Your content must have a StaggeredGridView whose id attribute is "
+ "'android.R.id.list'");
throw new RuntimeException("Content has view with id attribute 'android.R.id.list' "
+ "that is not a StaggeredGridView class");
}
mList = (StaggeredGridView) rawListView;
if (mEmptyView != null) {
mList.setEmptyView(mEmptyView);
} else if (mEmptyText != null) {
mStandardEmptyView.setText(mEmptyText);
mList.setEmptyView(mStandardEmptyView);
}
}
mListShown = true;
mList.setOnItemClickListener(mOnClickListener);
if (mAdapter != null) {
final ListAdapter adapter = mAdapter;
mAdapter = null;
setListAdapter(adapter);
} else {
// We are starting without an adapter, so assume we won't
// have our data right away and start with the progress indicator.
if (mProgressContainer != null) {
setListShown(false, false);
}
}
mHandler.post(mRequestFocus);
}
/**
* Control whether the list is being displayed. You can make it not
* displayed if you are waiting for the initial data to show in it. During
* this time an indeterminant progress indicator will be shown instead.
*
* @param shown If true, the list view is shown; if false, the progress
* indicator. The initial value is true.
* @param animate If true, an animation will be used to transition to the
* new state.
*/
private void setListShown(final boolean shown, final boolean animate) {
ensureList();
if (mProgressContainer == null) throw new IllegalStateException("Can't be used with a custom content view");
if (mListShown == shown) return;
mListShown = shown;
if (shown) {
if (animate) {
mProgressContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out));
mListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in));
} else {
mProgressContainer.clearAnimation();
mListContainer.clearAnimation();
}
mProgressContainer.setVisibility(View.GONE);
mListContainer.setVisibility(View.VISIBLE);
} else {
if (animate) {
mProgressContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in));
mListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out));
} else {
mProgressContainer.clearAnimation();
mListContainer.clearAnimation();
}
mProgressContainer.setVisibility(View.VISIBLE);
mListContainer.setVisibility(View.GONE);
}
}
}

View File

@ -1,103 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
import android.view.View;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class StaggeredHomeTimelineFragment extends CursorStatusesStaggeredGridFragment {
private final BroadcastReceiver mStatusReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
if (getActivity() == null || !isAdded() || isDetached()) return;
final String action = intent.getAction();
if (BROADCAST_HOME_TIMELINE_REFRESHED.equals(action)) {
setRefreshComplete();
} else if (BROADCAST_TASK_STATE_CHANGED.equals(action)) {
updateRefreshState();
}
}
};
@Override
public int getStatuses(final long[] accountIds, final long[] maxIds, final long[] sinceIds) {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null) return 0;
if (maxIds == null) return twitter.refreshAll(accountIds);
return twitter.getHomeTimelineAsync(accountIds, maxIds, sinceIds);
}
@Override
public void onStart() {
super.onStart();
final IntentFilter filter = new IntentFilter(BROADCAST_HOME_TIMELINE_REFRESHED);
filter.addAction(BROADCAST_TASK_STATE_CHANGED);
registerReceiver(mStatusReceiver, filter);
}
@Override
public void onStop() {
unregisterReceiver(mStatusReceiver);
super.onStop();
}
@Override
protected Uri getContentUri() {
return Statuses.CONTENT_URI;
}
@Override
protected int getNotificationType() {
return NOTIFICATION_ID_HOME_TIMELINE;
}
@Override
protected String getPositionKey() {
return "home_timeline" + getTabPosition();
}
@Override
protected boolean isFiltersEnabled() {
final SharedPreferences pref = getSharedPreferences();
return pref != null && pref.getBoolean(KEY_FILTERS_IN_HOME_TIMELINE, true);
}
@Override
protected void updateRefreshState() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
if (twitter == null || !getUserVisibleHint() || getActivity() == null) return;
setRefreshing(twitter.isHomeTimelineRefreshing());
}
@Override
public View getRefreshIndicatorView() {
return getListView().getRefreshIndicatorView();
}
}

View File

@ -74,8 +74,8 @@ import org.mariotaku.twidere.activity.support.ColorPickerDialogActivity;
import org.mariotaku.twidere.adapter.ParcelableStatusesListAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.Account.AccountWithCredentials;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableAccount.ParcelableAccountWithCredentials;
import org.mariotaku.twidere.model.ParcelableLocation;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
@ -203,7 +203,7 @@ public class StatusFragment extends ParcelableStatusesListFragment implements On
}
break;
}
case BROADCAST_RETWEET_CHANGED: {
case BROADCAST_STATUS_RETWEETED: {
final long status_id = intent.getLongExtra(EXTRA_STATUS_ID, -1);
if (status_id > 0 && status_id == getStatusId()) {
getStatus(true);
@ -561,9 +561,9 @@ public class StatusFragment extends ParcelableStatusesListFragment implements On
}
case R.id.favorites_container: {
// TODO
final AccountWithCredentials account = Account.getAccountWithCredentials(getActivity(),
final ParcelableAccountWithCredentials account = ParcelableAccount.getAccountWithCredentials(getActivity(),
status.account_id);
if (AccountWithCredentials.isOfficialCredentials(getActivity(), account)) {
if (ParcelableAccountWithCredentials.isOfficialCredentials(getActivity(), account)) {
openStatusFavoriters(getActivity(), status.account_id, status.retweet_id > 0 ? status.retweet_id
: status.id);
}
@ -689,7 +689,7 @@ public class StatusFragment extends ParcelableStatusesListFragment implements On
final IntentFilter filter = new IntentFilter();
filter.addAction(BROADCAST_FRIENDSHIP_CHANGED);
filter.addAction(BROADCAST_FAVORITE_CHANGED);
filter.addAction(BROADCAST_RETWEET_CHANGED);
filter.addAction(BROADCAST_STATUS_RETWEETED);
registerReceiver(mStatusReceiver, filter);
updateUserColor();
final int text_size = mPreferences.getInt(KEY_TEXT_SIZE, getDefaultTextSize(getActivity()));
@ -814,9 +814,9 @@ public class StatusFragment extends ParcelableStatusesListFragment implements On
break;
}
case MENU_TRANSLATE: {
final AccountWithCredentials account = Account.getAccountWithCredentials(getActivity(),
final ParcelableAccountWithCredentials account = ParcelableAccount.getAccountWithCredentials(getActivity(),
status.account_id);
if (AccountWithCredentials.isOfficialCredentials(getActivity(), account)) {
if (ParcelableAccountWithCredentials.isOfficialCredentials(getActivity(), account)) {
StatusTranslateDialogFragment.show(getFragmentManager(), status);
} else {

View File

@ -36,7 +36,6 @@ public class UserFavoritesFragment extends ParcelableStatusesFragment {
@Override
public Loader<List<ParcelableStatus>> onCreateLoader(int id, Bundle args) {
setRefreshing(true);
final List<ParcelableStatus> data = getAdapterData();
final Context context = getActivity();
final long accountId = args.getLong(EXTRA_ACCOUNT_ID, -1);
final long maxId = args.getLong(EXTRA_MAX_ID, -1);
@ -44,8 +43,8 @@ public class UserFavoritesFragment extends ParcelableStatusesFragment {
final long userId = args.getLong(EXTRA_USER_ID, -1);
final String screenName = args.getString(EXTRA_SCREEN_NAME);
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
return new UserFavoritesLoader(context, accountId, userId, screenName, maxId, sinceId, data,
null, tabPosition);
return new UserFavoritesLoader(context, accountId, userId, screenName, maxId, sinceId,
getAdapterData(), null, tabPosition);
}
}

View File

@ -80,7 +80,7 @@ import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.mariotaku.menucomponent.internal.menu.MenuUtils;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.AccountSelectorActivity;
import org.mariotaku.twidere.activity.support.ColorPickerDialogActivity;
@ -332,7 +332,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mFollowButton.setText(R.string.follow);
}
final ContentResolver resolver = getContentResolver();
final String where = Where.equals(CachedUsers.USER_ID, user.id).getSQL();
final String where = Expression.equals(CachedUsers.USER_ID, user.id).getSQL();
resolver.delete(CachedUsers.CONTENT_URI, where, null);
// I bet you don't want to see blocked user in your auto
// complete list.
@ -926,7 +926,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final boolean filtering = Utils.isFilteringUser(getActivity(), user.id);
final ContentResolver cr = getContentResolver();
if (filtering) {
final Where where = Where.equals(Filters.Users.USER_ID, user.id);
final Expression where = Expression.equals(Filters.Users.USER_ID, user.id);
cr.delete(Filters.Users.CONTENT_URI, where.getSQL(), null);
showInfoMessage(getActivity(), R.string.message_user_unmuted, false);
} else {
@ -1115,7 +1115,8 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final Drawable shadow = activity.getResources().getDrawable(R.drawable.shadow_user_banner_action_bar);
final Drawable background = ThemeUtils.getActionBarBackground(activity, themeResId);
mActionBarBackground = new ActionBarDrawable(getResources(), shadow, background, ThemeUtils.isDarkTheme(themeResId));
mActionBarBackground.setAlpha(ThemeUtils.getThemeAlpha(activity));
mActionBarBackground.setAlpha(linkHandler.getCurrentThemeBackgroundAlpha());
mProfileBannerView.setAlpha(linkHandler.getCurrentThemeBackgroundAlpha() / 255f);
actionBar.setBackgroundDrawable(mActionBarBackground);
}
@ -1161,8 +1162,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final View profileBannerContainer = mProfileBannerContainer;
final int spaceHeight = space.getHeight();
final float factor = MathUtils.clamp(offset / (float) spaceHeight, 0, 1);
profileBannerView.setAlpha(1.0f - factor / 8f);
profileBannerContainer.setTranslationY(-offset);
profileBannerContainer.setTranslationY(Math.max(-offset, -spaceHeight));
profileBannerView.setTranslationY(Math.min(offset, spaceHeight) / 2);
if (mActionBarBackground != null && mTintedStatusContent != null) {

View File

@ -32,12 +32,14 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.CardView;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
@ -59,6 +61,7 @@ import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.UserListSelectorActivity;
import org.mariotaku.twidere.adapter.support.SupportTabsAdapter;
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback;
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.model.SingleResponse;
@ -86,7 +89,7 @@ import static org.mariotaku.twidere.util.Utils.setMenuItemAvailability;
public class UserListFragment extends BaseSupportFragment implements OnClickListener,
LoaderCallbacks<SingleResponse<ParcelableUserList>>, DrawerCallback,
SystemWindowsInsetsCallback {
SystemWindowsInsetsCallback, SupportFragmentCallback {
private ImageLoaderWrapper mProfileImageLoader;
private AsyncTwitterWrapper mTwitterWrapper;
@ -100,6 +103,7 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
private HeaderDrawerLayout mHeaderDrawerLayout;
private ViewPager mViewPager;
private PagerSlidingTabStrip mPagerIndicator;
private CardView mCardView;
private SupportTabsAdapter mPagerAdapter;
@ -125,6 +129,59 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
}
};
private boolean mUserListLoaderInitialized;
private Fragment mCurrentVisibleFragment;
@Override
public boolean canScroll(float dy) {
final Fragment fragment = mCurrentVisibleFragment;
return fragment instanceof DrawerCallback && ((DrawerCallback) fragment).canScroll(dy);
}
@Override
public void cancelTouch() {
final Fragment fragment = mCurrentVisibleFragment;
if (fragment instanceof DrawerCallback) {
((DrawerCallback) fragment).cancelTouch();
}
}
@Override
public void fling(float velocity) {
final Fragment fragment = mCurrentVisibleFragment;
if (fragment instanceof DrawerCallback) {
((DrawerCallback) fragment).fling(velocity);
}
}
@Override
public boolean isScrollContent(float x, float y) {
final ViewPager v = mViewPager;
final int[] location = new int[2];
v.getLocationOnScreen(location);
return x >= location[0] && x <= location[0] + v.getWidth()
&& y >= location[1] && y <= location[1] + v.getHeight();
}
@Override
public void scrollBy(float dy) {
final Fragment fragment = mCurrentVisibleFragment;
if (fragment instanceof DrawerCallback) {
((DrawerCallback) fragment).scrollBy(dy);
}
}
@Override
public boolean shouldLayoutHeaderBottom() {
final HeaderDrawerLayout drawer = mHeaderDrawerLayout;
final CardView card = mCardView;
if (drawer == null || card == null) return false;
return card.getTop() + drawer.getHeaderTop() - drawer.getPaddingTop() <= 0;
}
@Override
public void topChanged(int offset) {
}
public void displayUserList(final ParcelableUserList userList) {
if (userList == null || getActivity() == null) return;
@ -149,6 +206,31 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
invalidateOptionsMenu();
}
@Override
public Fragment getCurrentVisibleFragment() {
return mCurrentVisibleFragment;
}
@Override
public void onDetachFragment(Fragment fragment) {
}
@Override
public void onSetUserVisibleHint(Fragment fragment, boolean isVisibleToUser) {
mCurrentVisibleFragment = isVisibleToUser ? fragment : null;
}
@Override
public boolean triggerRefresh(int position) {
return false;
}
@Override
public boolean getSystemWindowsInsets(Rect insets) {
return false;
}
public void getUserListInfo(final boolean omit_intent_extra) {
final LoaderManager lm = getLoaderManager();
lm.destroyLoader(0);
@ -320,29 +402,6 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
return true;
}
private void setupUserPages() {
final Context context = getActivity();
final Bundle args = getArguments(), tabArgs = new Bundle();
if (args.containsKey(EXTRA_USER)) {
final ParcelableUserList userList = args.getParcelable(EXTRA_USER_LIST);
tabArgs.putLong(EXTRA_ACCOUNT_ID, userList.account_id);
tabArgs.putLong(EXTRA_USER_ID, userList.user_id);
tabArgs.putString(EXTRA_SCREEN_NAME, userList.user_screen_name);
tabArgs.putInt(EXTRA_LIST_ID, (int) userList.id);
tabArgs.putString(EXTRA_LIST_NAME, userList.name);
} else {
tabArgs.putLong(EXTRA_ACCOUNT_ID, args.getLong(EXTRA_ACCOUNT_ID, -1));
tabArgs.putLong(EXTRA_USER_ID, args.getLong(EXTRA_USER_ID, -1));
tabArgs.putString(EXTRA_SCREEN_NAME, args.getString(EXTRA_SCREEN_NAME));
tabArgs.putInt(EXTRA_LIST_ID, args.getInt(EXTRA_LIST_ID, -1));
tabArgs.putString(EXTRA_LIST_NAME, args.getString(EXTRA_LIST_NAME));
}
mPagerAdapter.addTab(UserListTimelineFragment.class, tabArgs, getString(R.string.statuses), null, 0);
mPagerAdapter.addTab(UserListMembersFragment.class, tabArgs, getString(R.string.list_members), null, 1);
mPagerAdapter.addTab(UserListSubscribersFragment.class, tabArgs, getString(R.string.list_subscribers), null, 2);
mPagerIndicator.notifyDataSetChanged();
}
@Override
public void onClick(final View view) {
switch (view.getId()) {
@ -415,6 +474,7 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
final View headerView = mHeaderDrawerLayout.getHeader();
final View contentView = mHeaderDrawerLayout.getContent();
mCardView = (CardView) headerView.findViewById(R.id.card);
mProfileContainer = (ColorLabelRelativeLayout) headerView.findViewById(R.id.profile);
mListNameView = (TextView) headerView.findViewById(R.id.list_name);
mCreatedByView = (TextView) headerView.findViewById(R.id.created_by);
@ -441,44 +501,27 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
content.setClipToPadding(false);
}
@Override
public void fling(float velocity) {
}
@Override
public void scrollBy(float dy) {
}
@Override
public boolean shouldLayoutHeaderBottom() {
return false;
}
@Override
public boolean canScroll(float dy) {
return false;
}
@Override
public boolean isScrollContent(float x, float y) {
return false;
}
@Override
public void cancelTouch() {
}
@Override
public void topChanged(int offset) {
}
@Override
public boolean getSystemWindowsInsets(Rect insets) {
return false;
private void setupUserPages() {
final Context context = getActivity();
final Bundle args = getArguments(), tabArgs = new Bundle();
if (args.containsKey(EXTRA_USER)) {
final ParcelableUserList userList = args.getParcelable(EXTRA_USER_LIST);
tabArgs.putLong(EXTRA_ACCOUNT_ID, userList.account_id);
tabArgs.putLong(EXTRA_USER_ID, userList.user_id);
tabArgs.putString(EXTRA_SCREEN_NAME, userList.user_screen_name);
tabArgs.putInt(EXTRA_LIST_ID, (int) userList.id);
tabArgs.putString(EXTRA_LIST_NAME, userList.name);
} else {
tabArgs.putLong(EXTRA_ACCOUNT_ID, args.getLong(EXTRA_ACCOUNT_ID, -1));
tabArgs.putLong(EXTRA_USER_ID, args.getLong(EXTRA_USER_ID, -1));
tabArgs.putString(EXTRA_SCREEN_NAME, args.getString(EXTRA_SCREEN_NAME));
tabArgs.putInt(EXTRA_LIST_ID, args.getInt(EXTRA_LIST_ID, -1));
tabArgs.putString(EXTRA_LIST_NAME, args.getString(EXTRA_LIST_NAME));
}
mPagerAdapter.addTab(UserListTimelineFragment.class, tabArgs, getString(R.string.statuses), null, 0);
mPagerAdapter.addTab(UserListMembersFragment.class, tabArgs, getString(R.string.list_members), null, 1);
mPagerAdapter.addTab(UserListSubscribersFragment.class, tabArgs, getString(R.string.list_subscribers), null, 2);
mPagerIndicator.notifyDataSetChanged();
}
public static class EditUserListDialogFragment extends BaseSupportDialogFragment implements

View File

@ -1,75 +1,51 @@
/*
* Twidere - Twitter client for Android
*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.Loader;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.loader.support.UserListTimelineLoader;
import org.mariotaku.twidere.model.ParcelableStatus;
import java.util.List;
public class UserListTimelineFragment extends ParcelableStatusesListFragment {
/**
* Created by mariotaku on 14/12/2.
*/
public class UserListTimelineFragment extends ParcelableStatusesFragment {
@Override
public Loader<List<ParcelableStatus>> newLoaderInstance(final Context context, final Bundle args) {
if (args == null) return null;
final int list_id = args.getInt(EXTRA_LIST_ID, -1);
final long account_id = args.getLong(EXTRA_ACCOUNT_ID, -1);
final long max_id = args.getLong(EXTRA_MAX_ID, -1);
final long since_id = args.getLong(EXTRA_SINCE_ID, -1);
final long user_id = args.getLong(EXTRA_USER_ID, -1);
final String screen_name = args.getString(EXTRA_SCREEN_NAME);
final String list_name = args.getString(EXTRA_LIST_NAME);
final int tab_position = args.getInt(EXTRA_TAB_POSITION, -1);
return new UserListTimelineLoader(getActivity(), account_id, list_id, user_id, screen_name, list_name, max_id,
since_id, getData(), getSavedStatusesFileArgs(), tab_position);
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
adapter.setFiltersEnabled(true);
adapter.setIgnoredFilterFields(false, false, false, false, false);
}
@Override
protected String[] getSavedStatusesFileArgs() {
final Bundle args = getArguments();
if (args == null) return null;
final int list_id = args.getInt(EXTRA_LIST_ID, -1);
final long account_id = args.getLong(EXTRA_ACCOUNT_ID, -1);
final long user_id = args.getLong(EXTRA_USER_ID, -1);
final String screen_name = args.getString(EXTRA_SCREEN_NAME);
final String list_name = args.getString(EXTRA_LIST_NAME);
return new String[] { AUTHORITY_USER_LIST_TIMELINE, "account" + account_id, "list_id" + list_id,
"list_name" + list_name, "user" + user_id, "screen_name" + screen_name };
}
@Override
protected boolean shouldShowAccountColor() {
return false;
}
@Override
public Loader<List<ParcelableStatus>> onCreateLoader(int id, Bundle args) {
setRefreshing(true);
if (args == null) return null;
final int listId = args.getInt(EXTRA_LIST_ID, -1);
final long accountId = args.getLong(EXTRA_ACCOUNT_ID, -1);
final long maxId = args.getLong(EXTRA_MAX_ID, -1);
final long sinceId = args.getLong(EXTRA_SINCE_ID, -1);
final long userId = args.getLong(EXTRA_USER_ID, -1);
final String screenName = args.getString(EXTRA_SCREEN_NAME);
final String listName = args.getString(EXTRA_LIST_NAME);
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
return new UserListTimelineLoader(getActivity(), accountId, listId, userId, screenName,
listName, maxId, sinceId, getAdapterData(), null, tabPosition);
}
}

View File

@ -0,0 +1,75 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.Loader;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.loader.support.UserListTimelineLoader;
import org.mariotaku.twidere.model.ParcelableStatus;
import java.util.List;
public class UserListTimelineListFragment extends ParcelableStatusesListFragment {
@Override
public Loader<List<ParcelableStatus>> newLoaderInstance(final Context context, final Bundle args) {
if (args == null) return null;
final int list_id = args.getInt(EXTRA_LIST_ID, -1);
final long account_id = args.getLong(EXTRA_ACCOUNT_ID, -1);
final long max_id = args.getLong(EXTRA_MAX_ID, -1);
final long since_id = args.getLong(EXTRA_SINCE_ID, -1);
final long user_id = args.getLong(EXTRA_USER_ID, -1);
final String screen_name = args.getString(EXTRA_SCREEN_NAME);
final String list_name = args.getString(EXTRA_LIST_NAME);
final int tab_position = args.getInt(EXTRA_TAB_POSITION, -1);
return new UserListTimelineLoader(getActivity(), account_id, list_id, user_id, screen_name, list_name, max_id,
since_id, getData(), getSavedStatusesFileArgs(), tab_position);
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
adapter.setFiltersEnabled(true);
adapter.setIgnoredFilterFields(false, false, false, false, false);
}
@Override
protected String[] getSavedStatusesFileArgs() {
final Bundle args = getArguments();
if (args == null) return null;
final int list_id = args.getInt(EXTRA_LIST_ID, -1);
final long account_id = args.getLong(EXTRA_ACCOUNT_ID, -1);
final long user_id = args.getLong(EXTRA_USER_ID, -1);
final String screen_name = args.getString(EXTRA_SCREEN_NAME);
final String list_name = args.getString(EXTRA_LIST_NAME);
return new String[] { AUTHORITY_USER_LIST_TIMELINE, "account" + account_id, "list_id" + list_id,
"list_name" + list_name, "user" + user_id, "screen_name" + screen_name };
}
@Override
protected boolean shouldShowAccountColor() {
return false;
}
}

View File

@ -9,19 +9,19 @@ import android.view.SubMenu;
import android.view.View;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
public class AccountActionProvider extends ActionProvider implements TwidereConstants {
public static final int MENU_GROUP = 201;
private final Account[] mAccounts;
private final ParcelableAccount[] mAccounts;
private long mAccountId;
public AccountActionProvider(final Context context) {
super(context);
mAccounts = Account.getAccounts(context, false, false);
mAccounts = ParcelableAccount.getAccounts(context, false, false);
}
@Override
@ -37,7 +37,7 @@ public class AccountActionProvider extends ActionProvider implements TwidereCons
@Override
public void onPrepareSubMenu(final SubMenu subMenu) {
subMenu.removeGroup(MENU_GROUP);
for (final Account account : mAccounts) {
for (final ParcelableAccount account : mAccounts) {
final MenuItem item = subMenu.add(MENU_GROUP, Menu.NONE, 0, account.name);
final Intent intent = new Intent();
intent.putExtra(EXTRA_ACCOUNT, account);
@ -47,7 +47,7 @@ public class AccountActionProvider extends ActionProvider implements TwidereCons
for (int i = 0, j = subMenu.size(); i < j; i++) {
final MenuItem item = subMenu.getItem(i);
final Intent intent = item.getIntent();
final Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
final ParcelableAccount account = intent.getParcelableExtra(EXTRA_ACCOUNT);
if (account.account_id == mAccountId) {
item.setChecked(true);
}

View File

@ -46,7 +46,7 @@ public class AccountPreferences implements Constants {
}
public int getDefaultNotificationLightColor() {
final Account a = Account.getAccount(mContext, mAccountId);
final ParcelableAccount a = ParcelableAccount.getAccount(mContext, mAccountId);
return a != null ? a.color : mContext.getResources().getColor(R.color.material_light_blue);
}

View File

@ -1,176 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.model;
import android.support.v4.app.Fragment;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.support.ActivitiesAboutMeFragment;
import org.mariotaku.twidere.fragment.support.ActivitiesByFriendsFragment;
import org.mariotaku.twidere.fragment.support.DirectMessagesFragment;
import org.mariotaku.twidere.fragment.support.HomeTimelineFragment;
import org.mariotaku.twidere.fragment.support.HomeTimelineListFragment;
import org.mariotaku.twidere.fragment.support.MentionsTimelineFragment;
import org.mariotaku.twidere.fragment.support.SearchStatusesFragment;
import org.mariotaku.twidere.fragment.support.TrendsSuggectionsFragment;
import org.mariotaku.twidere.fragment.support.UserFavoritesFragment;
import org.mariotaku.twidere.fragment.support.UserListTimelineFragment;
import org.mariotaku.twidere.fragment.support.UserTimelineFragment;
import java.util.Comparator;
import java.util.Map.Entry;
public enum CustomTabConfiguration2 implements Constants {
HOME_TIMELINE(HomeTimelineFragment.class, R.string.home, R.drawable.ic_action_home,
CustomTabConfiguration.ACCOUNT_OPTIONAL, CustomTabConfiguration.FIELD_TYPE_NONE, 0, false),
MENTIONS_TIMELINE(MentionsTimelineFragment.class, R.string.mentions, R.drawable.ic_action_at,
CustomTabConfiguration.ACCOUNT_OPTIONAL, CustomTabConfiguration.FIELD_TYPE_NONE, 1, false),
DIRECT_MESSAGES(DirectMessagesFragment.class, R.string.direct_messages, R.drawable.ic_action_message,
CustomTabConfiguration.ACCOUNT_OPTIONAL, CustomTabConfiguration.FIELD_TYPE_NONE, 2, false),
TRENDS_SUGGESTIONS(TrendsSuggectionsFragment.class, R.string.trends, R.drawable.ic_action_hashtag,
CustomTabConfiguration.ACCOUNT_NONE, CustomTabConfiguration.FIELD_TYPE_NONE, 3, true),
FAVORITES(UserFavoritesFragment.class, R.string.favorites, R.drawable.ic_action_star,
CustomTabConfiguration.ACCOUNT_REQUIRED, CustomTabConfiguration.FIELD_TYPE_USER, 4),
USER_TIMELINE(UserTimelineFragment.class, R.string.users_statuses, R.drawable.ic_action_quote,
CustomTabConfiguration.ACCOUNT_REQUIRED, CustomTabConfiguration.FIELD_TYPE_USER, 5),
SEARCH_STATUSES(SearchStatusesFragment.class, R.string.search_statuses, R.drawable.ic_action_search,
CustomTabConfiguration.ACCOUNT_REQUIRED, CustomTabConfiguration.FIELD_TYPE_TEXT, R.string.query,
EXTRA_QUERY, 6),
LIST_TIMELINE(UserListTimelineFragment.class, R.string.list_timeline, R.drawable.ic_action_list,
CustomTabConfiguration.ACCOUNT_REQUIRED, CustomTabConfiguration.FIELD_TYPE_USER_LIST, 7),
ACTIVITIES_ABOUT_ME(ActivitiesAboutMeFragment.class, R.string.activities_about_me,
R.drawable.ic_action_user, CustomTabConfiguration.ACCOUNT_OPTIONAL,
CustomTabConfiguration.FIELD_TYPE_NONE, 8),
ACTIVITIES_BY_FRIENDS(ActivitiesByFriendsFragment.class, R.string.activities_by_friends,
R.drawable.ic_action_accounts, CustomTabConfiguration.ACCOUNT_REQUIRED,
CustomTabConfiguration.FIELD_TYPE_NONE, 9);
public static final int FIELD_TYPE_NONE = 0;
public static final int FIELD_TYPE_USER = 1;
public static final int FIELD_TYPE_USER_LIST = 2;
public static final int FIELD_TYPE_TEXT = 3;
public static final int ACCOUNT_NONE = 0;
public static final int ACCOUNT_REQUIRED = 1;
public static final int ACCOUNT_OPTIONAL = 2;
private final int title, icon, secondaryFieldType, secondaryFieldTitle, sortPosition, accountRequirement;
private final Class<? extends Fragment> cls;
private final String secondaryFieldTextKey;
private final boolean singleTab;
CustomTabConfiguration2(final Class<? extends Fragment> cls, final int title, final int icon,
final int accountRequirement, final int secondaryFieldType, final int sortPosition) {
this(cls, title, icon, accountRequirement, secondaryFieldType, 0, EXTRA_TEXT, sortPosition, false);
}
CustomTabConfiguration2(final Class<? extends Fragment> cls, final int title, final int icon,
final int accountRequirement, final int secondaryFieldType, final int sortPosition, final boolean singleTab) {
this(cls, title, icon, accountRequirement, secondaryFieldType, 0, EXTRA_TEXT, sortPosition, singleTab);
}
CustomTabConfiguration2(final Class<? extends Fragment> cls, final int title, final int icon,
final int accountRequirement, final int secondaryFieldType, final int secondaryFieldTitle,
final String secondaryFieldTextKey, final int sortPosition) {
this(cls, title, icon, accountRequirement, secondaryFieldType, 0, secondaryFieldTextKey, sortPosition, false);
}
CustomTabConfiguration2(final Class<? extends Fragment> cls, final int title, final int icon,
final int accountRequirement, final int secondaryFieldType, final int secondaryFieldTitle,
final String secondaryFieldTextKey, final int sortPosition, final boolean singleTab) {
this.cls = cls;
this.title = title;
this.icon = icon;
this.sortPosition = sortPosition;
this.accountRequirement = accountRequirement;
this.secondaryFieldType = secondaryFieldType;
this.secondaryFieldTitle = secondaryFieldTitle;
this.secondaryFieldTextKey = secondaryFieldTextKey;
this.singleTab = singleTab;
}
public int getAccountRequirement() {
return accountRequirement;
}
public int getDefaultIcon() {
return icon;
}
public int getDefaultTitle() {
return title;
}
public Class<? extends Fragment> getFragmentClass() {
return cls;
}
public String getSecondaryFieldTextKey() {
return secondaryFieldTextKey;
}
public int getSecondaryFieldTitle() {
return secondaryFieldTitle;
}
public int getSecondaryFieldType() {
return secondaryFieldType;
}
public int getSortPosition() {
return sortPosition;
}
public boolean isSingleTab() {
return singleTab;
}
@Override
public String toString() {
return "CustomTabConfiguration{title=" + title + ", icon=" + icon + ", secondaryFieldType="
+ secondaryFieldType + ", secondaryFieldTitle=" + secondaryFieldTitle + ", sortPosition="
+ sortPosition + ", accountRequirement=" + accountRequirement + ", cls=" + cls
+ ", secondaryFieldTextKey=" + secondaryFieldTextKey + ", singleTab=" + singleTab + "}";
}
public static class CustomTabConfigurationComparator implements Comparator<Entry<String, CustomTabConfiguration2>> {
public static final CustomTabConfigurationComparator SINGLETON = new CustomTabConfigurationComparator();
@Override
public int compare(final Entry<String, CustomTabConfiguration2> lhs,
final Entry<String, CustomTabConfiguration2> rhs) {
return lhs.getValue().getSortPosition() - rhs.getValue().getSortPosition();
}
}
}

View File

@ -80,7 +80,7 @@ public class DraftItem implements Parcelable {
public DraftItem(final ParcelableStatusUpdate status) {
_id = 0;
account_ids = Account.getAccountIds(status.accounts);
account_ids = ParcelableAccount.getAccountIds(status.accounts);
in_reply_to_status_id = status.in_reply_to_status_id;
text = status.text;
media = status.media;

View File

@ -27,8 +27,8 @@ import android.os.Parcelable;
import android.support.annotation.NonNull;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.Where;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.util.content.ContentResolverUtils;
@ -39,18 +39,18 @@ import java.util.List;
import static org.mariotaku.twidere.util.Utils.isOfficialConsumerKeySecret;
import static org.mariotaku.twidere.util.Utils.shouldForceUsingPrivateAPIs;
public class Account implements Parcelable {
public class ParcelableAccount implements Parcelable {
public static final Parcelable.Creator<Account> CREATOR = new Parcelable.Creator<Account>() {
public static final Parcelable.Creator<ParcelableAccount> CREATOR = new Parcelable.Creator<ParcelableAccount>() {
@Override
public Account createFromParcel(final Parcel in) {
return new Account(in);
public ParcelableAccount createFromParcel(final Parcel in) {
return new ParcelableAccount(in);
}
@Override
public Account[] newArray(final int size) {
return new Account[size];
public ParcelableAccount[] newArray(final int size) {
return new ParcelableAccount[size];
}
};
@ -60,7 +60,7 @@ public class Account implements Parcelable {
public final boolean is_activated;
public final boolean is_dummy;
public Account(final Cursor cursor, final Indices indices) {
public ParcelableAccount(final Cursor cursor, final Indices indices) {
is_dummy = false;
screen_name = indices.screen_name != -1 ? cursor.getString(indices.screen_name) : null;
name = indices.name != -1 ? cursor.getString(indices.name) : null;
@ -71,7 +71,7 @@ public class Account implements Parcelable {
is_activated = indices.is_activated != -1 && cursor.getInt(indices.is_activated) == 1;
}
public Account(final Parcel source) {
public ParcelableAccount(final Parcel source) {
is_dummy = source.readInt() == 1;
is_activated = source.readInt() == 1;
account_id = source.readLong();
@ -82,7 +82,7 @@ public class Account implements Parcelable {
color = source.readInt();
}
private Account() {
private ParcelableAccount() {
is_dummy = true;
screen_name = null;
name = null;
@ -117,11 +117,11 @@ public class Account implements Parcelable {
out.writeInt(color);
}
public static Account dummyInstance() {
return new Account();
public static ParcelableAccount dummyInstance() {
return new ParcelableAccount();
}
public static Account getAccount(final Context context, final long account_id) {
public static ParcelableAccount getAccount(final Context context, final long account_id) {
if (context == null) return null;
final Cursor cur = ContentResolverUtils.query(context.getContentResolver(), Accounts.CONTENT_URI,
Accounts.COLUMNS, Accounts.ACCOUNT_ID + " = " + account_id, null, null);
@ -130,7 +130,7 @@ public class Account implements Parcelable {
if (cur.getCount() > 0 && cur.moveToFirst()) {
final Indices indices = new Indices(cur);
cur.moveToFirst();
return new Account(cur, indices);
return new ParcelableAccount(cur, indices);
}
} finally {
cur.close();
@ -139,7 +139,7 @@ public class Account implements Parcelable {
return null;
}
public static long[] getAccountIds(final Account[] accounts) {
public static long[] getAccountIds(final ParcelableAccount[] accounts) {
final long[] ids = new long[accounts.length];
for (int i = 0, j = accounts.length; i < j; i++) {
ids[i] = accounts[i].account_id;
@ -147,25 +147,25 @@ public class Account implements Parcelable {
return ids;
}
public static Account[] getAccounts(final Context context, final boolean activatedOnly,
public static ParcelableAccount[] getAccounts(final Context context, final boolean activatedOnly,
final boolean officialKeyOnly) {
final List<Account> list = getAccountsList(context, activatedOnly, officialKeyOnly);
return list.toArray(new Account[list.size()]);
final List<ParcelableAccount> list = getAccountsList(context, activatedOnly, officialKeyOnly);
return list.toArray(new ParcelableAccount[list.size()]);
}
public static Account[] getAccounts(final Context context, final long[] accountIds) {
if (context == null) return new Account[0];
final String where = accountIds != null ? Where.in(new Column(Accounts.ACCOUNT_ID),
public static ParcelableAccount[] getAccounts(final Context context, final long[] accountIds) {
if (context == null) return new ParcelableAccount[0];
final String where = accountIds != null ? Expression.in(new Column(Accounts.ACCOUNT_ID),
new RawItemArray(accountIds)).getSQL() : null;
final Cursor cur = ContentResolverUtils.query(context.getContentResolver(), Accounts.CONTENT_URI,
Accounts.COLUMNS_NO_CREDENTIALS, where, null, null);
if (cur == null) return new Account[0];
if (cur == null) return new ParcelableAccount[0];
try {
final Indices idx = new Indices(cur);
cur.moveToFirst();
final Account[] names = new Account[cur.getCount()];
final ParcelableAccount[] names = new ParcelableAccount[cur.getCount()];
while (!cur.isAfterLast()) {
names[cur.getPosition()] = new Account(cur, idx);
names[cur.getPosition()] = new ParcelableAccount(cur, idx);
cur.moveToNext();
}
return names;
@ -174,14 +174,14 @@ public class Account implements Parcelable {
}
}
public static List<Account> getAccountsList(final Context context, final boolean activatedOnly) {
public static List<ParcelableAccount> getAccountsList(final Context context, final boolean activatedOnly) {
return getAccountsList(context, activatedOnly, false);
}
public static List<Account> getAccountsList(final Context context, final boolean activatedOnly,
public static List<ParcelableAccount> getAccountsList(final Context context, final boolean activatedOnly,
final boolean officialKeyOnly) {
if (context == null) return Collections.emptyList();
final ArrayList<Account> accounts = new ArrayList<>();
final ArrayList<ParcelableAccount> accounts = new ArrayList<>();
final Cursor cur = ContentResolverUtils.query(context.getContentResolver(),
Accounts.CONTENT_URI, Accounts.COLUMNS_NO_CREDENTIALS,
activatedOnly ? Accounts.IS_ACTIVATED + " = 1" : null, null, Accounts.SORT_POSITION);
@ -190,13 +190,13 @@ public class Account implements Parcelable {
cur.moveToFirst();
while (!cur.isAfterLast()) {
if (!officialKeyOnly) {
accounts.add(new Account(cur, indices));
accounts.add(new ParcelableAccount(cur, indices));
} else {
final String consumerKey = cur.getString(indices.consumer_key);
final String consumerSecret = cur.getString(indices.consumer_secret);
if (shouldForceUsingPrivateAPIs(context)
|| isOfficialConsumerKeySecret(context, consumerKey, consumerSecret)) {
accounts.add(new Account(cur, indices));
accounts.add(new ParcelableAccount(cur, indices));
}
}
cur.moveToNext();
@ -205,7 +205,7 @@ public class Account implements Parcelable {
return accounts;
}
public static AccountWithCredentials getAccountWithCredentials(final Context context, final long account_id) {
public static ParcelableAccountWithCredentials getAccountWithCredentials(final Context context, final long account_id) {
if (context == null) return null;
final Cursor cur = ContentResolverUtils.query(context.getContentResolver(), Accounts.CONTENT_URI,
Accounts.COLUMNS, Accounts.ACCOUNT_ID + " = " + account_id, null, null);
@ -214,7 +214,7 @@ public class Account implements Parcelable {
if (cur.getCount() > 0 && cur.moveToFirst()) {
final Indices indices = new Indices(cur);
cur.moveToFirst();
return new AccountWithCredentials(cur, indices);
return new ParcelableAccountWithCredentials(cur, indices);
}
} finally {
cur.close();
@ -223,7 +223,7 @@ public class Account implements Parcelable {
return null;
}
public static class AccountWithCredentials extends Account {
public static class ParcelableAccountWithCredentials extends ParcelableAccount {
public final int auth_type;
public final String consumer_key, consumer_secret;
@ -232,7 +232,7 @@ public class Account implements Parcelable {
public final String api_url_format;
public final boolean same_oauth_signing_url, no_version_suffix;
public AccountWithCredentials(final Cursor cursor, final Indices indices) {
public ParcelableAccountWithCredentials(final Cursor cursor, final Indices indices) {
super(cursor, indices);
auth_type = cursor.getInt(indices.auth_type);
consumer_key = cursor.getString(indices.consumer_key);
@ -254,7 +254,7 @@ public class Account implements Parcelable {
+ ", api_url_format=" + api_url_format + ", same_oauth_signing_url=" + same_oauth_signing_url + "}";
}
public static boolean isOfficialCredentials(final Context context, final AccountWithCredentials account) {
public static boolean isOfficialCredentials(final Context context, final ParcelableAccountWithCredentials account) {
if (account == null) return false;
final boolean isOAuth = account.auth_type == Accounts.AUTH_TYPE_OAUTH
|| account.auth_type == Accounts.AUTH_TYPE_XAUTH;

View File

@ -39,7 +39,7 @@ public class ParcelableStatusUpdate implements Parcelable {
}
};
public final Account[] accounts;
public final ParcelableAccount[] accounts;
public final ParcelableMediaUpdate[] media;
public final String text;
public final ParcelableLocation location;
@ -51,7 +51,7 @@ public class ParcelableStatusUpdate implements Parcelable {
* <b>ParcelableStatusUpdate.Builder</b> instead.
*/
@Deprecated
public ParcelableStatusUpdate(final Account[] accounts, final String text, final ParcelableLocation location,
public ParcelableStatusUpdate(final ParcelableAccount[] accounts, final String text, final ParcelableLocation location,
final ParcelableMediaUpdate[] media, final long in_reply_to_status_id, final boolean is_possibly_sensitive) {
this.accounts = accounts;
this.text = text;
@ -62,7 +62,7 @@ public class ParcelableStatusUpdate implements Parcelable {
}
public ParcelableStatusUpdate(final Context context, final DraftItem draft) {
accounts = Account.getAccounts(context, draft.account_ids);
accounts = ParcelableAccount.getAccounts(context, draft.account_ids);
text = draft.text;
location = draft.location;
media = draft.media;
@ -71,7 +71,7 @@ public class ParcelableStatusUpdate implements Parcelable {
}
public ParcelableStatusUpdate(final Parcel in) {
accounts = in.createTypedArray(Account.CREATOR);
accounts = in.createTypedArray(ParcelableAccount.CREATOR);
text = in.readString();
location = in.readParcelable(ParcelableLocation.class.getClassLoader());
media = in.createTypedArray(ParcelableMediaUpdate.CREATOR);
@ -103,7 +103,7 @@ public class ParcelableStatusUpdate implements Parcelable {
public static final class Builder {
private Account[] accounts;
private ParcelableAccount[] accounts;
private String text;
private ParcelableLocation location;
private ParcelableMediaUpdate[] media;
@ -123,7 +123,7 @@ public class ParcelableStatusUpdate implements Parcelable {
isPossiblySensitive(base.is_possibly_sensitive);
}
public Builder accounts(final Account[] accounts) {
public Builder accounts(final ParcelableAccount[] accounts) {
this.accounts = accounts;
return this;
}

View File

@ -36,8 +36,6 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.Switch;
import android.widget.TextView;
@ -47,7 +45,7 @@ import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.task.AsyncTask;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.Utils;
@ -76,9 +74,9 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
a.recycle();
}
public void setAccountsData(final List<Account> accounts) {
public void setAccountsData(final List<ParcelableAccount> accounts) {
removeAll();
for (final Account account : accounts) {
for (final ParcelableAccount account : accounts) {
final AccountItemPreference preference = new AccountItemPreference(getContext(), account, mSwitchKey,
mSwitchDefault);
setupPreference(preference, account);
@ -95,12 +93,12 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
new LoadAccountsTask(this).execute();
}
protected abstract void setupPreference(AccountItemPreference preference, Account account);
protected abstract void setupPreference(AccountItemPreference preference, ParcelableAccount account);
public static final class AccountItemPreference extends Preference implements ImageLoadingListener,
OnCheckedChangeListener, OnSharedPreferenceChangeListener, OnPreferenceClickListener, OnClickListener {
private final Account mAccount;
private final ParcelableAccount mAccount;
private final SharedPreferences mSwitchPreference;
private final ImageLoaderWrapper mImageLoader;
@ -108,7 +106,7 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
private final boolean mSwitchDefault;
private Switch mToggle;
public AccountItemPreference(final Context context, final Account account, final String switchKey,
public AccountItemPreference(final Context context, final ParcelableAccount account, final String switchKey,
final boolean switchDefault) {
super(context);
setWidgetLayoutResource(R.layout.preference_widget_account_preference_item);
@ -215,7 +213,7 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
}
}
private static class LoadAccountsTask extends AsyncTask<Void, Void, List<Account>> {
private static class LoadAccountsTask extends AsyncTask<Void, Void, List<ParcelableAccount>> {
private final AccountsListPreference mPreference;
@ -224,12 +222,12 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
}
@Override
protected List<Account> doInBackground(final Void... params) {
return Account.getAccountsList(mPreference.getContext(), false);
protected List<ParcelableAccount> doInBackground(final Void... params) {
return ParcelableAccount.getAccountsList(mPreference.getContext(), false);
}
@Override
protected void onPostExecute(final List<Account> result) {
protected void onPostExecute(final List<ParcelableAccount> result) {
mPreference.setAccountsData(result);
}

View File

@ -25,7 +25,7 @@ import android.util.AttributeSet;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.fragment.AccountRefreshSettingsFragment;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
public class AutoRefreshAccountsListPreference extends AccountsListPreference implements TwidereConstants {
@ -42,7 +42,7 @@ public class AutoRefreshAccountsListPreference extends AccountsListPreference im
}
@Override
protected void setupPreference(final AccountItemPreference preference, final Account account) {
protected void setupPreference(final AccountItemPreference preference, final ParcelableAccount account) {
preference.setFragment(AccountRefreshSettingsFragment.class.getName());
final Bundle args = preference.getExtras();
args.putParcelable(EXTRA_ACCOUNT, account);

View File

@ -25,7 +25,7 @@ import android.util.AttributeSet;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.fragment.AccountNotificationSettingsFragment;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.ParcelableAccount;
public class NotificationAccountsListPreference extends AccountsListPreference implements TwidereConstants {
@ -42,7 +42,7 @@ public class NotificationAccountsListPreference extends AccountsListPreference i
}
@Override
protected void setupPreference(final AccountItemPreference preference, final Account account) {
protected void setupPreference(final AccountItemPreference preference, final ParcelableAccount account) {
preference.setFragment(AccountNotificationSettingsFragment.class.getName());
final Bundle args = preference.getExtras();
args.putParcelable(EXTRA_ACCOUNT, account);

View File

@ -146,7 +146,7 @@ public class TwidereCommandProvider extends ContentProvider implements Constants
case CODE_REFRESH_HOME_TIMELINE:
if (mTwitterWrapper.isHomeTimelineRefreshing()) return getEmptyCursor();
case CODE_REFRESH_MENTIONS:
if (mTwitterWrapper.isMentionsRefreshing()) return getEmptyCursor();
if (mTwitterWrapper.isMentionsTimelineRefreshing()) return getEmptyCursor();
case CODE_REFRESH_INBOX:
if (mTwitterWrapper.isReceivedDirectMessagesRefreshing()) return getEmptyCursor();
case CODE_REFRESH_OUTBOX:

View File

@ -591,7 +591,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
isAccountSpecific = true;
break;
}
case NOTIFICATION_ID_MENTIONS: {
case NOTIFICATION_ID_MENTIONS_TIMELINE: {
mNewMentions.clear();
isAccountSpecific = true;
break;
@ -889,7 +889,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
private Cursor getNotificationsCursor() {
final MatrixCursor c = new MatrixCursor(TweetStore.Notifications.MATRIX_COLUMNS);
c.addRow(new Integer[]{NOTIFICATION_ID_HOME_TIMELINE, mUnreadStatuses.size()});
c.addRow(new Integer[]{NOTIFICATION_ID_MENTIONS, mNewMentions.size()});
c.addRow(new Integer[]{NOTIFICATION_ID_MENTIONS_TIMELINE, mNewMentions.size()});
c.addRow(new Integer[]{NOTIFICATION_ID_DIRECT_MESSAGES, mNewMessages.size()});
return c;
}
@ -898,7 +898,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
final MatrixCursor c = new MatrixCursor(TweetStore.Notifications.MATRIX_COLUMNS);
if (id == NOTIFICATION_ID_HOME_TIMELINE) {
c.addRow(new Integer[]{id, mNewStatuses.size()});
} else if (id == NOTIFICATION_ID_MENTIONS) {
} else if (id == NOTIFICATION_ID_MENTIONS_TIMELINE) {
c.addRow(new Integer[]{id, mNewMentions.size()});
} else if (id == NOTIFICATION_ID_DIRECT_MESSAGES) {
c.addRow(new Integer[]{id, mNewMessages.size()});
@ -1018,7 +1018,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
if (values == null || values.length == 0) return 0;
// Add statuses that not filtered to list for future use.
int result = 0;
final boolean enabled = mPreferences.getBoolean(KEY_FILTERS_IN_MENTIONS, true);
final boolean enabled = mPreferences.getBoolean(KEY_FILTERS_IN_MENTIONS_TIMELINE, true);
final boolean filtersForRts = mPreferences.getBoolean(KEY_FILTERS_FOR_RTS, true);
for (final ContentValues value : values) {
final ParcelableStatus status = new ParcelableStatus(value);
@ -1112,12 +1112,12 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
if (pref.isMentionsNotificationEnabled()) {
final long accountId = pref.getAccountId();
displayStatusesNotification(notifiedCount, pref, pref.getMentionsNotificationType(),
NOTIFICATION_ID_MENTIONS, getStatusesForAccounts(items, accountId),
NOTIFICATION_ID_MENTIONS_TIMELINE, getStatusesForAccounts(items, accountId),
R.string.notification_mention, R.string.notification_mention_multiple,
R.drawable.ic_stat_mention);
}
}
notifyUnreadCountChanged(NOTIFICATION_ID_MENTIONS);
notifyUnreadCountChanged(NOTIFICATION_ID_MENTIONS_TIMELINE);
break;
}
case TABLE_ID_DIRECT_MESSAGES_INBOX: {

Some files were not shown because too many files have changed in this diff Show More