supported filters for description
This commit is contained in:
parent
c06c500092
commit
5066f36506
|
@ -79,7 +79,6 @@ subprojects {
|
|||
ACRA : '4.9.2',
|
||||
AbstractTask : '0.9.5',
|
||||
Dagger : '2.11',
|
||||
ExpandableLayout : '1.6.0',
|
||||
]
|
||||
|
||||
}
|
||||
|
|
|
@ -26,8 +26,9 @@ import java.lang.annotation.RetentionPolicy;
|
|||
|
||||
@IntDef(value = {FilterScope.HOME, FilterScope.INTERACTIONS, FilterScope.MESSAGES,
|
||||
FilterScope.SEARCH_RESULTS, FilterScope.LIST_GROUP_TIMELINE, FilterScope.FAVORITES,
|
||||
FilterScope.USER_TIMELINE, FilterScope.PUBLIC_TIMELINE, FilterScope.ALL,
|
||||
FilterScope.FLAG_MATCH_NAME, FilterScope.FLAG_MATCH_TEXT, FilterScope.UGC_TIMELINE}, flag = true)
|
||||
FilterScope.USER_TIMELINE, FilterScope.PUBLIC_TIMELINE, FilterScope.UGC_TIMELINE,
|
||||
FilterScope.FLAG_MATCH_NAME, FilterScope.FLAG_MATCH_TEXT, FilterScope.FLAG_MATCH_DESCRIPTION,
|
||||
FilterScope.ALL, FilterScope.DEFAULT}, flag = true)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface FilterScope {
|
||||
int HOME = 0x1;
|
||||
|
@ -43,6 +44,7 @@ public @interface FilterScope {
|
|||
|
||||
int FLAG_MATCH_NAME = 0x80000000;
|
||||
int FLAG_MATCH_TEXT = 0x40000000;
|
||||
int FLAG_MATCH_DESCRIPTION = 0x20000000;
|
||||
|
||||
int MASK_FLAG = 0xFF000000;
|
||||
int MASK_SCOPE = 0x00FFFFFF;
|
||||
|
@ -54,4 +56,6 @@ public @interface FilterScope {
|
|||
|
||||
// Contains all flags
|
||||
int ALL = 0xFFFFFFFF;
|
||||
@SuppressWarnings("PointlessBitwiseExpression")
|
||||
int DEFAULT = ALL & ~FLAG_MATCH_NAME;
|
||||
}
|
||||
|
|
|
@ -345,6 +345,9 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
|
|||
@CursorField(value = Statuses.FILTER_TEXTS)
|
||||
public String filter_texts;
|
||||
|
||||
@CursorField(value = Statuses.FILTER_DESCRIPTIONS)
|
||||
public String filter_descriptions;
|
||||
|
||||
public transient boolean is_pinned_status;
|
||||
public transient boolean is_filtered;
|
||||
|
||||
|
|
|
@ -736,6 +736,7 @@ public interface TwidereDataStore {
|
|||
String FILTER_SOURCES = "filter_sources";
|
||||
String FILTER_NAMES = "filter_names";
|
||||
String FILTER_TEXTS = "filter_texts";
|
||||
String FILTER_DESCRIPTIONS = "filter_descriptions";
|
||||
|
||||
String DEFAULT_SORT_ORDER = TIMESTAMP + " DESC, " + SORT_ID + " DESC, " + ID
|
||||
+ " DESC";
|
||||
|
|
|
@ -224,7 +224,6 @@ dependencies {
|
|||
implementation "com.github.bumptech.glide:okhttp3-integration:${libVersions['GlideOkHttp3']}@aar"
|
||||
implementation "jp.wasabeef:glide-transformations:${libVersions['GlideTransformations']}"
|
||||
implementation "com.theartofdev.edmodo:android-image-cropper:${libVersions['AndroidImageCropper']}"
|
||||
implementation "com.github.aakira:expandable-layout:${libVersions['ExpandableLayout']}@aar"
|
||||
|
||||
implementation "com.github.mariotaku.MediaViewerLibrary:base:${libVersions['MediaViewerLibrary']}"
|
||||
implementation "com.github.mariotaku.MediaViewerLibrary:subsample-image-view:${libVersions['MediaViewerLibrary']}"
|
||||
|
|
|
@ -1 +1 @@
|
|||
2d1412bd3a0e5eb7aa9c556ad373f836ac9f67ba
|
||||
3dc89e56116e8ce97933fcc36164cd73f7901ad8
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.mariotaku.twidere.model.UserKey;
|
|||
public interface Constants extends TwidereConstants {
|
||||
|
||||
String DATABASES_NAME = "twidere.sqlite";
|
||||
int DATABASES_VERSION = 187;
|
||||
int DATABASES_VERSION = 188;
|
||||
|
||||
int EXTRA_FEATURES_NOTICE_VERSION = 2;
|
||||
|
||||
|
|
|
@ -26,14 +26,28 @@ import android.net.Uri
|
|||
import org.mariotaku.ktextension.map
|
||||
import org.mariotaku.library.objectcursor.ObjectCursor
|
||||
import org.mariotaku.sqliteqb.library.SQLFunctions
|
||||
import org.mariotaku.twidere.TwidereConstants.QUERY_PARAM_LIMIT
|
||||
import org.mariotaku.twidere.extension.model.component1
|
||||
import org.mariotaku.twidere.model.CursorReference
|
||||
import org.mariotaku.twidere.util.TwidereQueryBuilder
|
||||
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 {
|
||||
return if (limit != null) {
|
||||
query(uri.buildUpon().appendQueryParameter(QUERY_PARAM_LIMIT, limit.toString()).build(),
|
||||
projection, selection, selectionArgs, sortOrder)
|
||||
} else {
|
||||
query(uri, projection, selection, selectionArgs, sortOrder)
|
||||
}
|
||||
}
|
||||
|
||||
fun ContentResolver.queryReference(uri: Uri, projection: Array<String>? = null,
|
||||
selection: String? = null, selectionArgs: Array<String>? = null, sortOrder: String? = null) =
|
||||
CursorReference(query(uri, projection, selection, selectionArgs, sortOrder))
|
||||
selection: String? = null, selectionArgs: Array<String>? = null, sortOrder: String? = null,
|
||||
limit: String? = null): CursorReference<Cursor> {
|
||||
return CursorReference(query(uri, projection, selection, selectionArgs, sortOrder, limit))
|
||||
}
|
||||
|
||||
@SuppressLint("Recycle")
|
||||
fun ContentResolver.rawQuery(sql: String, selectionArgs: Array<String>?, notifyUri: Uri? = null): Cursor? {
|
||||
|
@ -41,9 +55,10 @@ fun ContentResolver.rawQuery(sql: String, selectionArgs: Array<String>?, notifyU
|
|||
return query(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).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)
|
||||
|
@ -67,6 +82,16 @@ fun ContentResolver.queryCount(uri: Uri, selection: String?, selectionArgs: Arra
|
|||
}
|
||||
}
|
||||
|
||||
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) ->
|
||||
if (cur.moveToFirst()) {
|
||||
return@use cur.getLong(0)
|
||||
}
|
||||
return@use def
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Any> ContentResolver.insert(uri: Uri, obj: T, cls: Class<T> = obj.javaClass): Uri? {
|
||||
return this.insert(uri, ObjectCursor.valuesCreatorFrom(cls).create(obj))
|
||||
}
|
||||
|
|
|
@ -30,10 +30,11 @@ val ParcelableActivity.activityStatus: ParcelableActivity?
|
|||
else -> null
|
||||
}
|
||||
|
||||
val ParcelableActivity.reachedCountLimit: Boolean get() {
|
||||
return sources.reachedCountLimit() || targets.reachedCountLimit() ||
|
||||
target_objects.reachedCountLimit()
|
||||
}
|
||||
val ParcelableActivity.reachedCountLimit: Boolean
|
||||
get() {
|
||||
return sources.reachedCountLimit() || targets.reachedCountLimit() ||
|
||||
target_objects.reachedCountLimit()
|
||||
}
|
||||
|
||||
fun ParcelableActivity.isSameSources(another: ParcelableActivity): Boolean {
|
||||
return Arrays.equals(sources, another.sources)
|
||||
|
@ -66,13 +67,20 @@ fun ParcelableActivity.prependTargetObjects(from: ParcelableActivity) {
|
|||
.prepend(from.target_objects)
|
||||
}
|
||||
|
||||
inline val ParcelableActivity.RelatedObject.size get() = when {
|
||||
statuses != null -> statuses.size
|
||||
users != null -> users.size
|
||||
user_lists != null -> user_lists.size
|
||||
else -> 0
|
||||
fun ParcelableActivity.updateActivityFilterInfo() {
|
||||
updateFilterInfo(sources?.flatMap {
|
||||
listOf(it.description_unescaped, it.location)
|
||||
}?.toTypedArray())
|
||||
}
|
||||
|
||||
inline val ParcelableActivity.RelatedObject.size
|
||||
get() = when {
|
||||
statuses != null -> statuses.size
|
||||
users != null -> users.size
|
||||
user_lists != null -> user_lists.size
|
||||
else -> 0
|
||||
}
|
||||
|
||||
fun ParcelableActivity.RelatedObject?.isNullOrEmpty(): Boolean {
|
||||
if (this == null) return true
|
||||
return size == 0
|
||||
|
|
|
@ -127,7 +127,7 @@ fun ParcelableStatus.addFilterFlag(@ParcelableStatus.FilterFlags flags: Long) {
|
|||
filter_flags = filter_flags or flags
|
||||
}
|
||||
|
||||
fun ParcelableStatus.updateFilterInfo() {
|
||||
fun ParcelableStatus.updateFilterInfo(descriptions: Array<String?>?) {
|
||||
val links = mutableSetOf<String>()
|
||||
spans?.mapNotNullTo(links) { span ->
|
||||
if (span.type != SpanItem.SpanType.LINK) return@mapNotNullTo null
|
||||
|
@ -166,6 +166,8 @@ fun ParcelableStatus.updateFilterInfo() {
|
|||
item.alt_text?.appendNewLineTo(texts)
|
||||
}
|
||||
filter_texts = texts.toString()
|
||||
|
||||
filter_descriptions = descriptions?.filterNotNull()?.joinToString("\n")
|
||||
}
|
||||
|
||||
fun ParcelableStatus.updateExtraInformation(details: AccountDetails) {
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.mariotaku.twidere.text.AcctMentionSpan
|
|||
import org.mariotaku.twidere.text.HashtagSpan
|
||||
import org.mariotaku.twidere.util.HtmlBuilder
|
||||
import org.mariotaku.twidere.util.HtmlSpanBuilder
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils.getMediaUrl
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils.getStartEndForEntity
|
||||
|
||||
|
@ -200,7 +201,9 @@ fun Status.applyTo(accountKey: UserKey, accountType: String, profileImageSize: S
|
|||
result.addFilterFlag(ParcelableStatus.FilterFlags.HAS_MEDIA)
|
||||
}
|
||||
|
||||
result.updateFilterInfo()
|
||||
result.updateFilterInfo(arrayOf(userDescriptionUnescaped, retweetedStatus?.userDescriptionUnescaped,
|
||||
quotedStatus?.userDescriptionUnescaped, this.user.location, retweetedStatus?.user?.location,
|
||||
quotedStatus?.user?.location))
|
||||
}
|
||||
|
||||
|
||||
|
@ -268,6 +271,9 @@ private fun String.twitterUnescaped(): String {
|
|||
return twitterRawTextTranslator.translate(this)
|
||||
}
|
||||
|
||||
private val Status.userDescriptionUnescaped: String?
|
||||
get() = user?.let { InternalTwitterContentUtils.formatUserDescription(it)?.first }
|
||||
|
||||
/**
|
||||
* @param spans Ordered spans
|
||||
* *
|
||||
|
@ -279,35 +285,39 @@ internal fun findByOrigRange(spans: Array<SpanItem>, start: Int, end: Int): List
|
|||
return spans.filter { it.orig_start >= start && it.orig_end <= end }
|
||||
}
|
||||
|
||||
internal inline val CharSequence.spanItems get() = (this as? Spanned)?.let { text ->
|
||||
text.getSpans(0, length, URLSpan::class.java).mapToArray {
|
||||
val item = it.toSpanItem(text)
|
||||
when (it) {
|
||||
is AcctMentionSpan -> item.type = SpanItem.SpanType.ACCT_MENTION
|
||||
is HashtagSpan -> item.type = SpanItem.SpanType.HASHTAG
|
||||
internal inline val CharSequence.spanItems
|
||||
get() = (this as? Spanned)?.let { text ->
|
||||
text.getSpans(0, length, URLSpan::class.java).mapToArray {
|
||||
val item = it.toSpanItem(text)
|
||||
when (it) {
|
||||
is AcctMentionSpan -> item.type = SpanItem.SpanType.ACCT_MENTION
|
||||
is HashtagSpan -> item.type = SpanItem.SpanType.HASHTAG
|
||||
}
|
||||
return@mapToArray item
|
||||
}
|
||||
return@mapToArray item
|
||||
}
|
||||
}
|
||||
|
||||
internal inline val String.isHtml get() = contains('<') && contains('>')
|
||||
|
||||
private inline val Status.inReplyToName get() = userMentionEntities?.firstOrNull {
|
||||
inReplyToUserId == it.id
|
||||
}?.name ?: attentions?.firstOrNull {
|
||||
inReplyToUserId == it.id
|
||||
}?.fullName ?: inReplyToScreenName
|
||||
private inline val Status.inReplyToName
|
||||
get() = userMentionEntities?.firstOrNull {
|
||||
inReplyToUserId == it.id
|
||||
}?.name ?: attentions?.firstOrNull {
|
||||
inReplyToUserId == it.id
|
||||
}?.fullName ?: inReplyToScreenName
|
||||
|
||||
|
||||
private inline val Status.placeFullName get() = place?.fullName ?: location?.takeIf {
|
||||
ParcelableLocation.valueOf(location) == null
|
||||
}
|
||||
|
||||
private inline val Status.inferredExternalUrl get() = externalUrl ?: uri?.let { uri ->
|
||||
noticeUriRegex.matchEntire(uri)?.let { result: MatchResult ->
|
||||
"https://${result.groups[1]?.value}/notice/${result.groups[3]?.value}"
|
||||
private inline val Status.placeFullName
|
||||
get() = place?.fullName ?: location?.takeIf {
|
||||
ParcelableLocation.valueOf(location) == null
|
||||
}
|
||||
|
||||
private inline val Status.inferredExternalUrl
|
||||
get() = externalUrl ?: uri?.let { uri ->
|
||||
noticeUriRegex.matchEntire(uri)?.let { result: MatchResult ->
|
||||
"https://${result.groups[1]?.value}/notice/${result.groups[3]?.value}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val Status.parcelableLocation: ParcelableLocation?
|
||||
get() {
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.mariotaku.microblog.library.mastodon.model.Relationship
|
|||
import org.mariotaku.microblog.library.twitter.model.Activity
|
||||
import org.mariotaku.twidere.extension.model.toLite
|
||||
import org.mariotaku.twidere.extension.model.toSummaryLine
|
||||
import org.mariotaku.twidere.extension.model.updateActivityFilterInfo
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableActivity
|
||||
import org.mariotaku.twidere.model.ParcelableUser
|
||||
|
@ -92,6 +93,8 @@ fun Notification.toParcelable(accountKey: UserKey, relationships: Map<String, Re
|
|||
result.sources_lite = result.sources?.mapToArray { it.toLite() }
|
||||
result.source_keys = result.sources_lite?.mapToArray { it.key }
|
||||
|
||||
result.updateActivityFilterInfo()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,9 @@ import org.mariotaku.ktextension.isNotNullOrEmpty
|
|||
import org.mariotaku.ktextension.mapToArray
|
||||
import org.mariotaku.microblog.library.mastodon.model.Status
|
||||
import org.mariotaku.twidere.extension.model.addFilterFlag
|
||||
import org.mariotaku.twidere.extension.model.api.isHtml
|
||||
import org.mariotaku.twidere.extension.model.api.spanItems
|
||||
import org.mariotaku.twidere.extension.model.updateFilterInfo
|
||||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.text.AcctMentionSpan
|
||||
import org.mariotaku.twidere.text.HashtagSpan
|
||||
|
@ -39,6 +41,7 @@ fun Status.toParcelable(details: AccountDetails): ParcelableStatus {
|
|||
account_color = details.color
|
||||
}
|
||||
}
|
||||
|
||||
fun Status.toParcelable(accountKey: UserKey): ParcelableStatus {
|
||||
val result = ParcelableStatus()
|
||||
applyTo(accountKey, result)
|
||||
|
@ -121,6 +124,8 @@ fun Status.applyTo(accountKey: UserKey, result: ParcelableStatus) {
|
|||
}
|
||||
|
||||
result.extras = extras
|
||||
|
||||
result.updateFilterInfo(arrayOf(accountDescriptionUnescaped, reblog?.accountDescriptionUnescaped))
|
||||
}
|
||||
|
||||
private fun calculateDisplayTextRange(text: String, spans: Array<SpanItem>?, media: Array<ParcelableMedia>?): IntArray? {
|
||||
|
@ -130,6 +135,16 @@ private fun calculateDisplayTextRange(text: String, spans: Array<SpanItem>?, med
|
|||
return intArrayOf(0, lastMatch.start)
|
||||
}
|
||||
|
||||
private val Status.accountDescriptionUnescaped: String?
|
||||
get() {
|
||||
val note = account?.note ?: return null
|
||||
return if (note.isHtml) {
|
||||
HtmlSpanBuilder.fromHtml(note, note, MastodonSpanProcessor).toString()
|
||||
} else {
|
||||
HtmlEscapeHelper.unescape(note)
|
||||
}
|
||||
}
|
||||
|
||||
object MastodonSpanProcessor : HtmlSpanBuilder.SpanProcessor {
|
||||
|
||||
override fun appendText(text: Editable, buffer: CharArray, start: Int, len: Int,
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.mariotaku.twidere.extension.model.api.applyTo
|
|||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.toLite
|
||||
import org.mariotaku.twidere.extension.model.toSummaryLine
|
||||
import org.mariotaku.twidere.extension.model.updateFilterInfo
|
||||
import org.mariotaku.twidere.extension.model.updateActivityFilterInfo
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableActivity
|
||||
import org.mariotaku.twidere.model.ParcelableUserList
|
||||
|
@ -152,7 +152,7 @@ fun Activity.toParcelable(accountKey: UserKey, accountType: String, isGap: Boole
|
|||
} ?: false
|
||||
result.is_gap = isGap
|
||||
|
||||
result.updateFilterInfo()
|
||||
result.updateActivityFilterInfo()
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.mariotaku.twidere.loader.ExtendedObjectCursorLoader
|
|||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.event.*
|
||||
import org.mariotaku.twidere.model.pagination.SinceMaxPagination
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Activities
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters
|
||||
import org.mariotaku.twidere.task.twitter.GetStatusesTask
|
||||
|
@ -354,7 +355,8 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
|||
val activityColumnsLite = Activities.COLUMNS - arrayOf(Activities.SOURCES, Activities.TARGETS,
|
||||
Activities.TARGET_OBJECTS, Activities.MENTIONS_JSON, Activities.CARD,
|
||||
Activities.FILTER_FLAGS, Activities.FILTER_USERS, Activities.FILTER_LINKS,
|
||||
Activities.FILTER_SOURCES, Activities.FILTER_NAMES, Activities.FILTER_TEXTS)
|
||||
Activities.FILTER_SOURCES, Activities.FILTER_NAMES, Activities.FILTER_TEXTS,
|
||||
Activities.FILTER_DESCRIPTIONS)
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,6 +319,7 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() {
|
|||
companion object {
|
||||
private val statusColumnsLite = Statuses.COLUMNS - arrayOf(Statuses.MENTIONS_JSON,
|
||||
Statuses.CARD, Statuses.FILTER_FLAGS, Statuses.FILTER_USERS, Statuses.FILTER_LINKS,
|
||||
Statuses.FILTER_SOURCES, Statuses.FILTER_NAMES, Statuses.FILTER_TEXTS)
|
||||
Statuses.FILTER_SOURCES, Statuses.FILTER_NAMES, Statuses.FILTER_TEXTS,
|
||||
Statuses.FILTER_DESCRIPTIONS)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.os.Parcel
|
|||
import android.os.Parcelable
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.CheckBox
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.dialog_filter_rule_editor.*
|
||||
|
@ -43,7 +44,8 @@ import org.mariotaku.twidere.annotation.FilterScope
|
|||
import org.mariotaku.twidere.constant.IntentConstants.*
|
||||
import org.mariotaku.twidere.extension.applyOnShow
|
||||
import org.mariotaku.twidere.extension.applyTheme
|
||||
import org.mariotaku.twidere.extension.queryCount
|
||||
import org.mariotaku.twidere.extension.queryLong
|
||||
import org.mariotaku.twidere.extension.setVisible
|
||||
import org.mariotaku.twidere.fragment.BaseDialogFragment
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters
|
||||
|
@ -60,7 +62,7 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
get() = arguments.getString(EXTRA_VALUE)
|
||||
|
||||
private val defaultScope: FilterScopes
|
||||
get() = FilterScopes(filterMasks, arguments.getInt(EXTRA_SCOPE, filterMasks))
|
||||
get() = FilterScopes(filterMasks, arguments.getInt(EXTRA_SCOPE, FilterScope.DEFAULT))
|
||||
|
||||
private val filterMasks: Int
|
||||
get() = when (contentUri) {
|
||||
|
@ -78,11 +80,18 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
}
|
||||
|
||||
private var Dialog.scope: FilterScopes?
|
||||
get() = defaultScope.also { applyScopes(it) }
|
||||
get() = defaultScope.also { saveScopes(it) }
|
||||
set(value) {
|
||||
loadScopes(value ?: defaultScope)
|
||||
}
|
||||
|
||||
private var Dialog.advancedExpanded: Boolean
|
||||
get() = advancedContainer.visibility == View.VISIBLE
|
||||
set(value) {
|
||||
advancedContainer.setVisible(value)
|
||||
advancedCollapseIndicator.rotation = if (value) 90f else 0f
|
||||
}
|
||||
|
||||
override fun onClick(dialog: DialogInterface, which: Int) {
|
||||
dialog as AlertDialog
|
||||
when (which) {
|
||||
|
@ -100,12 +109,14 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
if (id >= 0) {
|
||||
val valueWhere = Expression.equalsArgs(Filters.VALUE).sql
|
||||
val valueWhereArgs = arrayOf(value)
|
||||
if (resolver.queryCount(uri, valueWhere, valueWhereArgs) == 0) {
|
||||
val idWhere = Expression.equals(Filters._ID, id).sql
|
||||
resolver.update(uri, values, idWhere, null)
|
||||
} else {
|
||||
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 {
|
||||
resolver.insert(uri, values)
|
||||
|
@ -129,6 +140,7 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
val dialog = builder.create()
|
||||
dialog.applyOnShow {
|
||||
applyTheme()
|
||||
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
editText.setAdapter(when (contentUri) {
|
||||
Filters.Sources.CONTENT_URI -> SourceAutoCompleteAdapter(activity)
|
||||
Filters.Users.CONTENT_URI -> ComposeAutoCompleteAdapter(activity, requestManager).apply {
|
||||
|
@ -138,6 +150,10 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
else -> null
|
||||
})
|
||||
editText.threshold = 1
|
||||
advancedToggle.setOnClickListener {
|
||||
advancedExpanded = !advancedExpanded
|
||||
}
|
||||
advancedExpanded = false
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
value = defaultValue
|
||||
|
@ -156,19 +172,21 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
outState.putParcelable(EXTRA_SCOPE, dialog.scope)
|
||||
}
|
||||
|
||||
private fun Dialog.applyScopes(scopes: FilterScopes) {
|
||||
targetText.applyScope(scopes, FilterScope.FLAG_MATCH_TEXT)
|
||||
targetName.applyScope(scopes, FilterScope.FLAG_MATCH_NAME)
|
||||
scopeHome.applyScope(scopes, FilterScope.HOME)
|
||||
scopeInteractions.applyScope(scopes, FilterScope.INTERACTIONS)
|
||||
scopeMessages.applyScope(scopes, FilterScope.MESSAGES)
|
||||
scopeSearchResults.applyScope(scopes, FilterScope.SEARCH_RESULTS)
|
||||
scopeOther.applyScope(scopes, FilterScope.UGC_TIMELINE)
|
||||
private fun Dialog.saveScopes(scopes: FilterScopes) {
|
||||
targetText.saveScope(scopes, FilterScope.FLAG_MATCH_TEXT)
|
||||
targetName.saveScope(scopes, FilterScope.FLAG_MATCH_NAME)
|
||||
targetDescription.saveScope(scopes, FilterScope.FLAG_MATCH_DESCRIPTION)
|
||||
scopeHome.saveScope(scopes, FilterScope.HOME)
|
||||
scopeInteractions.saveScope(scopes, FilterScope.INTERACTIONS)
|
||||
scopeMessages.saveScope(scopes, FilterScope.MESSAGES)
|
||||
scopeSearchResults.saveScope(scopes, FilterScope.SEARCH_RESULTS)
|
||||
scopeOther.saveScope(scopes, FilterScope.UGC_TIMELINE)
|
||||
}
|
||||
|
||||
private fun Dialog.loadScopes(scopes: FilterScopes) {
|
||||
targetText.loadScope(scopes, FilterScope.FLAG_MATCH_TEXT)
|
||||
targetName.loadScope(scopes, FilterScope.FLAG_MATCH_NAME)
|
||||
targetDescription.loadScope(scopes, FilterScope.FLAG_MATCH_DESCRIPTION)
|
||||
scopeHome.loadScope(scopes, FilterScope.HOME)
|
||||
scopeInteractions.loadScope(scopes, FilterScope.INTERACTIONS)
|
||||
scopeMessages.loadScope(scopes, FilterScope.MESSAGES)
|
||||
|
@ -176,7 +194,7 @@ class AddEditItemFragment : BaseDialogFragment(), DialogInterface.OnClickListene
|
|||
scopeOther.loadScope(scopes, FilterScope.UGC_TIMELINE)
|
||||
}
|
||||
|
||||
private fun CheckBox.applyScope(scopes: FilterScopes, scope: Int) {
|
||||
private fun CheckBox.saveScope(scopes: FilterScopes, scope: Int) {
|
||||
if (!isEnabled || visibility != View.VISIBLE) return
|
||||
scopes[scope] = isChecked
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.mariotaku.sqliteqb.library.Expression
|
|||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.*
|
||||
import org.mariotaku.twidere.activity.iface.IControlBarActivity
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.extension.invertSelection
|
||||
import org.mariotaku.twidere.extension.selectAll
|
||||
import org.mariotaku.twidere.extension.selectNone
|
||||
|
@ -222,7 +223,7 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
|
|||
context.contentResolver.delete(contentUri, where.sql, Array(ids.size) { ids[it].toString() })
|
||||
}
|
||||
|
||||
protected open fun addOrEditItem(id: Long = -1, value: String? = null, scope: Int = 0) {
|
||||
protected open fun addOrEditItem(id: Long = -1, value: String? = null, scope: Int = FilterScope.DEFAULT) {
|
||||
val dialog = AddEditItemFragment()
|
||||
dialog.arguments = Bundle {
|
||||
this[EXTRA_URI] = contentUri
|
||||
|
|
|
@ -230,8 +230,9 @@ class TwidereDataProvider : ContentProvider(), LazyLoadCallback {
|
|||
}
|
||||
}
|
||||
if (table == null) return null
|
||||
val limit = uri.getQueryParameter(QUERY_PARAM_LIMIT)
|
||||
val c = databaseWrapper.query(table, projection, selection, selectionArgs,
|
||||
null, null, sortOrder)
|
||||
null, null, sortOrder, limit)
|
||||
c?.setNotificationUri(context.contentResolver, uri)
|
||||
return c
|
||||
} catch (e: SQLException) {
|
||||
|
|
|
@ -496,6 +496,11 @@ object DataStoreUtils {
|
|||
Expression.notEquals("${Filters.Keywords.TABLE_NAME}.${Filters.Keywords.SCOPE} & ${FilterScope.FLAG_MATCH_NAME}", 0),
|
||||
ScopeMatchesExpression(Filters.Keywords.TABLE_NAME, Filters.Keywords.SCOPE),
|
||||
ContainsExpression(Statuses.FILTER_NAMES, Filters.Keywords.TABLE_NAME, Filters.Keywords.VALUE)
|
||||
),
|
||||
Expression.and(
|
||||
Expression.notEquals("${Filters.Keywords.TABLE_NAME}.${Filters.Keywords.SCOPE} & ${FilterScope.FLAG_MATCH_DESCRIPTION}", 0),
|
||||
ScopeMatchesExpression(Filters.Keywords.TABLE_NAME, Filters.Keywords.SCOPE),
|
||||
ContainsExpression(Statuses.FILTER_DESCRIPTIONS, Filters.Keywords.TABLE_NAME, Filters.Keywords.VALUE)
|
||||
)
|
||||
)
|
||||
val filteredLinksWhere = Expression.and(
|
||||
|
|
|
@ -17,76 +17,133 @@
|
|||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<android.support.v7.widget.AppCompatAutoCompleteTextView
|
||||
android:id="@+id/editText"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:completionThreshold="1"
|
||||
android:maxLines="1"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
style="?android:listSeparatorTextViewStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_filter_for"
|
||||
android:textColor="?colorAccent"/>
|
||||
<android.support.v7.widget.AppCompatAutoCompleteTextView
|
||||
android:id="@+id/editText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:completionThreshold="1"
|
||||
android:maxLines="1"
|
||||
app:backgroundTint="?colorAccent"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/targetText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_filter_target_text"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/advancedToggle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/element_spacing_normal"
|
||||
android:background="?selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/element_spacing_normal">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/targetName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_filter_target_name"/>
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/label_advanced"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
android:textColor="?android:textColorPrimary"/>
|
||||
|
||||
<TextView
|
||||
style="?android:listSeparatorTextViewStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_filter_apply_to"
|
||||
android:textColor="?colorAccent"/>
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:id="@+id/advancedCollapseIndicator"
|
||||
android:layout_width="@dimen/element_size_small"
|
||||
android:layout_height="@dimen/element_size_small"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_indicator_arrow_next"
|
||||
app:tint="?android:textColorSecondary"/>
|
||||
</LinearLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/scopeHome"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_filter_scope_home"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/advancedContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_normal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/scopeInteractions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_filter_scope_interactions"/>
|
||||
<TextView
|
||||
style="?android:listSeparatorTextViewStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:text="@string/label_filter_for"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?colorAccent"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/scopeMessages"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_filter_scope_messages"/>
|
||||
<CheckBox
|
||||
android:id="@+id/targetText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:text="@string/label_filter_target_text"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/scopeSearchResults"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_filter_scope_search_results"/>
|
||||
<CheckBox
|
||||
android:id="@+id/targetName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:text="@string/label_filter_target_name"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/scopeOther"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_filter_scope_search_other"/>
|
||||
</LinearLayout>
|
||||
<CheckBox
|
||||
android:id="@+id/targetDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:text="@string/label_filter_target_description"/>
|
||||
|
||||
<TextView
|
||||
style="?android:listSeparatorTextViewStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:text="@string/label_filter_apply_to"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?colorAccent"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/scopeHome"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:text="@string/label_filter_scope_home"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/scopeInteractions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:text="@string/label_filter_scope_interactions"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/scopeMessages"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:text="@string/label_filter_scope_messages"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/scopeSearchResults"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:text="@string/label_filter_scope_search_results"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/scopeOther"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/element_spacing_small"
|
||||
android:text="@string/label_filter_scope_search_other"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
|
@ -500,6 +500,7 @@
|
|||
|
||||
<string name="label_account">Account</string>
|
||||
<string name="label_account_type">Account type</string>
|
||||
<string name="label_advanced">Advanced</string>
|
||||
<string name="label_auth_type">Auth type</string>
|
||||
<string name="label_background_operation_service">Background operation service</string>
|
||||
<string name="label_buffer_accounts">Buffer accounts</string>
|
||||
|
@ -523,6 +524,7 @@
|
|||
<string name="label_filter_scope_messages">Messages</string>
|
||||
<string name="label_filter_scope_search_other">Other</string>
|
||||
<string name="label_filter_scope_search_results">Search results</string>
|
||||
<string name="label_filter_target_description">Description</string>
|
||||
<string name="label_filter_target_name">Name</string>
|
||||
<string name="label_filter_target_text">Text</string>
|
||||
<string name="label_filters_subscription">Subscription</string>
|
||||
|
|
Loading…
Reference in New Issue