parent
d43d6220bd
commit
6cc278d667
|
@ -68,7 +68,7 @@ subprojects {
|
|||
KPreferences : '0.9.7',
|
||||
Kovenant : '3.3.0',
|
||||
ParcelablePlease : '1.0.2',
|
||||
Chameleon : '0.9.20',
|
||||
Chameleon : '0.9.22',
|
||||
UniqR : '0.9.4',
|
||||
SQLiteQB : '0.9.15',
|
||||
Glide : '3.7.0',
|
||||
|
|
|
@ -115,6 +115,10 @@ public class FiltersData {
|
|||
@FilterScope
|
||||
int scope = 0;
|
||||
|
||||
public long getId() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
public UserKey getUserKey() {
|
||||
return userKey;
|
||||
}
|
||||
|
@ -149,6 +153,7 @@ public class FiltersData {
|
|||
|
||||
@FilterScope
|
||||
public int getScope() {
|
||||
if (scope == 0) return FilterScope.DEFAULT;
|
||||
return scope;
|
||||
}
|
||||
|
||||
|
@ -210,7 +215,7 @@ public class FiltersData {
|
|||
@CursorField(value = Filters.SCOPE, type = "INTEGER DEFAULT 0")
|
||||
@JsonField(name = "scope")
|
||||
@FilterScope
|
||||
int scope = 0;
|
||||
int scope = FilterScope.ALL;
|
||||
|
||||
public long getId() {
|
||||
return _id;
|
||||
|
@ -243,6 +248,7 @@ public class FiltersData {
|
|||
|
||||
@FilterScope
|
||||
public int getScope() {
|
||||
if (scope == 0) return FilterScope.DEFAULT;
|
||||
return scope;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,29 +21,37 @@ package org.mariotaku.twidere.model;
|
|||
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CursorReference<C extends Cursor> implements Closeable {
|
||||
|
||||
@NonNull
|
||||
private final C cursor;
|
||||
|
||||
public CursorReference(C cursor) {
|
||||
private CursorReference(@NonNull C cursor) {
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public C get() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@NonNull
|
||||
public C component1() {
|
||||
return get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (cursor == null) return;
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
public static <Cur extends Cursor> CursorReference<Cur> get(Cur cursor) {
|
||||
return new CursorReference<>(cursor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,11 @@
|
|||
|
||||
package org.mariotaku.ktextension
|
||||
|
||||
import android.database.Cursor
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import org.mariotaku.twidere.model.CursorReference
|
||||
|
||||
fun SQLiteDatabase.queryReference(table: String, columns: Array<String>? = null,
|
||||
selection: String? = null, selectionArgs: Array<String>? = null, groupBy: String? = null,
|
||||
having: String? = null, orderBy: String? = null) =
|
||||
CursorReference(query(table, columns, selection, selectionArgs, groupBy, having, orderBy))
|
||||
having: String? = null, orderBy: String? = null): CursorReference<Cursor>? =
|
||||
CursorReference.get(query(table, columns, selection, selectionArgs, groupBy, having, orderBy))
|
|
@ -33,7 +33,7 @@ import org.mariotaku.twidere.util.content.ContentResolverUtils
|
|||
|
||||
fun ContentResolver.query(uri: Uri, projection: Array<String>? = null,
|
||||
selection: String? = null, selectionArgs: Array<String>? = null, sortOrder: String? = null,
|
||||
limit: String? = null): Cursor {
|
||||
limit: String? = null): Cursor? {
|
||||
return if (limit != null) {
|
||||
query(uri.buildUpon().appendQueryParameter(QUERY_PARAM_LIMIT, limit.toString()).build(),
|
||||
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,
|
||||
selection: String? = null, selectionArgs: Array<String>? = null, sortOrder: String? = null,
|
||||
limit: String? = null): CursorReference<Cursor> {
|
||||
return CursorReference(query(uri, projection, selection, selectionArgs, sortOrder, limit))
|
||||
limit: String? = null): CursorReference<Cursor>? {
|
||||
return CursorReference.get(query(uri, projection, selection, selectionArgs, sortOrder, limit))
|
||||
}
|
||||
|
||||
@SuppressLint("Recycle")
|
||||
|
@ -54,10 +54,16 @@ fun ContentResolver.rawQuery(sql: String, selectionArgs: Array<String>?, notifyU
|
|||
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?,
|
||||
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
|
||||
val indices = ObjectCursor.indicesFrom(cur, cls)
|
||||
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?,
|
||||
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))
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
fun ContentResolver.queryCount(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
|
||||
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()) {
|
||||
return@use cur.getInt(0)
|
||||
}
|
||||
return@use -1
|
||||
}
|
||||
} ?: -1
|
||||
}
|
||||
|
||||
fun ContentResolver.queryLong(uri: Uri, field: String, selection: String?, selectionArgs: Array<String>?, def: Long = -1): Long {
|
||||
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()) {
|
||||
return@use cur.getLong(0)
|
||||
}
|
||||
return@use def
|
||||
}
|
||||
} ?: def
|
||||
}
|
||||
|
||||
fun <T : Any> ContentResolver.insert(uri: Uri, obj: T, cls: Class<T> = obj.javaClass): Uri? {
|
||||
|
|
|
@ -36,9 +36,8 @@ class ThemedEditTextPreferenceDialogFragmentCompat : ThemedPreferenceDialogFragm
|
|||
override fun onCreateDialogView(context: Context): View {
|
||||
val view = super.onCreateDialogView(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)
|
||||
appearance.backgroundTintColor = theme.colorAccent
|
||||
ChameleonTextView.Appearance.apply(editText, appearance)
|
||||
return view
|
||||
}
|
||||
|
|
|
@ -73,6 +73,9 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
else -> 0
|
||||
}
|
||||
|
||||
private val canEditValue: Boolean
|
||||
get() = contentUri != Filters.Users.CONTENT_URI
|
||||
|
||||
private var Dialog.value: String?
|
||||
get() = editText.string?.takeIf(String::isNotEmpty)
|
||||
set(value) {
|
||||
|
@ -100,30 +103,12 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
dialog as AlertDialog
|
||||
when (which) {
|
||||
DialogInterface.BUTTON_POSITIVE -> {
|
||||
val value = dialog.value ?: return
|
||||
val scope = dialog.scope ?: return
|
||||
|
||||
val values = ContentValues {
|
||||
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)
|
||||
}
|
||||
if (!canEditValue) {
|
||||
saveScopeOnly(scope)
|
||||
} else {
|
||||
resolver.insert(uri, values)
|
||||
val value = dialog.value ?: return
|
||||
saveItem(value, scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,6 +139,9 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
else -> null
|
||||
})
|
||||
editText.threshold = 1
|
||||
val canEdit = canEditValue
|
||||
editText.isEnabled = canEdit
|
||||
editText.setTextIsSelectable(canEdit)
|
||||
advancedToggle.setOnClickListener {
|
||||
advancedExpanded = !advancedExpanded
|
||||
}
|
||||
|
@ -231,6 +219,45 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
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 {
|
||||
|
||||
var value: Int = 0
|
||||
|
|
|
@ -83,11 +83,7 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
|
|||
setHasOptionsMenu(true)
|
||||
listView.choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL
|
||||
listView.setOnItemClickListener { _, _, pos, _ ->
|
||||
if (!supportsEdit) return@setOnItemClickListener
|
||||
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)
|
||||
onItemClick(pos)
|
||||
}
|
||||
listView.setMultiChoiceModeListener(this)
|
||||
loaderManager.initLoader(0, null, this)
|
||||
|
@ -110,7 +106,6 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
|
|||
actionMode = mode
|
||||
setControlVisible(true)
|
||||
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)
|
||||
return true
|
||||
}
|
||||
|
@ -217,6 +212,13 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
|
|||
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() {
|
||||
val ids = listView.checkedItemIds
|
||||
val where = Expression.inArgs(Columns.Column(Filters._ID), ids.size)
|
||||
|
|
|
@ -22,6 +22,7 @@ import kotlinx.android.synthetic.main.fragment_content_listview.*
|
|||
import nl.komponents.kovenant.then
|
||||
import nl.komponents.kovenant.ui.alwaysUi
|
||||
import org.mariotaku.kpreferences.KPreferences
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.*
|
||||
import org.mariotaku.library.objectcursor.ObjectCursor
|
||||
import org.mariotaku.twidere.R
|
||||
|
@ -140,6 +141,12 @@ class FilteredUsersFragment : BaseFiltersFragment() {
|
|||
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 {
|
||||
val result = super.onPrepareActionMode(mode, menu)
|
||||
val isFeaturesSupported = extraFeaturesService.isSupported()
|
||||
|
@ -161,8 +168,18 @@ class FilteredUsersFragment : BaseFiltersFragment() {
|
|||
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) {
|
||||
// No-op
|
||||
if (id < 0) return
|
||||
super.addOrEditItem(id, value, scope)
|
||||
}
|
||||
|
||||
override fun performDeletion() {
|
||||
|
@ -289,6 +306,15 @@ class FilteredUsersFragment : BaseFiltersFragment() {
|
|||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -60,8 +60,7 @@ class UpdateAccountInfoTask(
|
|||
|
||||
private fun updateTabs(resolver: ContentResolver, accountKey: UserKey) {
|
||||
resolver.queryReference(Tabs.CONTENT_URI, Tabs.COLUMNS, null, null,
|
||||
null).use { (tabsCursor) ->
|
||||
if (tabsCursor == null) return
|
||||
null)?.use { (tabsCursor) ->
|
||||
val indices = ObjectCursor.indicesFrom(tabsCursor, Tab::class.java)
|
||||
val creator = ObjectCursor.valuesCreatorFrom(Tab::class.java)
|
||||
tabsCursor.moveToFirst()
|
||||
|
|
|
@ -26,8 +26,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Accounts
|
|||
@Suppress("deprecation")
|
||||
fun migrateAccounts(am: AccountManager, db: SQLiteDatabase) {
|
||||
db.queryReference(Accounts.TABLE_NAME, Accounts.COLUMNS, null, null,
|
||||
null, null, null).use { (cur) ->
|
||||
if (cur == null) return
|
||||
null, null, null)?.use { (cur) ->
|
||||
val indices = ObjectCursor.indicesFrom(cur, ParcelableCredentials::class.java)
|
||||
cur.moveToFirst()
|
||||
while (!cur.isAfterLast) {
|
||||
|
|
|
@ -31,7 +31,7 @@ fun Context.deleteDrafts(draftIds: LongArray): Int {
|
|||
val where = Expression.inArgs(Drafts._ID, draftIds.size).sql
|
||||
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)
|
||||
cursor.moveToFirst()
|
||||
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) {
|
||||
val values = LongSparseArray<ContentValues>()
|
||||
|
||||
queryReference(uri, columns, where, whereArgs, null).use { (c) ->
|
||||
if (c == null) return
|
||||
queryReference(uri, columns, where, whereArgs, null)?.use { (c) ->
|
||||
val ci = ObjectCursor.indicesFrom(c, cls)
|
||||
val vc = ObjectCursor.valuesCreatorFrom(cls)
|
||||
c.moveToFirst()
|
||||
|
|
|
@ -286,12 +286,12 @@ object DataStoreUtils {
|
|||
Expression.notEquals("${Filters.Users.SCOPE} & $scope", 0)
|
||||
)
|
||||
return resolver.queryReference(Filters.Users.CONTENT_URI, projection, where.sql,
|
||||
null, null).use { (cur) ->
|
||||
null, null)?.use { (cur) ->
|
||||
return@use Array(cur.count) { i ->
|
||||
cur.moveToPosition(i)
|
||||
UserKey.valueOf(cur.getString(0))
|
||||
}
|
||||
}
|
||||
} ?: emptyArray()
|
||||
}
|
||||
|
||||
fun getFilteredKeywords(context: Context, @FilterScope scope: Int): Array<String> {
|
||||
|
@ -302,12 +302,12 @@ object DataStoreUtils {
|
|||
Expression.notEquals("${Filters.SCOPE} & $scope", 0)
|
||||
)
|
||||
return resolver.queryReference(Filters.Keywords.CONTENT_URI, projection, where.sql,
|
||||
null, null).use { (cur) ->
|
||||
null, null)?.use { (cur) ->
|
||||
return@use Array(cur.count) { i ->
|
||||
cur.moveToPosition(i)
|
||||
cur.getString(0)
|
||||
}
|
||||
}
|
||||
} ?: emptyArray()
|
||||
}
|
||||
|
||||
fun getAccountDisplayName(context: Context, accountKey: UserKey, nameFirst: Boolean): String? {
|
||||
|
@ -418,8 +418,7 @@ object DataStoreUtils {
|
|||
val resolver = context.contentResolver
|
||||
if (followingOnly) {
|
||||
val projection = arrayOf(Activities.SOURCES)
|
||||
return resolver.queryReference(uri, projection, selection.sql, selectionArgs, null).use { (cur) ->
|
||||
if (cur == null) return@use 0
|
||||
return resolver.queryReference(uri, projection, selection.sql, selectionArgs, null)?.use { (cur) ->
|
||||
var total = 0
|
||||
cur.moveToFirst()
|
||||
while (!cur.isAfterLast) {
|
||||
|
@ -443,7 +442,7 @@ object DataStoreUtils {
|
|||
cur.moveToNext()
|
||||
}
|
||||
return@use total
|
||||
}
|
||||
} ?: 0
|
||||
}
|
||||
return resolver.queryCount(uri, selection.sql, selectionArgs)
|
||||
}
|
||||
|
|
|
@ -97,6 +97,10 @@ class UserColorNameManager(context: Context) {
|
|||
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 {
|
||||
return getDisplayName(userKey.toString(), name, screenName, nameFirst)
|
||||
}
|
||||
|
|
|
@ -21,39 +21,24 @@ package org.mariotaku.twidere.util.database
|
|||
|
||||
import android.content.ContentResolver
|
||||
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.UserKey
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters.*
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/2/16.
|
||||
*/
|
||||
|
||||
object ContentFiltersUtils {
|
||||
|
||||
fun isFiltered(cr: ContentResolver, status: ParcelableStatus, filterRts: 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_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>?,
|
||||
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>?,
|
||||
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): Pair<String, Array<String>> {
|
||||
val selectionArgs = mutableListOf<String>()
|
||||
|
|
|
@ -205,8 +205,8 @@ class ContentNotificationManager(
|
|||
|
||||
val (remaining, consumed) = cr.queryReference(Activities.AboutMe.CONTENT_URI, Activities.COLUMNS,
|
||||
filteredSelection.sql, selectionArgs,
|
||||
OrderBy(Activities.TIMESTAMP, false).sql).use { (cur) ->
|
||||
if (cur == null || cur.isEmpty) return@use Pair(-1, -1)
|
||||
OrderBy(Activities.TIMESTAMP, false).sql)?.use { (cur) ->
|
||||
if (cur.isEmpty) return@use Pair(-1, -1)
|
||||
val ci = ObjectCursor.indicesFrom(cur, ParcelableActivity::class.java)
|
||||
var con = 0
|
||||
val rem = cur.forEachRow(5) { c, _ ->
|
||||
|
@ -248,7 +248,7 @@ class ContentNotificationManager(
|
|||
return@forEachRow true
|
||||
}
|
||||
return@use Pair(rem, con)
|
||||
}
|
||||
} ?: Pair(-1, -1)
|
||||
if (remaining < 0) return
|
||||
if (remaining > 0) {
|
||||
style.addLine(resources.getString(R.string.and_N_more, remaining))
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
android:inputType="textEmailAddress"
|
||||
android:maxLines="1"
|
||||
android:typeface="normal"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedEditText
|
||||
android:id="@+id/editPassword"
|
||||
|
@ -57,7 +57,7 @@
|
|||
android:inputType="textPassword"
|
||||
android:maxLines="1"
|
||||
android:typeface="normal"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
</LinearLayout>
|
||||
|
||||
<android.support.v7.widget.AppCompatButton
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
android:ems="10"
|
||||
android:hint="@string/search_hint_users"
|
||||
android:maxLines="1"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
<org.mariotaku.twidere.view.IconActionButton
|
||||
android:id="@+id/screenNameConfirm"
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
app:met_baseColor="?android:textColorPrimary"
|
||||
app:met_floatingLabel="normal"
|
||||
app:met_floatingLabelText="@string/title_subscription_name"
|
||||
app:met_primaryColor="?colorAccent"/>
|
||||
app:met_primaryColor="?colorControlStateful"/>
|
||||
|
||||
<com.rengwuxian.materialedittext.MaterialEditText
|
||||
android:id="@+id/url"
|
||||
|
@ -49,6 +49,6 @@
|
|||
app:met_baseColor="?android:textColorPrimary"
|
||||
app:met_floatingLabel="normal"
|
||||
app:met_floatingLabelText="@string/title_subscription_url"
|
||||
app:met_primaryColor="?colorAccent"/>
|
||||
app:met_primaryColor="?colorControlStateful"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -39,7 +39,7 @@
|
|||
android:hint="@string/host_mapping_host"
|
||||
android:inputType="text|textUri"
|
||||
android:maxLines="1"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedEditText
|
||||
android:id="@+id/editAddress"
|
||||
|
@ -49,6 +49,6 @@
|
|||
android:hint="@string/host_mapping_address"
|
||||
android:inputType="text|textUri"
|
||||
android:maxLines="1"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -69,7 +69,7 @@
|
|||
android:ems="10"
|
||||
android:inputType="textUri"
|
||||
android:maxLines="1"
|
||||
app:backgroundTint="?colorAccent"
|
||||
app:backgroundTint="?colorControlStateful"
|
||||
tools:text="https://api.twitter.com/"/>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedTextView
|
||||
|
|
|
@ -31,6 +31,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:completionThreshold="1"
|
||||
android:maxLines="1"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -12,6 +12,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -32,6 +32,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:hint="@string/hint_conversation_name"
|
||||
android:maxLines="1"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -13,7 +13,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:inputType="text|textPersonName"
|
||||
android:maxLines="1"
|
||||
app:backgroundTint="?colorAccent"
|
||||
app:backgroundTint="?colorControlStateful"
|
||||
tools:text="Nickname"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -35,7 +35,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:completionThreshold="1"
|
||||
android:maxLines="1"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/advancedToggle"
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
android:layout_margin="@dimen/element_spacing_normal"
|
||||
android:textAppearance="?android:textAppearanceMedium"
|
||||
android:typeface="monospace"
|
||||
app:backgroundTint="?colorAccent">
|
||||
app:backgroundTint="?colorControlStateful">
|
||||
|
||||
<requestFocus/>
|
||||
</org.mariotaku.twidere.view.FixedEditText>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
android:inputType="textEmailAddress"
|
||||
android:maxLines="1"
|
||||
android:typeface="normal"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedEditText
|
||||
android:id="@+id/editPassword"
|
||||
|
@ -26,6 +26,6 @@
|
|||
android:inputType="textPassword"
|
||||
android:maxLines="1"
|
||||
android:typeface="normal"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -54,7 +54,7 @@
|
|||
android:hint="@string/comment_hint"
|
||||
android:inputType="textMultiLine|textLongMessage|textCapSentences"
|
||||
android:visibility="visible"
|
||||
app:backgroundTint="?colorAccent">
|
||||
app:backgroundTint="?colorControlStateful">
|
||||
|
||||
<requestFocus/>
|
||||
</org.mariotaku.twidere.view.ComposeEditText>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
android:layout_weight="0"
|
||||
android:hint="@string/hint_message_select_user"
|
||||
android:minLines="1"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_normal"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
app:backgroundTint="?colorControlStateful"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
<item name="colorToolbar">@color/background_color_action_bar_dark</item>
|
||||
<item name="isToolbarColored">false</item>
|
||||
<item name="colorControlStateful">?colorControlNormal</item>
|
||||
|
||||
<item name="actionBarTheme">@style/Theme.Twidere.Dark.ActionBar</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="isToolbarColored">false</item>
|
||||
<item name="colorControlStateful">?colorControlNormal</item>
|
||||
|
||||
<item name="actionBarTheme">@null</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
<item name="colorToolbar">?colorPrimary</item>
|
||||
<item name="isToolbarColored">true</item>
|
||||
<item name="colorControlStateful">?colorControlNormal</item>
|
||||
|
||||
<item name="actionBarTheme">@style/Theme.Twidere.Light.ActionBar</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
@ -71,6 +72,7 @@
|
|||
|
||||
<item name="colorToolbar">?colorPrimary</item>
|
||||
<item name="isToolbarColored">true</item>
|
||||
<item name="colorControlStateful">?colorControlNormal</item>
|
||||
|
||||
<item name="actionBarTheme">@null</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
|
Loading…
Reference in New Issue