improved theme

improved filters
This commit is contained in:
Mariotaku Lee 2017-09-16 22:36:21 +08:00
parent d43d6220bd
commit 6cc278d667
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
33 changed files with 167 additions and 103 deletions

View File

@ -68,7 +68,7 @@ subprojects {
KPreferences : '0.9.7', KPreferences : '0.9.7',
Kovenant : '3.3.0', Kovenant : '3.3.0',
ParcelablePlease : '1.0.2', ParcelablePlease : '1.0.2',
Chameleon : '0.9.20', Chameleon : '0.9.22',
UniqR : '0.9.4', UniqR : '0.9.4',
SQLiteQB : '0.9.15', SQLiteQB : '0.9.15',
Glide : '3.7.0', Glide : '3.7.0',

View File

@ -115,6 +115,10 @@ public class FiltersData {
@FilterScope @FilterScope
int scope = 0; int scope = 0;
public long getId() {
return _id;
}
public UserKey getUserKey() { public UserKey getUserKey() {
return userKey; return userKey;
} }
@ -149,6 +153,7 @@ public class FiltersData {
@FilterScope @FilterScope
public int getScope() { public int getScope() {
if (scope == 0) return FilterScope.DEFAULT;
return scope; return scope;
} }
@ -210,7 +215,7 @@ public class FiltersData {
@CursorField(value = Filters.SCOPE, type = "INTEGER DEFAULT 0") @CursorField(value = Filters.SCOPE, type = "INTEGER DEFAULT 0")
@JsonField(name = "scope") @JsonField(name = "scope")
@FilterScope @FilterScope
int scope = 0; int scope = FilterScope.ALL;
public long getId() { public long getId() {
return _id; return _id;
@ -243,6 +248,7 @@ public class FiltersData {
@FilterScope @FilterScope
public int getScope() { public int getScope() {
if (scope == 0) return FilterScope.DEFAULT;
return scope; return scope;
} }

View File

@ -21,29 +21,37 @@ package org.mariotaku.twidere.model;
import android.database.Cursor; import android.database.Cursor;
import android.support.annotation.NonNull;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
public class CursorReference<C extends Cursor> implements Closeable { public class CursorReference<C extends Cursor> implements Closeable {
@NonNull
private final C cursor; private final C cursor;
public CursorReference(C cursor) { private CursorReference(@NonNull C cursor) {
this.cursor = cursor; this.cursor = cursor;
} }
@NonNull
public C get() { public C get() {
return cursor; return cursor;
} }
@SuppressWarnings("unused")
@NonNull
public C component1() { public C component1() {
return get(); return get();
} }
@Override @Override
public void close() throws IOException { public void close() throws IOException {
if (cursor == null) return;
cursor.close(); cursor.close();
} }
public static <Cur extends Cursor> CursorReference<Cur> get(Cur cursor) {
return new CursorReference<>(cursor);
}
} }

View File

@ -19,10 +19,11 @@
package org.mariotaku.ktextension package org.mariotaku.ktextension
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteDatabase
import org.mariotaku.twidere.model.CursorReference import org.mariotaku.twidere.model.CursorReference
fun SQLiteDatabase.queryReference(table: String, columns: Array<String>? = null, fun SQLiteDatabase.queryReference(table: String, columns: Array<String>? = null,
selection: String? = null, selectionArgs: Array<String>? = null, groupBy: String? = null, selection: String? = null, selectionArgs: Array<String>? = null, groupBy: String? = null,
having: String? = null, orderBy: String? = null) = having: String? = null, orderBy: String? = null): CursorReference<Cursor>? =
CursorReference(query(table, columns, selection, selectionArgs, groupBy, having, orderBy)) CursorReference.get(query(table, columns, selection, selectionArgs, groupBy, having, orderBy))

View File

@ -33,7 +33,7 @@ import org.mariotaku.twidere.util.content.ContentResolverUtils
fun ContentResolver.query(uri: Uri, projection: Array<String>? = null, fun ContentResolver.query(uri: Uri, projection: Array<String>? = null,
selection: String? = null, selectionArgs: Array<String>? = null, sortOrder: String? = null, selection: String? = null, selectionArgs: Array<String>? = null, sortOrder: String? = null,
limit: String? = null): Cursor { limit: String? = null): Cursor? {
return if (limit != null) { return if (limit != null) {
query(uri.buildUpon().appendQueryParameter(QUERY_PARAM_LIMIT, limit.toString()).build(), query(uri.buildUpon().appendQueryParameter(QUERY_PARAM_LIMIT, limit.toString()).build(),
projection, selection, selectionArgs, sortOrder) projection, selection, selectionArgs, sortOrder)
@ -44,8 +44,8 @@ fun ContentResolver.query(uri: Uri, projection: Array<String>? = null,
fun ContentResolver.queryReference(uri: Uri, projection: Array<String>? = null, fun ContentResolver.queryReference(uri: Uri, projection: Array<String>? = null,
selection: String? = null, selectionArgs: Array<String>? = null, sortOrder: String? = null, selection: String? = null, selectionArgs: Array<String>? = null, sortOrder: String? = null,
limit: String? = null): CursorReference<Cursor> { limit: String? = null): CursorReference<Cursor>? {
return CursorReference(query(uri, projection, selection, selectionArgs, sortOrder, limit)) return CursorReference.get(query(uri, projection, selection, selectionArgs, sortOrder, limit))
} }
@SuppressLint("Recycle") @SuppressLint("Recycle")
@ -54,10 +54,16 @@ fun ContentResolver.rawQuery(sql: String, selectionArgs: Array<String>?, notifyU
return query(rawUri, null, null, selectionArgs, null) return query(rawUri, null, null, selectionArgs, null)
} }
@SuppressLint("Recycle")
fun ContentResolver.rawQueryReference(sql: String, selectionArgs: Array<String>?, notifyUri: Uri? = null): CursorReference<Cursor>? {
val rawUri = TwidereQueryBuilder.rawQuery(sql, notifyUri)
return queryReference(rawUri, null, null, selectionArgs, null)
}
fun <T> ContentResolver.queryOne(uri: Uri, projection: Array<String>?, selection: String?, fun <T> ContentResolver.queryOne(uri: Uri, projection: Array<String>?, selection: String?,
selectionArgs: Array<String>?, sortOrder: String? = null, cls: Class<T>): T? { selectionArgs: Array<String>?, sortOrder: String? = null, cls: Class<T>): T? {
return queryReference(uri, projection, selection, selectionArgs, sortOrder, "1").use { (cur) -> return queryReference(uri, projection, selection, selectionArgs, sortOrder, "1")?.use { (cur) ->
if (!cur.moveToFirst()) return@use null if (!cur.moveToFirst()) return@use null
val indices = ObjectCursor.indicesFrom(cur, cls) val indices = ObjectCursor.indicesFrom(cur, cls)
return@use indices.newObject(cur) return@use indices.newObject(cur)
@ -66,29 +72,29 @@ fun <T> ContentResolver.queryOne(uri: Uri, projection: Array<String>?, selection
fun <T> ContentResolver.queryAll(uri: Uri, projection: Array<String>?, selection: String?, fun <T> ContentResolver.queryAll(uri: Uri, projection: Array<String>?, selection: String?,
selectionArgs: Array<String>?, sortOrder: String? = null, cls: Class<T>): List<T> { selectionArgs: Array<String>?, sortOrder: String? = null, cls: Class<T>): List<T> {
return queryReference(uri, projection, selection, selectionArgs, sortOrder).use { (cur) -> return queryReference(uri, projection, selection, selectionArgs, sortOrder)?.use { (cur) ->
return@use cur.map(ObjectCursor.indicesFrom(cur, cls)) return@use cur.map(ObjectCursor.indicesFrom(cur, cls))
} } ?: emptyList()
} }
fun ContentResolver.queryCount(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int { fun ContentResolver.queryCount(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
val projection = arrayOf(SQLFunctions.COUNT()) val projection = arrayOf(SQLFunctions.COUNT())
return queryReference(uri, projection, selection, selectionArgs, null).use { (cur) -> return queryReference(uri, projection, selection, selectionArgs, null)?.use { (cur) ->
if (cur.moveToFirst()) { if (cur.moveToFirst()) {
return@use cur.getInt(0) return@use cur.getInt(0)
} }
return@use -1 return@use -1
} } ?: -1
} }
fun ContentResolver.queryLong(uri: Uri, field: String, selection: String?, selectionArgs: Array<String>?, def: Long = -1): Long { fun ContentResolver.queryLong(uri: Uri, field: String, selection: String?, selectionArgs: Array<String>?, def: Long = -1): Long {
val projection = arrayOf(field) val projection = arrayOf(field)
return queryReference(uri, projection, selection, selectionArgs, null, "1").use { (cur) -> return queryReference(uri, projection, selection, selectionArgs, null, "1")?.use { (cur) ->
if (cur.moveToFirst()) { if (cur.moveToFirst()) {
return@use cur.getLong(0) return@use cur.getLong(0)
} }
return@use def return@use def
} } ?: def
} }
fun <T : Any> ContentResolver.insert(uri: Uri, obj: T, cls: Class<T> = obj.javaClass): Uri? { fun <T : Any> ContentResolver.insert(uri: Uri, obj: T, cls: Class<T> = obj.javaClass): Uri? {

View File

@ -36,9 +36,8 @@ class ThemedEditTextPreferenceDialogFragmentCompat : ThemedPreferenceDialogFragm
override fun onCreateDialogView(context: Context): View { override fun onCreateDialogView(context: Context): View {
val view = super.onCreateDialogView(context) val view = super.onCreateDialogView(context)
val theme = Chameleon.getOverrideTheme(context, context) val theme = Chameleon.getOverrideTheme(context, context)
editText = view.findViewById<EditText>(android.R.id.edit) editText = view.findViewById(android.R.id.edit)
val appearance = ChameleonTextView.Appearance.create(editText, context, null, theme) val appearance = ChameleonTextView.Appearance.create(editText, context, null, theme)
appearance.backgroundTintColor = theme.colorAccent
ChameleonTextView.Appearance.apply(editText, appearance) ChameleonTextView.Appearance.apply(editText, appearance)
return view return view
} }

View File

@ -73,6 +73,9 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
else -> 0 else -> 0
} }
private val canEditValue: Boolean
get() = contentUri != Filters.Users.CONTENT_URI
private var Dialog.value: String? private var Dialog.value: String?
get() = editText.string?.takeIf(String::isNotEmpty) get() = editText.string?.takeIf(String::isNotEmpty)
set(value) { set(value) {
@ -100,30 +103,12 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
dialog as AlertDialog dialog as AlertDialog
when (which) { when (which) {
DialogInterface.BUTTON_POSITIVE -> { DialogInterface.BUTTON_POSITIVE -> {
val value = dialog.value ?: return
val scope = dialog.scope ?: return val scope = dialog.scope ?: return
if (!canEditValue) {
val values = ContentValues { saveScopeOnly(scope)
this[Filters.VALUE] = value
this[Filters.SCOPE] = scope.value
}
val uri = contentUri
val id = rowId
val resolver = context.contentResolver
if (id >= 0) {
val valueWhere = Expression.equalsArgs(Filters.VALUE).sql
val valueWhereArgs = arrayOf(value)
val matchedId = resolver.queryLong(uri, Filters._ID, valueWhere, valueWhereArgs,
-1)
if (matchedId != -1L && matchedId != id) {
Toast.makeText(context, R.string.message_toast_duplicate_filter_rule,
Toast.LENGTH_SHORT).show()
} else {
val idWhere = Expression.equals(Filters._ID, id).sql
resolver.update(uri, values, idWhere, null)
}
} else { } else {
resolver.insert(uri, values) val value = dialog.value ?: return
saveItem(value, scope)
} }
} }
} }
@ -154,6 +139,9 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
else -> null else -> null
}) })
editText.threshold = 1 editText.threshold = 1
val canEdit = canEditValue
editText.isEnabled = canEdit
editText.setTextIsSelectable(canEdit)
advancedToggle.setOnClickListener { advancedToggle.setOnClickListener {
advancedExpanded = !advancedExpanded advancedExpanded = !advancedExpanded
} }
@ -231,6 +219,45 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
isChecked = scopes[scope] isChecked = scopes[scope]
} }
private fun saveScopeOnly(scopes: FilterScopes) {
val resolver = context.contentResolver
val contentUri = contentUri
val rowId = rowId
if (rowId < 0) return
val values = ContentValues {
this[Filters.SCOPE] = scopes.value
}
val idWhere = Expression.equals(Filters._ID, rowId).sql
resolver.update(contentUri, values, idWhere, null)
}
private fun saveItem(value: String, scopes: FilterScopes) {
val resolver = context.contentResolver
val uri = contentUri
val rowId = rowId
val values = ContentValues {
this[Filters.VALUE] = value
this[Filters.SCOPE] = scopes.value
}
if (rowId >= 0) {
val valueWhere = Expression.equalsArgs(Filters.VALUE).sql
val valueWhereArgs = arrayOf(value)
val matchedId = resolver.queryLong(uri, Filters._ID, valueWhere, valueWhereArgs,
-1)
if (matchedId != -1L && matchedId != rowId) {
Toast.makeText(context, R.string.message_toast_duplicate_filter_rule,
Toast.LENGTH_SHORT).show()
} else {
val idWhere = Expression.equals(Filters._ID, rowId).sql
resolver.update(uri, values, idWhere, null)
}
} else {
resolver.insert(uri, values)
}
}
class FilterScopes(val masks: Int, value: Int = 0) : Parcelable { class FilterScopes(val masks: Int, value: Int = 0) : Parcelable {
var value: Int = 0 var value: Int = 0

View File

@ -83,11 +83,7 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
setHasOptionsMenu(true) setHasOptionsMenu(true)
listView.choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL listView.choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL
listView.setOnItemClickListener { _, _, pos, _ -> listView.setOnItemClickListener { _, _, pos, _ ->
if (!supportsEdit) return@setOnItemClickListener onItemClick(pos)
val adapter = this.adapter as FilterListAdapter
val item = adapter.getFilterItem(pos) ?: return@setOnItemClickListener
if (item.source >= 0) return@setOnItemClickListener
addOrEditItem(item.id, item.value, item.scope)
} }
listView.setMultiChoiceModeListener(this) listView.setMultiChoiceModeListener(this)
loaderManager.initLoader(0, null, this) loaderManager.initLoader(0, null, this)
@ -110,7 +106,6 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
actionMode = mode actionMode = mode
setControlVisible(true) setControlVisible(true)
mode.menuInflater.inflate(R.menu.action_multi_select_items, menu) mode.menuInflater.inflate(R.menu.action_multi_select_items, menu)
mode.menuInflater.inflate(R.menu.action_multi_select_filtered_users, menu)
menu.setGroupAvailability(R.id.selection_group, true) menu.setGroupAvailability(R.id.selection_group, true)
return true return true
} }
@ -217,6 +212,13 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
return FilterListAdapter(context) return FilterListAdapter(context)
} }
protected open fun onItemClick(position: Int) {
val adapter = this.adapter as FilterListAdapter
val item = adapter.getFilterItem(position) ?: return
if (item.source >= 0) return
addOrEditItem(item.id, item.value, item.scope)
}
protected open fun performDeletion() { protected open fun performDeletion() {
val ids = listView.checkedItemIds val ids = listView.checkedItemIds
val where = Expression.inArgs(Columns.Column(Filters._ID), ids.size) val where = Expression.inArgs(Columns.Column(Filters._ID), ids.size)

View File

@ -22,6 +22,7 @@ import kotlinx.android.synthetic.main.fragment_content_listview.*
import nl.komponents.kovenant.then import nl.komponents.kovenant.then
import nl.komponents.kovenant.ui.alwaysUi import nl.komponents.kovenant.ui.alwaysUi
import org.mariotaku.kpreferences.KPreferences import org.mariotaku.kpreferences.KPreferences
import org.mariotaku.kpreferences.get
import org.mariotaku.ktextension.* import org.mariotaku.ktextension.*
import org.mariotaku.library.objectcursor.ObjectCursor import org.mariotaku.library.objectcursor.ObjectCursor
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
@ -140,6 +141,12 @@ class FilteredUsersFragment : BaseFiltersFragment() {
return true return true
} }
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
super.onCreateActionMode(mode, menu)
mode.menuInflater.inflate(R.menu.action_multi_select_filtered_users, menu)
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
val result = super.onPrepareActionMode(mode, menu) val result = super.onPrepareActionMode(mode, menu)
val isFeaturesSupported = extraFeaturesService.isSupported() val isFeaturesSupported = extraFeaturesService.isSupported()
@ -161,8 +168,18 @@ class FilteredUsersFragment : BaseFiltersFragment() {
return FilterUsersListAdapter(context) return FilterUsersListAdapter(context)
} }
override fun onItemClick(position: Int) {
val adapter = this.adapter as FilterUsersListAdapter
val item = adapter.getFilterItem(position) ?: return
if (item.source >= 0) return
addOrEditItem(item.id, userColorNameManager.getDisplayName(item,
preferences[nameFirstKey]), item.scope)
}
override fun addOrEditItem(id: Long, value: String?, scope: Int) { override fun addOrEditItem(id: Long, value: String?, scope: Int) {
// No-op // No-op
if (id < 0) return
super.addOrEditItem(id, value, scope)
} }
override fun performDeletion() { override fun performDeletion() {
@ -289,6 +306,15 @@ class FilteredUsersFragment : BaseFiltersFragment() {
} }
return null return null
} }
fun getFilterItem(position: Int): FiltersData.UserItem? {
val cursor = this.cursor ?: return null
val indices = this.indices ?: return null
if (cursor.moveToPosition(position)) {
return indices.newObject(cursor)
}
return null
}
} }
} }

View File

@ -60,8 +60,7 @@ class UpdateAccountInfoTask(
private fun updateTabs(resolver: ContentResolver, accountKey: UserKey) { private fun updateTabs(resolver: ContentResolver, accountKey: UserKey) {
resolver.queryReference(Tabs.CONTENT_URI, Tabs.COLUMNS, null, null, resolver.queryReference(Tabs.CONTENT_URI, Tabs.COLUMNS, null, null,
null).use { (tabsCursor) -> null)?.use { (tabsCursor) ->
if (tabsCursor == null) return
val indices = ObjectCursor.indicesFrom(tabsCursor, Tab::class.java) val indices = ObjectCursor.indicesFrom(tabsCursor, Tab::class.java)
val creator = ObjectCursor.valuesCreatorFrom(Tab::class.java) val creator = ObjectCursor.valuesCreatorFrom(Tab::class.java)
tabsCursor.moveToFirst() tabsCursor.moveToFirst()

View File

@ -26,8 +26,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Accounts
@Suppress("deprecation") @Suppress("deprecation")
fun migrateAccounts(am: AccountManager, db: SQLiteDatabase) { fun migrateAccounts(am: AccountManager, db: SQLiteDatabase) {
db.queryReference(Accounts.TABLE_NAME, Accounts.COLUMNS, null, null, db.queryReference(Accounts.TABLE_NAME, Accounts.COLUMNS, null, null,
null, null, null).use { (cur) -> null, null, null)?.use { (cur) ->
if (cur == null) return
val indices = ObjectCursor.indicesFrom(cur, ParcelableCredentials::class.java) val indices = ObjectCursor.indicesFrom(cur, ParcelableCredentials::class.java)
cur.moveToFirst() cur.moveToFirst()
while (!cur.isAfterLast) { while (!cur.isAfterLast) {

View File

@ -31,7 +31,7 @@ fun Context.deleteDrafts(draftIds: LongArray): Int {
val where = Expression.inArgs(Drafts._ID, draftIds.size).sql val where = Expression.inArgs(Drafts._ID, draftIds.size).sql
val whereArgs = draftIds.mapToArray(Long::toString) val whereArgs = draftIds.mapToArray(Long::toString)
contentResolver.queryReference(Drafts.CONTENT_URI, Drafts.COLUMNS, where, whereArgs, null).use { (cursor) -> contentResolver.queryReference(Drafts.CONTENT_URI, Drafts.COLUMNS, where, whereArgs, null)?.use { (cursor) ->
val indices = ObjectCursor.indicesFrom(cursor, Draft::class.java) val indices = ObjectCursor.indicesFrom(cursor, Draft::class.java)
cursor.moveToFirst() cursor.moveToFirst()
while (!cursor.isAfterLast) { while (!cursor.isAfterLast) {
@ -126,8 +126,7 @@ fun <T> ContentResolver.updateItems(uri: Uri, columns: Array<String>?, where: St
whereArgs: Array<String>?, cls: Class<T>, action: (T) -> T) { whereArgs: Array<String>?, cls: Class<T>, action: (T) -> T) {
val values = LongSparseArray<ContentValues>() val values = LongSparseArray<ContentValues>()
queryReference(uri, columns, where, whereArgs, null).use { (c) -> queryReference(uri, columns, where, whereArgs, null)?.use { (c) ->
if (c == null) return
val ci = ObjectCursor.indicesFrom(c, cls) val ci = ObjectCursor.indicesFrom(c, cls)
val vc = ObjectCursor.valuesCreatorFrom(cls) val vc = ObjectCursor.valuesCreatorFrom(cls)
c.moveToFirst() c.moveToFirst()

View File

@ -286,12 +286,12 @@ object DataStoreUtils {
Expression.notEquals("${Filters.Users.SCOPE} & $scope", 0) Expression.notEquals("${Filters.Users.SCOPE} & $scope", 0)
) )
return resolver.queryReference(Filters.Users.CONTENT_URI, projection, where.sql, return resolver.queryReference(Filters.Users.CONTENT_URI, projection, where.sql,
null, null).use { (cur) -> null, null)?.use { (cur) ->
return@use Array(cur.count) { i -> return@use Array(cur.count) { i ->
cur.moveToPosition(i) cur.moveToPosition(i)
UserKey.valueOf(cur.getString(0)) UserKey.valueOf(cur.getString(0))
} }
} } ?: emptyArray()
} }
fun getFilteredKeywords(context: Context, @FilterScope scope: Int): Array<String> { fun getFilteredKeywords(context: Context, @FilterScope scope: Int): Array<String> {
@ -302,12 +302,12 @@ object DataStoreUtils {
Expression.notEquals("${Filters.SCOPE} & $scope", 0) Expression.notEquals("${Filters.SCOPE} & $scope", 0)
) )
return resolver.queryReference(Filters.Keywords.CONTENT_URI, projection, where.sql, return resolver.queryReference(Filters.Keywords.CONTENT_URI, projection, where.sql,
null, null).use { (cur) -> null, null)?.use { (cur) ->
return@use Array(cur.count) { i -> return@use Array(cur.count) { i ->
cur.moveToPosition(i) cur.moveToPosition(i)
cur.getString(0) cur.getString(0)
} }
} } ?: emptyArray()
} }
fun getAccountDisplayName(context: Context, accountKey: UserKey, nameFirst: Boolean): String? { fun getAccountDisplayName(context: Context, accountKey: UserKey, nameFirst: Boolean): String? {
@ -418,8 +418,7 @@ object DataStoreUtils {
val resolver = context.contentResolver val resolver = context.contentResolver
if (followingOnly) { if (followingOnly) {
val projection = arrayOf(Activities.SOURCES) val projection = arrayOf(Activities.SOURCES)
return resolver.queryReference(uri, projection, selection.sql, selectionArgs, null).use { (cur) -> return resolver.queryReference(uri, projection, selection.sql, selectionArgs, null)?.use { (cur) ->
if (cur == null) return@use 0
var total = 0 var total = 0
cur.moveToFirst() cur.moveToFirst()
while (!cur.isAfterLast) { while (!cur.isAfterLast) {
@ -443,7 +442,7 @@ object DataStoreUtils {
cur.moveToNext() cur.moveToNext()
} }
return@use total return@use total
} } ?: 0
} }
return resolver.queryCount(uri, selection.sql, selectionArgs) return resolver.queryCount(uri, selection.sql, selectionArgs)
} }

View File

@ -97,6 +97,10 @@ class UserColorNameManager(context: Context) {
return getDisplayName(status.user_key, status.user_name, status.user_screen_name, nameFirst) return getDisplayName(status.user_key, status.user_name, status.user_screen_name, nameFirst)
} }
fun getDisplayName(user: FiltersData.UserItem, nameFirst: Boolean): String {
return getDisplayName(user.userKey, user.name, user.screenName, nameFirst)
}
fun getDisplayName(userKey: UserKey, name: String, screenName: String, nameFirst: Boolean): String { fun getDisplayName(userKey: UserKey, name: String, screenName: String, nameFirst: Boolean): String {
return getDisplayName(userKey.toString(), name, screenName, nameFirst) return getDisplayName(userKey.toString(), name, screenName, nameFirst)
} }

View File

@ -21,39 +21,24 @@ package org.mariotaku.twidere.util.database
import android.content.ContentResolver import android.content.ContentResolver
import org.mariotaku.twidere.annotation.FilterScope import org.mariotaku.twidere.annotation.FilterScope
import org.mariotaku.twidere.extension.rawQuery import org.mariotaku.twidere.extension.rawQueryReference
import org.mariotaku.twidere.model.ParcelableStatus import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.provider.TwidereDataStore.Filters.* import org.mariotaku.twidere.provider.TwidereDataStore.Filters.*
/**
* Created by mariotaku on 2017/2/16.
*/
object ContentFiltersUtils { object ContentFiltersUtils {
fun isFiltered(cr: ContentResolver, status: ParcelableStatus, filterRts: Boolean, fun isFiltered(cr: ContentResolver, status: ParcelableStatus, filterRts: Boolean,
@FilterScope scope: Int, allowedKeywords: Array<String>? = null): Boolean { @FilterScope scope: Int, allowedKeywords: Array<String>? = null): Boolean {
return isFiltered(cr, status.filter_users, status.filter_texts, val query = isFilteredQuery(status.filter_users, status.filter_texts,
status.filter_sources, status.filter_links, status.filter_names, status.filter_sources, status.filter_links, status.filter_names,
status.filter_descriptions, filterRts, scope, allowedKeywords) status.filter_descriptions, filterRts, scope, allowedKeywords)
return cr.rawQueryReference(query.first, query.second)?.use { (cur) ->
cur.moveToFirst() && cur.getInt(0) != 0
} ?: false
} }
fun isFiltered(cr: ContentResolver, users: Array<UserKey>?, texts: String?, sources: Array<String>?, private fun isFilteredQuery(users: Array<UserKey>?, texts: String?, sources: Array<String>?,
links: Array<String>?, names: Array<String>?, descriptions: String?, filterRts: Boolean,
@FilterScope scope: Int, allowedKeywords: Array<String>? = null): Boolean {
val query = isFilteredQuery(users, texts, sources, links, names, descriptions, true,
scope, allowedKeywords)
val cur = cr.rawQuery(query.first, query.second) ?: return false
@Suppress("ConvertTryFinallyToUseCall")
try {
return cur.moveToFirst() && cur.getInt(0) != 0
} finally {
cur.close()
}
}
fun isFilteredQuery(users: Array<UserKey>?, texts: String?, sources: Array<String>?,
links: Array<String>?, names: Array<String>?, descriptions: String?, links: Array<String>?, names: Array<String>?, descriptions: String?,
filterRts: Boolean, @FilterScope scope: Int, allowedKeywords: Array<String>? = null): Pair<String, Array<String>> { filterRts: Boolean, @FilterScope scope: Int, allowedKeywords: Array<String>? = null): Pair<String, Array<String>> {
val selectionArgs = mutableListOf<String>() val selectionArgs = mutableListOf<String>()

View File

@ -205,8 +205,8 @@ class ContentNotificationManager(
val (remaining, consumed) = cr.queryReference(Activities.AboutMe.CONTENT_URI, Activities.COLUMNS, val (remaining, consumed) = cr.queryReference(Activities.AboutMe.CONTENT_URI, Activities.COLUMNS,
filteredSelection.sql, selectionArgs, filteredSelection.sql, selectionArgs,
OrderBy(Activities.TIMESTAMP, false).sql).use { (cur) -> OrderBy(Activities.TIMESTAMP, false).sql)?.use { (cur) ->
if (cur == null || cur.isEmpty) return@use Pair(-1, -1) if (cur.isEmpty) return@use Pair(-1, -1)
val ci = ObjectCursor.indicesFrom(cur, ParcelableActivity::class.java) val ci = ObjectCursor.indicesFrom(cur, ParcelableActivity::class.java)
var con = 0 var con = 0
val rem = cur.forEachRow(5) { c, _ -> val rem = cur.forEachRow(5) { c, _ ->
@ -248,7 +248,7 @@ class ContentNotificationManager(
return@forEachRow true return@forEachRow true
} }
return@use Pair(rem, con) return@use Pair(rem, con)
} } ?: Pair(-1, -1)
if (remaining < 0) return if (remaining < 0) return
if (remaining > 0) { if (remaining > 0) {
style.addLine(resources.getString(R.string.and_N_more, remaining)) style.addLine(resources.getString(R.string.and_N_more, remaining))

View File

@ -46,7 +46,7 @@
android:inputType="textEmailAddress" android:inputType="textEmailAddress"
android:maxLines="1" android:maxLines="1"
android:typeface="normal" android:typeface="normal"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
<org.mariotaku.twidere.view.FixedEditText <org.mariotaku.twidere.view.FixedEditText
android:id="@+id/editPassword" android:id="@+id/editPassword"
@ -57,7 +57,7 @@
android:inputType="textPassword" android:inputType="textPassword"
android:maxLines="1" android:maxLines="1"
android:typeface="normal" android:typeface="normal"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
</LinearLayout> </LinearLayout>
<android.support.v7.widget.AppCompatButton <android.support.v7.widget.AppCompatButton

View File

@ -44,7 +44,7 @@
android:ems="10" android:ems="10"
android:hint="@string/search_hint_users" android:hint="@string/search_hint_users"
android:maxLines="1" android:maxLines="1"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
<org.mariotaku.twidere.view.IconActionButton <org.mariotaku.twidere.view.IconActionButton
android:id="@+id/screenNameConfirm" android:id="@+id/screenNameConfirm"

View File

@ -36,7 +36,7 @@
app:met_baseColor="?android:textColorPrimary" app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal" app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/title_subscription_name" app:met_floatingLabelText="@string/title_subscription_name"
app:met_primaryColor="?colorAccent"/> app:met_primaryColor="?colorControlStateful"/>
<com.rengwuxian.materialedittext.MaterialEditText <com.rengwuxian.materialedittext.MaterialEditText
android:id="@+id/url" android:id="@+id/url"
@ -49,6 +49,6 @@
app:met_baseColor="?android:textColorPrimary" app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal" app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/title_subscription_url" app:met_floatingLabelText="@string/title_subscription_url"
app:met_primaryColor="?colorAccent"/> app:met_primaryColor="?colorControlStateful"/>
</LinearLayout> </LinearLayout>

View File

@ -39,7 +39,7 @@
android:hint="@string/host_mapping_host" android:hint="@string/host_mapping_host"
android:inputType="text|textUri" android:inputType="text|textUri"
android:maxLines="1" android:maxLines="1"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
<org.mariotaku.twidere.view.FixedEditText <org.mariotaku.twidere.view.FixedEditText
android:id="@+id/editAddress" android:id="@+id/editAddress"
@ -49,6 +49,6 @@
android:hint="@string/host_mapping_address" android:hint="@string/host_mapping_address"
android:inputType="text|textUri" android:inputType="text|textUri"
android:maxLines="1" android:maxLines="1"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
</LinearLayout> </LinearLayout>

View File

@ -69,7 +69,7 @@
android:ems="10" android:ems="10"
android:inputType="textUri" android:inputType="textUri"
android:maxLines="1" android:maxLines="1"
app:backgroundTint="?colorAccent" app:backgroundTint="?colorControlStateful"
tools:text="https://api.twitter.com/"/> tools:text="https://api.twitter.com/"/>
<org.mariotaku.twidere.view.FixedTextView <org.mariotaku.twidere.view.FixedTextView

View File

@ -31,6 +31,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:completionThreshold="1" android:completionThreshold="1"
android:maxLines="1" android:maxLines="1"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
</FrameLayout> </FrameLayout>

View File

@ -12,6 +12,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="text" android:inputType="text"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
</LinearLayout> </LinearLayout>

View File

@ -32,6 +32,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/hint_conversation_name" android:hint="@string/hint_conversation_name"
android:maxLines="1" android:maxLines="1"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
</LinearLayout> </LinearLayout>

View File

@ -13,7 +13,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="text|textPersonName" android:inputType="text|textPersonName"
android:maxLines="1" android:maxLines="1"
app:backgroundTint="?colorAccent" app:backgroundTint="?colorControlStateful"
tools:text="Nickname"/> tools:text="Nickname"/>
</FrameLayout> </FrameLayout>

View File

@ -35,7 +35,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:completionThreshold="1" android:completionThreshold="1"
android:maxLines="1" android:maxLines="1"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
<LinearLayout <LinearLayout
android:id="@+id/advancedToggle" android:id="@+id/advancedToggle"

View File

@ -39,7 +39,7 @@
android:layout_margin="@dimen/element_spacing_normal" android:layout_margin="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceMedium" android:textAppearance="?android:textAppearanceMedium"
android:typeface="monospace" android:typeface="monospace"
app:backgroundTint="?colorAccent"> app:backgroundTint="?colorControlStateful">
<requestFocus/> <requestFocus/>
</org.mariotaku.twidere.view.FixedEditText> </org.mariotaku.twidere.view.FixedEditText>

View File

@ -15,7 +15,7 @@
android:inputType="textEmailAddress" android:inputType="textEmailAddress"
android:maxLines="1" android:maxLines="1"
android:typeface="normal" android:typeface="normal"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
<org.mariotaku.twidere.view.FixedEditText <org.mariotaku.twidere.view.FixedEditText
android:id="@+id/editPassword" android:id="@+id/editPassword"
@ -26,6 +26,6 @@
android:inputType="textPassword" android:inputType="textPassword"
android:maxLines="1" android:maxLines="1"
android:typeface="normal" android:typeface="normal"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
</LinearLayout> </LinearLayout>

View File

@ -54,7 +54,7 @@
android:hint="@string/comment_hint" android:hint="@string/comment_hint"
android:inputType="textMultiLine|textLongMessage|textCapSentences" android:inputType="textMultiLine|textLongMessage|textCapSentences"
android:visibility="visible" android:visibility="visible"
app:backgroundTint="?colorAccent"> app:backgroundTint="?colorControlStateful">
<requestFocus/> <requestFocus/>
</org.mariotaku.twidere.view.ComposeEditText> </org.mariotaku.twidere.view.ComposeEditText>

View File

@ -33,7 +33,7 @@
android:layout_weight="0" android:layout_weight="0"
android:hint="@string/hint_message_select_user" android:hint="@string/hint_message_select_user"
android:minLines="1" android:minLines="1"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView" android:id="@+id/recyclerView"

View File

@ -11,6 +11,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/element_spacing_normal" android:layout_margin="@dimen/element_spacing_normal"
app:backgroundTint="?colorAccent"/> app:backgroundTint="?colorControlStateful"/>
</LinearLayout> </LinearLayout>

View File

@ -39,6 +39,7 @@
<item name="colorToolbar">@color/background_color_action_bar_dark</item> <item name="colorToolbar">@color/background_color_action_bar_dark</item>
<item name="isToolbarColored">false</item> <item name="isToolbarColored">false</item>
<item name="colorControlStateful">?colorControlNormal</item>
<item name="actionBarTheme">@style/Theme.Twidere.Dark.ActionBar</item> <item name="actionBarTheme">@style/Theme.Twidere.Dark.ActionBar</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item> <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
@ -70,6 +71,7 @@
<item name="colorToolbar">@color/background_color_action_bar_dark</item> <item name="colorToolbar">@color/background_color_action_bar_dark</item>
<item name="isToolbarColored">false</item> <item name="isToolbarColored">false</item>
<item name="colorControlStateful">?colorControlNormal</item>
<item name="actionBarTheme">@null</item> <item name="actionBarTheme">@null</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item> <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>

View File

@ -39,6 +39,7 @@
<item name="colorToolbar">?colorPrimary</item> <item name="colorToolbar">?colorPrimary</item>
<item name="isToolbarColored">true</item> <item name="isToolbarColored">true</item>
<item name="colorControlStateful">?colorControlNormal</item>
<item name="actionBarTheme">@style/Theme.Twidere.Light.ActionBar</item> <item name="actionBarTheme">@style/Theme.Twidere.Light.ActionBar</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item> <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
@ -71,6 +72,7 @@
<item name="colorToolbar">?colorPrimary</item> <item name="colorToolbar">?colorPrimary</item>
<item name="isToolbarColored">true</item> <item name="isToolbarColored">true</item>
<item name="colorControlStateful">?colorControlNormal</item>
<item name="actionBarTheme">@null</item> <item name="actionBarTheme">@null</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item> <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>