improved filters
This commit is contained in:
parent
cdad3eb532
commit
d43d6220bd
|
@ -34,10 +34,10 @@ import org.mariotaku.commons.objectcursor.LoganSquareCursorFieldConverter;
|
|||
import org.mariotaku.library.objectcursor.annotation.AfterCursorObjectCreated;
|
||||
import org.mariotaku.library.objectcursor.annotation.CursorField;
|
||||
import org.mariotaku.library.objectcursor.annotation.CursorObject;
|
||||
import org.mariotaku.twidere.model.util.LineSeparatedStringArrayConverter;
|
||||
import org.mariotaku.twidere.model.util.FilterStringsFieldConverter;
|
||||
import org.mariotaku.twidere.model.util.FilterUserKeysFieldConverter;
|
||||
import org.mariotaku.twidere.model.util.UserKeyConverter;
|
||||
import org.mariotaku.twidere.model.util.UserKeyCursorFieldConverter;
|
||||
import org.mariotaku.twidere.model.util.UserKeysCursorFieldConverter;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
|
||||
|
||||
|
@ -330,16 +330,16 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
|
|||
@CursorField(Statuses.FILTER_FLAGS)
|
||||
public long filter_flags;
|
||||
|
||||
@CursorField(value = Statuses.FILTER_USERS, converter = UserKeysCursorFieldConverter.class)
|
||||
@CursorField(value = Statuses.FILTER_USERS, converter = FilterUserKeysFieldConverter.class)
|
||||
public UserKey[] filter_users;
|
||||
|
||||
@CursorField(value = Statuses.FILTER_SOURCES, converter = LineSeparatedStringArrayConverter.class)
|
||||
@CursorField(value = Statuses.FILTER_SOURCES, converter = FilterStringsFieldConverter.class)
|
||||
public String[] filter_sources;
|
||||
|
||||
@CursorField(value = Statuses.FILTER_LINKS, converter = LineSeparatedStringArrayConverter.class)
|
||||
@CursorField(value = Statuses.FILTER_LINKS, converter = FilterStringsFieldConverter.class)
|
||||
public String[] filter_links;
|
||||
|
||||
@CursorField(value = Statuses.FILTER_NAMES, converter = LineSeparatedStringArrayConverter.class)
|
||||
@CursorField(value = Statuses.FILTER_NAMES, converter = FilterStringsFieldConverter.class)
|
||||
public String[] filter_names;
|
||||
|
||||
@CursorField(value = Statuses.FILTER_TEXTS)
|
||||
|
|
|
@ -20,11 +20,7 @@ package org.mariotaku.twidere.model.util;
|
|||
|
||||
import org.mariotaku.commons.objectcursor.AbsArrayCursorFieldConverter;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/9/12.
|
||||
*/
|
||||
|
||||
public class LineSeparatedStringArrayConverter extends AbsArrayCursorFieldConverter<String> {
|
||||
public class FilterStringsFieldConverter extends AbsArrayCursorFieldConverter<String> {
|
||||
@Override
|
||||
protected String[] newArray(int size) {
|
||||
return new String[size];
|
||||
|
@ -32,12 +28,16 @@ public class LineSeparatedStringArrayConverter extends AbsArrayCursorFieldConver
|
|||
|
||||
@Override
|
||||
protected String convertToString(String item) {
|
||||
return item;
|
||||
if (item == null || item.isEmpty()) return "";
|
||||
return '\\' + item + '\\';
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String parseItem(String str) {
|
||||
return str;
|
||||
if (str == null || str.isEmpty()) return null;
|
||||
final int len = str.length();
|
||||
if (str.charAt(0) != '\\' || str.charAt(len - 1) != '\\') return str;
|
||||
return str.substring(1, len - 1);
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.model.util;
|
||||
|
||||
import org.mariotaku.commons.objectcursor.AbsArrayCursorFieldConverter;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/9/12.
|
||||
*/
|
||||
|
||||
public class FilterUserKeysFieldConverter extends AbsArrayCursorFieldConverter<UserKey> {
|
||||
@Override
|
||||
protected UserKey[] newArray(int size) {
|
||||
return new UserKey[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String convertToString(UserKey item) {
|
||||
if (item == null) return "";
|
||||
return '\\' + item.toString() + '\\';
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UserKey parseItem(String str) {
|
||||
if (str == null || str.isEmpty()) return null;
|
||||
final int len = str.length();
|
||||
if (str.charAt(0) != '\\' || str.charAt(len - 1) != '\\') return UserKey.valueOf(str);
|
||||
return UserKey.valueOf(str.substring(1, len - 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected char separatorChar() {
|
||||
return '\n';
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
@ -18,10 +16,7 @@ import org.mariotaku.microblog.library.twitter.model.User;
|
|||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.extension.model.api.StatusExtensionsKt;
|
||||
import org.mariotaku.twidere.model.ConsumerKeyType;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.model.SpanItem;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.util.database.FilterQueryBuilder;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.zip.CRC32;
|
||||
|
@ -38,44 +33,6 @@ public class InternalTwitterContentUtils {
|
|||
private InternalTwitterContentUtils() {
|
||||
}
|
||||
|
||||
public static boolean isFiltered(final SQLiteDatabase database, final UserKey userKey,
|
||||
final String textPlain, final String quotedTextPlain,
|
||||
final SpanItem[] spans, final SpanItem[] quotedSpans,
|
||||
final String source, final String quotedSource,
|
||||
final UserKey retweetedByKey, final UserKey quotedUserKey) {
|
||||
return isFiltered(database, userKey, textPlain, quotedTextPlain, spans, quotedSpans, source,
|
||||
quotedSource, retweetedByKey, quotedUserKey, true);
|
||||
}
|
||||
|
||||
|
||||
public static boolean isFiltered(final SQLiteDatabase database, final UserKey userKey,
|
||||
final String textPlain, final String quotedTextPlain,
|
||||
final SpanItem[] spans, final SpanItem[] quotedSpans,
|
||||
final String source, final String quotedSource,
|
||||
final UserKey retweetedByKey, final UserKey quotedUserKey,
|
||||
final boolean filterRts) {
|
||||
if (textPlain == null && spans == null && userKey == null && source == null)
|
||||
return false;
|
||||
|
||||
final Pair<String, String[]> query = FilterQueryBuilder.INSTANCE.isFilteredQuery(userKey,
|
||||
textPlain, quotedTextPlain, spans, quotedSpans, source, quotedSource, retweetedByKey,
|
||||
quotedUserKey, filterRts);
|
||||
final Cursor cur = database.rawQuery(query.getFirst(), query.getSecond());
|
||||
if (cur == null) return false;
|
||||
try {
|
||||
return cur.moveToFirst() && cur.getInt(0) != 0;
|
||||
} finally {
|
||||
cur.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFiltered(@NonNull final SQLiteDatabase database,
|
||||
@NonNull final ParcelableStatus status, final boolean filterRTs) {
|
||||
return isFiltered(database, status.user_key, status.text_plain, status.quoted_text_plain,
|
||||
status.spans, status.quoted_spans, status.source, status.quoted_source,
|
||||
status.retweeted_by_user_key, status.quoted_user_key, filterRTs);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String getBestBannerUrl(@NonNull final String baseUrl, final int width, final int height) {
|
||||
final String type;
|
||||
|
|
|
@ -83,85 +83,6 @@ inline val ParcelableStatus.can_retweet: Boolean
|
|||
}
|
||||
}
|
||||
|
||||
fun ParcelableStatus.toSummaryLine(): ParcelableActivity.SummaryLine {
|
||||
val result = ParcelableActivity.SummaryLine()
|
||||
result.key = user_key
|
||||
result.name = user_name
|
||||
result.screen_name = user_screen_name
|
||||
result.content = text_unescaped
|
||||
return result
|
||||
}
|
||||
|
||||
fun ParcelableStatus.extractFanfouHashtags(): List<String> {
|
||||
return spans?.filter { span ->
|
||||
var link = span.link
|
||||
if (link.startsWith("/")) {
|
||||
link = "http://fanfou.com$link"
|
||||
}
|
||||
if (UriUtils.getAuthority(link) != "fanfou.com") {
|
||||
return@filter false
|
||||
}
|
||||
if (span.start <= 0 || span.end > text_unescaped.lastIndex) return@filter false
|
||||
if (text_unescaped[span.start - 1] == '#' && text_unescaped[span.end] == '#') {
|
||||
return@filter true
|
||||
}
|
||||
return@filter false
|
||||
}?.map { text_unescaped.substring(it.start, it.end) }.orEmpty()
|
||||
}
|
||||
|
||||
|
||||
fun ParcelableStatus.makeOriginal() {
|
||||
if (!is_retweet) return
|
||||
id = retweet_id
|
||||
is_retweet = false
|
||||
retweeted_by_user_key = null
|
||||
retweeted_by_user_name = null
|
||||
retweeted_by_user_screen_name = null
|
||||
retweeted_by_user_profile_image = null
|
||||
retweet_timestamp = -1
|
||||
retweet_id = null
|
||||
}
|
||||
|
||||
fun ParcelableStatus.addFilterFlag(@ParcelableStatus.FilterFlags flags: Long) {
|
||||
filter_flags = filter_flags or flags
|
||||
}
|
||||
|
||||
fun ParcelableStatus.updateFilterInfo(descriptions: Collection<String?>?) {
|
||||
val links = mutableSetOf<String>()
|
||||
spans?.mapNotNullTo(links) { span ->
|
||||
if (span.type != SpanItem.SpanType.LINK) return@mapNotNullTo null
|
||||
return@mapNotNullTo span.link
|
||||
}
|
||||
quoted_spans?.mapNotNullTo(links) { span ->
|
||||
if (span.type != SpanItem.SpanType.LINK) return@mapNotNullTo null
|
||||
return@mapNotNullTo span.link
|
||||
}
|
||||
filter_links = links.toTypedArray()
|
||||
|
||||
filter_sources = setOf(source?.plainText, quoted_source?.plainText).filterNotNull().toTypedArray()
|
||||
|
||||
filter_users = setOf(user_key, quoted_user_key, retweeted_by_user_key).filterNotNull().toTypedArray()
|
||||
|
||||
filter_names = setOf(user_name, quoted_user_name, retweeted_by_user_name).filterNotNull().toTypedArray()
|
||||
|
||||
val texts = StringBuilder()
|
||||
texts.appendNonEmptyLine(text_unescaped)
|
||||
texts.appendNonEmptyLine(quoted_text_unescaped)
|
||||
media?.forEach { item ->
|
||||
texts.appendNonEmptyLine(item.alt_text)
|
||||
}
|
||||
quoted_media?.forEach { item ->
|
||||
texts.appendNonEmptyLine(item.alt_text)
|
||||
}
|
||||
filter_texts = texts.toString()
|
||||
|
||||
filter_descriptions = descriptions?.filterNotNull()?.joinToString("\n")
|
||||
}
|
||||
|
||||
fun ParcelableStatus.updateExtraInformation(details: AccountDetails) {
|
||||
account_color = details.color
|
||||
}
|
||||
|
||||
val ParcelableStatus.quoted: ParcelableStatus?
|
||||
get() {
|
||||
val obj = ParcelableStatus()
|
||||
|
@ -182,6 +103,95 @@ val ParcelableStatus.quoted: ParcelableStatus?
|
|||
return obj
|
||||
}
|
||||
|
||||
fun ParcelableStatus.toSummaryLine(): ParcelableActivity.SummaryLine {
|
||||
val result = ParcelableActivity.SummaryLine()
|
||||
result.key = user_key
|
||||
result.name = user_name
|
||||
result.screen_name = user_screen_name
|
||||
result.content = text_unescaped
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
fun ParcelableStatus.extractFanfouHashtags(): List<String> {
|
||||
return spans?.filter { span ->
|
||||
var link = span.link
|
||||
if (link.startsWith("/")) {
|
||||
link = "http://fanfou.com$link"
|
||||
}
|
||||
if (UriUtils.getAuthority(link) != "fanfou.com") {
|
||||
return@filter false
|
||||
}
|
||||
if (span.start <= 0 || span.end > text_unescaped.lastIndex) return@filter false
|
||||
if (text_unescaped[span.start - 1] == '#' && text_unescaped[span.end] == '#') {
|
||||
return@filter true
|
||||
}
|
||||
return@filter false
|
||||
}?.map { text_unescaped.substring(it.start, it.end) }.orEmpty()
|
||||
}
|
||||
|
||||
fun ParcelableStatus.makeOriginal() {
|
||||
if (!is_retweet) return
|
||||
id = retweet_id
|
||||
is_retweet = false
|
||||
retweeted_by_user_key = null
|
||||
retweeted_by_user_name = null
|
||||
retweeted_by_user_screen_name = null
|
||||
retweeted_by_user_profile_image = null
|
||||
retweet_timestamp = -1
|
||||
retweet_id = null
|
||||
}
|
||||
|
||||
fun ParcelableStatus.addFilterFlag(@ParcelableStatus.FilterFlags flags: Long) {
|
||||
filter_flags = filter_flags or flags
|
||||
}
|
||||
|
||||
fun ParcelableStatus.updateFilterInfo(descriptions: Collection<String?>?) {
|
||||
updateContentFilterInfo()
|
||||
filter_users = setOf(user_key, quoted_user_key, retweeted_by_user_key).filterNotNull().toTypedArray()
|
||||
filter_names = setOf(user_name, quoted_user_name, retweeted_by_user_name).filterNotNull().toTypedArray()
|
||||
filter_descriptions = descriptions?.filterNotNull()?.joinToString("\n")
|
||||
}
|
||||
|
||||
fun ParcelableStatus.updateContentFilterInfo() {
|
||||
filter_links = generateFilterLinks()
|
||||
filter_texts = generateFilterTexts()
|
||||
|
||||
filter_sources = setOf(source?.plainText, quoted_source?.plainText).filterNotNull().toTypedArray()
|
||||
}
|
||||
|
||||
fun ParcelableStatus.generateFilterTexts(): String {
|
||||
val texts = StringBuilder()
|
||||
texts.appendNonEmptyLine(text_unescaped)
|
||||
texts.appendNonEmptyLine(quoted_text_unescaped)
|
||||
media?.forEach { item ->
|
||||
texts.appendNonEmptyLine(item.alt_text)
|
||||
}
|
||||
quoted_media?.forEach { item ->
|
||||
texts.appendNonEmptyLine(item.alt_text)
|
||||
}
|
||||
return texts.toString()
|
||||
}
|
||||
|
||||
fun ParcelableStatus.generateFilterLinks(): Array<String> {
|
||||
val links = mutableSetOf<String>()
|
||||
spans?.mapNotNullTo(links) { span ->
|
||||
if (span.type != SpanItem.SpanType.LINK) return@mapNotNullTo null
|
||||
return@mapNotNullTo span.link
|
||||
}
|
||||
quoted_spans?.mapNotNullTo(links) { span ->
|
||||
if (span.type != SpanItem.SpanType.LINK) return@mapNotNullTo null
|
||||
return@mapNotNullTo span.link
|
||||
}
|
||||
return links.toTypedArray()
|
||||
}
|
||||
|
||||
fun ParcelableStatus.updateExtraInformation(details: AccountDetails) {
|
||||
account_color = details.color
|
||||
}
|
||||
|
||||
internal inline val String.plainText: String get() = HtmlEscapeHelper.toPlainText(this)
|
||||
|
||||
private fun parcelableUserMention(key: UserKey, name: String, screenName: String) = ParcelableUserMention().also {
|
||||
it.key = key
|
||||
it.name = name
|
||||
|
@ -193,5 +203,3 @@ private fun StringBuilder.appendNonEmptyLine(line: CharSequence?) {
|
|||
append(line)
|
||||
append('\n')
|
||||
}
|
||||
|
||||
private val String.plainText: String get() = HtmlEscapeHelper.toPlainText(this)
|
|
@ -33,6 +33,7 @@ import org.mariotaku.microblog.library.twitter.model.Status
|
|||
import org.mariotaku.twidere.exception.MalformedResponseException
|
||||
import org.mariotaku.twidere.extension.model.addFilterFlag
|
||||
import org.mariotaku.twidere.extension.model.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.updateContentFilterInfo
|
||||
import org.mariotaku.twidere.extension.model.updateFilterInfo
|
||||
import org.mariotaku.twidere.extension.toSpanItem
|
||||
import org.mariotaku.twidere.model.*
|
||||
|
@ -46,19 +47,23 @@ import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
|||
import org.mariotaku.twidere.util.InternalTwitterContentUtils.getMediaUrl
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils.getStartEndForEntity
|
||||
|
||||
fun Status.toParcelable(details: AccountDetails, profileImageSize: String = "normal"): ParcelableStatus {
|
||||
return toParcelable(details.key, details.type, profileImageSize).apply {
|
||||
fun Status.toParcelable(details: AccountDetails, profileImageSize: String = "normal",
|
||||
updateFilterInfoAction: (Status, ParcelableStatus) -> Unit = ::updateFilterInfoDefault): ParcelableStatus {
|
||||
return toParcelable(details.key, details.type, profileImageSize, updateFilterInfoAction).apply {
|
||||
account_color = details.color
|
||||
}
|
||||
}
|
||||
|
||||
fun Status.toParcelable(accountKey: UserKey, accountType: String, profileImageSize: String = "normal"): ParcelableStatus {
|
||||
fun Status.toParcelable(accountKey: UserKey, accountType: String, profileImageSize: String = "normal",
|
||||
updateFilterInfoAction: (Status, ParcelableStatus) -> Unit = ::updateFilterInfoDefault): ParcelableStatus {
|
||||
val result = ParcelableStatus()
|
||||
applyTo(accountKey, accountType, profileImageSize, result)
|
||||
applyTo(accountKey, accountType, profileImageSize, result, updateFilterInfoAction)
|
||||
return result
|
||||
}
|
||||
|
||||
fun Status.applyTo(accountKey: UserKey, accountType: String, profileImageSize: String = "normal", result: ParcelableStatus) {
|
||||
fun Status.applyTo(accountKey: UserKey, accountType: String, profileImageSize: String = "normal",
|
||||
result: ParcelableStatus,
|
||||
updateFilterInfoAction: (Status, ParcelableStatus) -> Unit = ::updateFilterInfoDefault) {
|
||||
val extras = ParcelableStatus.Extras()
|
||||
result.account_key = accountKey
|
||||
result.id = id
|
||||
|
@ -201,10 +206,7 @@ fun Status.applyTo(accountKey: UserKey, accountType: String, profileImageSize: S
|
|||
result.addFilterFlag(ParcelableStatus.FilterFlags.HAS_MEDIA)
|
||||
}
|
||||
|
||||
result.updateFilterInfo(setOf(userDescriptionUnescaped, retweetedStatus?.userDescriptionUnescaped,
|
||||
quotedStatus?.userDescriptionUnescaped, this.user.location, retweetedStatus?.user?.location,
|
||||
quotedStatus?.user?.location, userUrlExpanded, retweetedStatus?.userUrlExpanded,
|
||||
quotedStatus?.userUrlExpanded))
|
||||
updateFilterInfoAction(this, result)
|
||||
}
|
||||
|
||||
|
||||
|
@ -228,7 +230,6 @@ fun Status.formattedTextWithIndices(): StatusTextWithIndices {
|
|||
return textWithIndices
|
||||
}
|
||||
|
||||
|
||||
fun CodePointArray.findResultRangeLength(spans: Array<SpanItem>, origStart: Int, origEnd: Int): Int {
|
||||
val findResult = findByOrigRange(spans, origStart, origEnd)
|
||||
if (findResult.isEmpty()) {
|
||||
|
@ -241,7 +242,6 @@ fun CodePointArray.findResultRangeLength(spans: Array<SpanItem>, origStart: Int,
|
|||
return charCount(origStart, first.orig_start) + (last.end - first.start) + charCount(first.orig_end, origEnd)
|
||||
}
|
||||
|
||||
|
||||
fun HtmlBuilder.addEntities(entities: EntitySupport) {
|
||||
// Format media.
|
||||
var mediaEntities: Array<MediaEntity>? = null
|
||||
|
@ -268,16 +268,62 @@ fun HtmlBuilder.addEntities(entities: EntitySupport) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fun updateFilterInfoDefault(status: Status, result: ParcelableStatus) {
|
||||
result.updateFilterInfo(setOf(
|
||||
status.userDescriptionUnescaped,
|
||||
status.userUrlExpanded,
|
||||
status.userLocation,
|
||||
status.retweetedStatus?.userDescriptionUnescaped,
|
||||
status.retweetedStatus?.userLocation,
|
||||
status.retweetedStatus?.userUrlExpanded,
|
||||
status.quotedStatus?.userDescriptionUnescaped,
|
||||
status.quotedStatus?.userLocation,
|
||||
status.quotedStatus?.userUrlExpanded
|
||||
))
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignores status user info
|
||||
*/
|
||||
fun updateFilterInfoForUserTimeline(status: Status, result: ParcelableStatus) {
|
||||
result.updateContentFilterInfo()
|
||||
|
||||
if (result.is_retweet) {
|
||||
result.filter_users = setOf(result.user_key, result.quoted_user_key).filterNotNull().toTypedArray()
|
||||
result.filter_names = setOf(result.user_name, result.quoted_user_name).filterNotNull().toTypedArray()
|
||||
result.filter_descriptions = setOf(
|
||||
status.retweetedStatus?.userDescriptionUnescaped,
|
||||
status.retweetedStatus?.userUrlExpanded,
|
||||
status.retweetedStatus?.userLocation,
|
||||
status.quotedStatus?.userDescriptionUnescaped,
|
||||
status.quotedStatus?.userLocation,
|
||||
status.quotedStatus?.userUrlExpanded
|
||||
).filterNotNull().joinToString("\n")
|
||||
} else {
|
||||
result.filter_users = setOf(result.quoted_user_key).filterNotNull().toTypedArray()
|
||||
result.filter_names = setOf(result.quoted_user_name).filterNotNull().toTypedArray()
|
||||
result.filter_descriptions = setOf(
|
||||
status.quotedStatus?.userDescriptionUnescaped,
|
||||
status.quotedStatus?.userLocation,
|
||||
status.quotedStatus?.userUrlExpanded
|
||||
).filterNotNull().joinToString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.twitterUnescaped(): String {
|
||||
return twitterRawTextTranslator.translate(this)
|
||||
}
|
||||
|
||||
private val Status.userDescriptionUnescaped: String?
|
||||
private inline val Status.userDescriptionUnescaped: String?
|
||||
get() = user?.let { InternalTwitterContentUtils.formatUserDescription(it)?.first }
|
||||
|
||||
private val Status.userUrlExpanded: String?
|
||||
private inline val Status.userUrlExpanded: String?
|
||||
get() = user?.urlEntities?.firstOrNull()?.expandedUrl
|
||||
|
||||
private inline val Status.userLocation: String?
|
||||
get() = user?.location
|
||||
|
||||
/**
|
||||
* @param spans Ordered spans
|
||||
* *
|
||||
|
|
|
@ -22,7 +22,6 @@ package org.mariotaku.twidere.loader.statuses
|
|||
import android.accounts.AccountManager
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
|
@ -30,7 +29,6 @@ import org.mariotaku.microblog.library.twitter.model.Paging
|
|||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.LOGTAG
|
||||
import org.mariotaku.twidere.app.TwidereApplication
|
||||
import org.mariotaku.twidere.constant.loadItemLimitKey
|
||||
import org.mariotaku.twidere.extension.model.api.applyLoadLimit
|
||||
import org.mariotaku.twidere.loader.iface.IPaginationLoader
|
||||
|
@ -170,8 +168,7 @@ abstract class AbsRequestStatusesLoader(
|
|||
data.addAll(statuses)
|
||||
}
|
||||
|
||||
val db = TwidereApplication.getInstance(context).sqLiteDatabase
|
||||
data.forEach { it.is_filtered = shouldFilterStatus(db, it) }
|
||||
data.forEach { it.is_filtered = shouldFilterStatus(it) }
|
||||
|
||||
if (comparator != null) {
|
||||
data.sortWith(comparator!!)
|
||||
|
@ -188,8 +185,7 @@ abstract class AbsRequestStatusesLoader(
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
protected abstract fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean
|
||||
|
||||
protected abstract fun shouldFilterStatus(status: ParcelableStatus): Boolean
|
||||
|
||||
protected open fun processPaging(paging: Paging, details: AccountDetails, loadItemLimit: Int) {
|
||||
paging.applyLoadLimit(details, loadItemLimit)
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.attoparser.config.ParseConfiguration
|
||||
import org.attoparser.dom.DOMMarkupParser
|
||||
|
@ -48,7 +47,7 @@ import org.mariotaku.twidere.model.pagination.PaginatedArrayList
|
|||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.model.pagination.Pagination
|
||||
import org.mariotaku.twidere.model.pagination.SinceMaxPagination
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
import java.text.ParseException
|
||||
import java.util.*
|
||||
|
||||
|
@ -120,8 +119,8 @@ class ConversationLoader(
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean {
|
||||
return InternalTwitterContentUtils.isFiltered(database, status, false)
|
||||
override fun shouldFilterStatus(status: ParcelableStatus): Boolean {
|
||||
return ContentFiltersUtils.isFiltered(context.contentResolver, status, false, 0)
|
||||
}
|
||||
|
||||
@Throws(MicroBlogException::class)
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import org.mariotaku.twidere.model.ListResponse
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
|
||||
class DummyParcelableStatusesLoader @JvmOverloads constructor(context: Context, data: List<ParcelableStatus>? = null, fromUser: Boolean = false) : ParcelableStatusesLoader(context, data, -1, fromUser) {
|
||||
|
||||
override fun loadInBackground(): ListResponse<ParcelableStatus> {
|
||||
return ListResponse.getListInstance(data)
|
||||
}
|
||||
|
||||
}
|
|
@ -20,13 +20,13 @@
|
|||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.exception.APINotSupportedException
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
|
@ -34,7 +34,7 @@ import org.mariotaku.twidere.model.AccountDetails
|
|||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
|
||||
class GroupTimelineLoader(
|
||||
context: Context,
|
||||
|
@ -57,18 +57,19 @@ class GroupTimelineLoader(
|
|||
}
|
||||
}
|
||||
@WorkerThread
|
||||
override fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean {
|
||||
return InternalTwitterContentUtils.isFiltered(database, status, true)
|
||||
override fun shouldFilterStatus(status: ParcelableStatus): Boolean {
|
||||
return ContentFiltersUtils.isFiltered(context.contentResolver, status, true,
|
||||
FilterScope.LIST_GROUP_TIMELINE)
|
||||
}
|
||||
|
||||
private fun getMicroBlogStatuses(account: AccountDetails, paging: Paging): List<Status> {
|
||||
val microBlog = account.newMicroBlogInstance(context, MicroBlog::class.java)
|
||||
when {
|
||||
return when {
|
||||
groupId != null -> {
|
||||
return microBlog.getGroupStatuses(groupId, paging)
|
||||
microBlog.getGroupStatuses(groupId, paging)
|
||||
}
|
||||
groupName != null -> {
|
||||
return microBlog.getGroupStatusesByName(groupName, paging)
|
||||
microBlog.getGroupStatusesByName(groupName, paging)
|
||||
}
|
||||
else -> {
|
||||
throw MicroBlogException("No group name or id given")
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_STATUSES
|
||||
import org.mariotaku.twidere.model.ListResponse
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import java.util.*
|
||||
|
||||
class IntentExtrasStatusesLoader(context: Context, private val mExtras: Bundle?,
|
||||
data: List<ParcelableStatus>, fromUser: Boolean) : ParcelableStatusesLoader(context, data, -1, fromUser) {
|
||||
|
||||
override fun loadInBackground(): ListResponse<ParcelableStatus> {
|
||||
if (mExtras != null && mExtras.containsKey(EXTRA_STATUSES)) {
|
||||
val users = mExtras.getParcelableArrayList<ParcelableStatus>(EXTRA_STATUSES)
|
||||
if (users != null) {
|
||||
data.addAll(users)
|
||||
Collections.sort(data)
|
||||
}
|
||||
}
|
||||
return ListResponse.getListInstance(data)
|
||||
}
|
||||
|
||||
}
|
|
@ -20,7 +20,6 @@
|
|||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.ktextension.isNullOrEmpty
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
|
@ -30,6 +29,7 @@ import org.mariotaku.microblog.library.twitter.model.SearchQuery
|
|||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.microblog.library.twitter.model.UniversalSearchQuery
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
import org.mariotaku.twidere.extension.model.official
|
||||
|
@ -37,7 +37,7 @@ import org.mariotaku.twidere.model.AccountDetails
|
|||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
|
||||
open class MediaStatusesSearchLoader(
|
||||
context: Context,
|
||||
|
@ -60,9 +60,11 @@ open class MediaStatusesSearchLoader(
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean {
|
||||
override fun shouldFilterStatus(status: ParcelableStatus): Boolean {
|
||||
if (status.media.isNullOrEmpty()) return true
|
||||
return InternalTwitterContentUtils.isFiltered(database, status, true)
|
||||
val allowed = query?.split(' ')?.toTypedArray()
|
||||
return ContentFiltersUtils.isFiltered(context.contentResolver, status, true,
|
||||
FilterScope.SEARCH_RESULTS, allowed)
|
||||
}
|
||||
|
||||
override fun processPaging(paging: Paging, details: AccountDetails, loadItemLimit: Int) {
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.ktextension.isNullOrEmpty
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
|
@ -29,10 +28,12 @@ import org.mariotaku.microblog.library.mastodon.Mastodon
|
|||
import org.mariotaku.microblog.library.twitter.model.*
|
||||
import org.mariotaku.twidere.alias.MastodonTimelineOption
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.extension.api.tryShowUser
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.mapToPaginated
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.api.updateFilterInfoForUserTimeline
|
||||
import org.mariotaku.twidere.extension.model.isOfficial
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
|
@ -40,7 +41,7 @@ import org.mariotaku.twidere.model.ParcelableStatus
|
|||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.util.DataStoreUtils
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
|
||||
class MediaTimelineLoader(
|
||||
context: Context,
|
||||
|
@ -69,21 +70,20 @@ class MediaTimelineLoader(
|
|||
|
||||
@Throws(MicroBlogException::class)
|
||||
override fun getStatuses(account: AccountDetails, paging: Paging): PaginatedList<ParcelableStatus> {
|
||||
when (account.type) {
|
||||
AccountType.MASTODON -> return getMastodonStatuses(account, paging)
|
||||
else -> return getMicroBlogStatuses(account, paging).mapMicroBlogToPaginated {
|
||||
it.toParcelable(account, profileImageSize)
|
||||
return when (account.type) {
|
||||
AccountType.MASTODON -> getMastodonStatuses(account, paging)
|
||||
else -> getMicroBlogStatuses(account, paging).mapMicroBlogToPaginated {
|
||||
it.toParcelable(account, profileImageSize = profileImageSize,
|
||||
updateFilterInfoAction = ::updateFilterInfoForUserTimeline)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean {
|
||||
override fun shouldFilterStatus(status: ParcelableStatus): Boolean {
|
||||
if (status.media.isNullOrEmpty()) return false
|
||||
val retweetUserKey = status.user_key.takeIf { status.is_retweet }
|
||||
return !isMyTimeline && InternalTwitterContentUtils.isFiltered(database, retweetUserKey,
|
||||
status.text_plain, status.quoted_text_plain, status.spans, status.quoted_spans,
|
||||
status.source, status.quoted_source, null, status.quoted_user_key)
|
||||
return !isMyTimeline && ContentFiltersUtils.isFiltered(context.contentResolver, status,
|
||||
true, FilterScope.USER_TIMELINE)
|
||||
}
|
||||
|
||||
private fun getMicroBlogStatuses(account: AccountDetails, paging: Paging): ResponseList<Status> {
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.mastodon.Mastodon
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.exception.APINotSupportedException
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.mapToPaginated
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.toParcelable
|
||||
|
@ -36,7 +36,7 @@ import org.mariotaku.twidere.model.AccountDetails
|
|||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
|
||||
class NetworkPublicTimelineLoader(
|
||||
context: Context,
|
||||
|
@ -68,7 +68,8 @@ class NetworkPublicTimelineLoader(
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean {
|
||||
return InternalTwitterContentUtils.isFiltered(database, status, true)
|
||||
override fun shouldFilterStatus(status: ParcelableStatus): Boolean {
|
||||
return ContentFiltersUtils.isFiltered(context.contentResolver, status, true,
|
||||
FilterScope.SEARCH_RESULTS)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.mastodon.Mastodon
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.mapToPaginated
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
|
@ -35,7 +35,7 @@ import org.mariotaku.twidere.model.AccountDetails
|
|||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
|
||||
class PublicTimelineLoader(
|
||||
context: Context,
|
||||
|
@ -66,7 +66,8 @@ class PublicTimelineLoader(
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean {
|
||||
return InternalTwitterContentUtils.isFiltered(database, status, true)
|
||||
override fun shouldFilterStatus(status: ParcelableStatus): Boolean {
|
||||
return ContentFiltersUtils.isFiltered(context.contentResolver, status, true,
|
||||
FilterScope.SEARCH_RESULTS)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
|
@ -30,6 +29,7 @@ import org.mariotaku.microblog.library.twitter.model.SearchQuery
|
|||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.microblog.library.twitter.model.UniversalSearchQuery
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.mapToPaginated
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
|
@ -41,7 +41,7 @@ import org.mariotaku.twidere.model.UserKey
|
|||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.model.pagination.Pagination
|
||||
import org.mariotaku.twidere.model.pagination.SinceMaxPagination
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
|
||||
open class TweetSearchLoader(
|
||||
context: Context,
|
||||
|
@ -59,22 +59,24 @@ open class TweetSearchLoader(
|
|||
|
||||
@Throws(MicroBlogException::class)
|
||||
override fun getStatuses(account: AccountDetails, paging: Paging): PaginatedList<ParcelableStatus> {
|
||||
when (account.type) {
|
||||
AccountType.MASTODON -> return getMastodonStatuses(account, paging)
|
||||
else -> return getMicroBlogStatuses(account, paging).mapMicroBlogToPaginated {
|
||||
return when (account.type) {
|
||||
AccountType.MASTODON -> getMastodonStatuses(account, paging)
|
||||
else -> getMicroBlogStatuses(account, paging).mapMicroBlogToPaginated {
|
||||
it.toParcelable(account, profileImageSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean {
|
||||
return InternalTwitterContentUtils.isFiltered(database, status, true)
|
||||
override fun shouldFilterStatus(status: ParcelableStatus): Boolean {
|
||||
val allowed = query?.split(' ')?.toTypedArray()
|
||||
return ContentFiltersUtils.isFiltered(context.contentResolver, status, true,
|
||||
FilterScope.SEARCH_RESULTS, allowed)
|
||||
}
|
||||
|
||||
protected open fun processQuery(details: AccountDetails, query: String): String {
|
||||
if (details.type == AccountType.TWITTER) {
|
||||
if (details.extras?.official ?: false) {
|
||||
if (details.extras?.official == true) {
|
||||
return smQuery(query, pagination)
|
||||
}
|
||||
return "$query exclude:retweets"
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
|
@ -29,6 +28,7 @@ import org.mariotaku.microblog.library.twitter.model.Paging
|
|||
import org.mariotaku.microblog.library.twitter.model.ResponseList
|
||||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.mapToPaginated
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
|
@ -37,7 +37,7 @@ import org.mariotaku.twidere.model.AccountDetails
|
|||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
|
||||
class UserFavoritesLoader(
|
||||
context: Context,
|
||||
|
@ -64,8 +64,9 @@ class UserFavoritesLoader(
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean {
|
||||
return InternalTwitterContentUtils.isFiltered(database, status, false)
|
||||
override fun shouldFilterStatus(status: ParcelableStatus): Boolean {
|
||||
return ContentFiltersUtils.isFiltered(context.contentResolver, status, false,
|
||||
FilterScope.FAVORITES)
|
||||
}
|
||||
|
||||
private fun getMicroBlogStatuses(account: AccountDetails, paging: Paging): ResponseList<Status> {
|
||||
|
|
|
@ -20,20 +20,20 @@
|
|||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
import org.mariotaku.microblog.library.twitter.model.ResponseList
|
||||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
|
||||
class UserListTimelineLoader(
|
||||
context: Context,
|
||||
|
@ -57,8 +57,9 @@ class UserListTimelineLoader(
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean {
|
||||
return InternalTwitterContentUtils.isFiltered(database, status, true)
|
||||
override fun shouldFilterStatus(status: ParcelableStatus): Boolean {
|
||||
return ContentFiltersUtils.isFiltered(context.contentResolver, status, true,
|
||||
FilterScope.LIST_GROUP_TIMELINE)
|
||||
}
|
||||
|
||||
private fun getMicroBlogStatuses(account: AccountDetails, paging: Paging): ResponseList<Status> {
|
||||
|
|
|
@ -43,7 +43,7 @@ class UserMentionsLoader(
|
|||
override fun processQuery(details: AccountDetails, query: String): String {
|
||||
val screenName = query.substringAfter("@")
|
||||
if (details.type == AccountType.TWITTER) {
|
||||
if (details.extras?.official ?: false) {
|
||||
if (details.extras?.official == true) {
|
||||
return smQuery("to:$screenName", pagination)
|
||||
}
|
||||
return "to:$screenName exclude:retweets"
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
package org.mariotaku.twidere.loader.statuses
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import android.text.TextUtils
|
||||
import okhttp3.HttpUrl
|
||||
|
@ -42,18 +41,20 @@ import org.mariotaku.restfu.http.mime.SimpleBody
|
|||
import org.mariotaku.twidere.alias.MastodonStatus
|
||||
import org.mariotaku.twidere.alias.MastodonTimelineOption
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.extension.api.tryShowUser
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.mapToPaginated
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.api.updateFilterInfoForUserTimeline
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.timeline.UserTimelineFilter
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.JsonSerializer
|
||||
import org.mariotaku.twidere.util.dagger.DependencyHolder
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
|
@ -86,12 +87,13 @@ class UserTimelineLoader(
|
|||
it.toParcelable(account)
|
||||
}
|
||||
else -> getMicroBlogStatuses(account, paging).mapMicroBlogToPaginated {
|
||||
it.toParcelable(account, profileImageSize = profileImageSize)
|
||||
it.toParcelable(account, profileImageSize = profileImageSize,
|
||||
updateFilterInfoAction = ::updateFilterInfoForUserTimeline)
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun shouldFilterStatus(database: SQLiteDatabase, status: ParcelableStatus): Boolean {
|
||||
override fun shouldFilterStatus(status: ParcelableStatus): Boolean {
|
||||
if (timelineFilter != null) {
|
||||
if (status.is_retweet && !timelineFilter.isIncludeRetweets) {
|
||||
return true
|
||||
|
@ -99,10 +101,8 @@ class UserTimelineLoader(
|
|||
}
|
||||
if (accountKey != null && userKey != null && TextUtils.equals(accountKey.id, userKey.id))
|
||||
return false
|
||||
val retweetUserKey = status.user_key.takeIf { status.is_retweet }
|
||||
return InternalTwitterContentUtils.isFiltered(database, retweetUserKey, status.text_plain,
|
||||
status.quoted_text_plain, status.spans, status.quoted_spans, status.source,
|
||||
status.quoted_source, null, status.quoted_user_key)
|
||||
return ContentFiltersUtils.isFiltered(context.contentResolver, status, true,
|
||||
FilterScope.USER_TIMELINE)
|
||||
}
|
||||
|
||||
private fun getMastodonStatuses(account: AccountDetails, paging: Paging): LinkHeaderList<MastodonStatus> {
|
||||
|
|
|
@ -493,13 +493,19 @@ object DataStoreUtils {
|
|||
fun ContainsExpression(dataField: String, filterTable: String, filterField: String) =
|
||||
Expression.likeRaw(Column(Table(table), dataField), "'%'||$filterTable.$filterField||'%'")
|
||||
|
||||
fun LineContainsExpression(dataField: String, filterTable: String, filterField: String) =
|
||||
Expression.likeRaw(Column(Table(table), dataField), "'\\%'||$filterTable.$filterField||'%\\'")
|
||||
|
||||
fun LineMatchExpression(dataField: String, filterTable: String, filterField: String) =
|
||||
Expression.likeRaw(Column(Table(table), dataField), "'%\\'||$filterTable.$filterField||'\\%'")
|
||||
|
||||
val filteredUsersWhere = Expression.and(
|
||||
ScopeMatchesExpression(Filters.Users.TABLE_NAME, Filters.Users.SCOPE),
|
||||
ContainsExpression(Statuses.FILTER_USERS, Filters.Users.TABLE_NAME, Filters.Users.USER_KEY)
|
||||
LineMatchExpression(Statuses.FILTER_USERS, Filters.Users.TABLE_NAME, Filters.Users.USER_KEY)
|
||||
)
|
||||
val filteredSourcesWhere = Expression.and(
|
||||
ScopeMatchesExpression(Filters.Sources.TABLE_NAME, Filters.Sources.SCOPE),
|
||||
ContainsExpression(Statuses.FILTER_SOURCES, Filters.Sources.TABLE_NAME, Filters.Sources.VALUE)
|
||||
LineMatchExpression(Statuses.FILTER_SOURCES, Filters.Sources.TABLE_NAME, Filters.Sources.VALUE)
|
||||
)
|
||||
val filteredTextKeywordsWhere = Expression.or(
|
||||
Expression.and(
|
||||
|
@ -513,7 +519,7 @@ object DataStoreUtils {
|
|||
Expression.and(
|
||||
Expression.notEquals("${Filters.Keywords.TABLE_NAME}.${Filters.Keywords.SCOPE} & ${FilterScope.TARGET_NAME}", 0),
|
||||
ScopeMatchesExpression(Filters.Keywords.TABLE_NAME, Filters.Keywords.SCOPE),
|
||||
ContainsExpression(Statuses.FILTER_NAMES, Filters.Keywords.TABLE_NAME, Filters.Keywords.VALUE)
|
||||
LineMatchExpression(Statuses.FILTER_NAMES, Filters.Keywords.TABLE_NAME, Filters.Keywords.VALUE)
|
||||
),
|
||||
Expression.and(
|
||||
Expression.notEquals("${Filters.Keywords.TABLE_NAME}.${Filters.Keywords.SCOPE} & ${FilterScope.TARGET_DESCRIPTION}", 0),
|
||||
|
@ -523,7 +529,7 @@ object DataStoreUtils {
|
|||
)
|
||||
val filteredLinksWhere = Expression.and(
|
||||
ScopeMatchesExpression(Filters.Links.TABLE_NAME, Filters.Links.SCOPE),
|
||||
ContainsExpression(Statuses.FILTER_LINKS, Filters.Links.TABLE_NAME, Filters.Links.VALUE)
|
||||
LineContainsExpression(Statuses.FILTER_LINKS, Filters.Links.TABLE_NAME, Filters.Links.VALUE)
|
||||
)
|
||||
val filteredIdsQueryBuilder = SQLQueryBuilder
|
||||
.select(Column(Table(table), Statuses._ID))
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util.database
|
||||
|
||||
import android.content.ContentResolver
|
||||
import org.mariotaku.twidere.annotation.FilterScope
|
||||
import org.mariotaku.twidere.extension.rawQuery
|
||||
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,
|
||||
status.filter_sources, status.filter_links, status.filter_names,
|
||||
status.filter_descriptions, filterRts, scope, allowedKeywords)
|
||||
}
|
||||
|
||||
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>?,
|
||||
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>()
|
||||
val queryBuilder = StringBuilder("SELECT ")
|
||||
|
||||
fun addExpression(ruleTable: String, ruleField: String, scopeField: String,
|
||||
@FilterScope expressionScope: Int, noScopeAsTrue: Boolean, matchType: Int,
|
||||
value: String, extraWhereAppend: ((StringBuilder, MutableList<String>, String) -> Unit)? = null) {
|
||||
if (selectionArgs.isNotEmpty()) {
|
||||
queryBuilder.append(" OR ")
|
||||
}
|
||||
selectionArgs.add(value)
|
||||
queryBuilder.append("1 IN (SELECT ? LIKE ")
|
||||
when (matchType) {
|
||||
LINE_MATCH -> {
|
||||
queryBuilder.append("'%\\'||")
|
||||
queryBuilder.append(ruleField)
|
||||
queryBuilder.append("||'\\%'")
|
||||
}
|
||||
LINE_CONTAINS -> {
|
||||
queryBuilder.append("'\\%'||")
|
||||
queryBuilder.append(ruleField)
|
||||
queryBuilder.append("||'%\\'")
|
||||
}
|
||||
CONTAINS -> {
|
||||
queryBuilder.append("'%'||")
|
||||
queryBuilder.append(ruleField)
|
||||
queryBuilder.append("||'%'")
|
||||
}
|
||||
}
|
||||
queryBuilder.append(" FROM ")
|
||||
queryBuilder.append(ruleTable)
|
||||
queryBuilder.append(" WHERE ")
|
||||
if (noScopeAsTrue) {
|
||||
queryBuilder.append("(")
|
||||
queryBuilder.append(scopeField)
|
||||
queryBuilder.append(" = 0 OR ")
|
||||
}
|
||||
queryBuilder.append(scopeField)
|
||||
queryBuilder.append(" & ")
|
||||
queryBuilder.append(expressionScope)
|
||||
queryBuilder.append(" != 0")
|
||||
if (noScopeAsTrue) {
|
||||
queryBuilder.append(")")
|
||||
}
|
||||
extraWhereAppend?.invoke(queryBuilder, selectionArgs, ruleField)
|
||||
queryBuilder.append(")")
|
||||
|
||||
}
|
||||
|
||||
fun allowKeywordsWhere(sb: StringBuilder, args: MutableList<String>, ruleField: String) {
|
||||
val allowed = allowedKeywords?.takeUnless(Array<*>::isEmpty) ?: return
|
||||
sb.append(" AND NOT (")
|
||||
allowed.forEachIndexed { i, s ->
|
||||
args.add(s)
|
||||
if (i != 0) {
|
||||
sb.append(" OR ")
|
||||
}
|
||||
sb.append("? LIKE ")
|
||||
sb.append(ruleField)
|
||||
}
|
||||
sb.append(")")
|
||||
}
|
||||
|
||||
if (users != null) {
|
||||
addExpression(Users.TABLE_NAME, Users.USER_KEY, Users.SCOPE, scope, true,
|
||||
LINE_MATCH, users.joinToString("\n", "\\", "\\"))
|
||||
}
|
||||
if (sources != null) {
|
||||
addExpression(Sources.TABLE_NAME, Sources.VALUE, Sources.SCOPE, scope, true,
|
||||
LINE_MATCH, sources.joinToString("\n", "\\", "\\"))
|
||||
}
|
||||
if (links != null) {
|
||||
addExpression(Links.TABLE_NAME, Links.VALUE, Links.SCOPE, scope, true,
|
||||
LINE_CONTAINS, links.joinToString("\n", "\\", "\\"))
|
||||
}
|
||||
if (texts != null) {
|
||||
addExpression(Keywords.TABLE_NAME, Keywords.VALUE, Keywords.SCOPE,
|
||||
FilterScope.TARGET_TEXT or scope, true, CONTAINS,
|
||||
texts, ::allowKeywordsWhere)
|
||||
}
|
||||
if (names != null) {
|
||||
addExpression(Keywords.TABLE_NAME, Keywords.VALUE, Keywords.SCOPE,
|
||||
FilterScope.TARGET_NAME or scope, false, LINE_CONTAINS,
|
||||
names.joinToString("\n", "\\", "\\"), ::allowKeywordsWhere)
|
||||
}
|
||||
if (descriptions != null) {
|
||||
addExpression(Keywords.TABLE_NAME, Keywords.VALUE, Keywords.SCOPE,
|
||||
FilterScope.TARGET_DESCRIPTION or scope, false, CONTAINS,
|
||||
descriptions, ::allowKeywordsWhere)
|
||||
}
|
||||
if (queryBuilder.isEmpty())
|
||||
return Pair("SELECT 0", emptyArray())
|
||||
return Pair(queryBuilder.toString(), selectionArgs.toTypedArray())
|
||||
}
|
||||
|
||||
private const val LINE_MATCH = 0
|
||||
private const val LINE_CONTAINS = 1
|
||||
private const val CONTAINS = 2
|
||||
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util.database
|
||||
|
||||
import android.content.ContentResolver
|
||||
import org.mariotaku.twidere.extension.rawQuery
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.SpanItem
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/2/16.
|
||||
*/
|
||||
|
||||
object FilterQueryBuilder {
|
||||
|
||||
fun isFiltered(cr: ContentResolver, activity: ParcelableStatus): Boolean {
|
||||
return isFiltered(cr, activity.user_key, activity.text_plain,
|
||||
activity.quoted_text_plain, activity.spans, activity.quoted_spans,
|
||||
activity.source, activity.quoted_source, activity.retweeted_by_user_key,
|
||||
activity.quoted_user_key)
|
||||
}
|
||||
|
||||
fun isFiltered(cr: ContentResolver, userKey: UserKey?, textPlain: String?, quotedTextPlain: String?,
|
||||
spans: Array<SpanItem>?, quotedSpans: Array<SpanItem>?, source: String?, quotedSource: String?,
|
||||
retweetedByKey: UserKey?, quotedUserKey: UserKey?): Boolean {
|
||||
val query = FilterQueryBuilder.isFilteredQuery(userKey,
|
||||
textPlain, quotedTextPlain, spans, quotedSpans, source, quotedSource, retweetedByKey,
|
||||
quotedUserKey, true)
|
||||
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(userKey: UserKey?, textPlain: String?, quotedTextPlain: String?,
|
||||
spans: Array<SpanItem>?, quotedSpans: Array<SpanItem>?, source: String?, quotedSource: String?,
|
||||
retweetedByKey: UserKey?, quotedUserKey: UserKey?, filterRts: Boolean): Pair<String, Array<String>> {
|
||||
val builder = StringBuilder()
|
||||
val selectionArgs = ArrayList<String>()
|
||||
builder.append("SELECT ")
|
||||
if (textPlain != null) {
|
||||
selectionArgs.add(textPlain)
|
||||
addTextPlainStatement(builder)
|
||||
}
|
||||
if (quotedTextPlain != null) {
|
||||
if (!selectionArgs.isEmpty()) {
|
||||
builder.append(" OR ")
|
||||
}
|
||||
selectionArgs.add(quotedTextPlain)
|
||||
addTextPlainStatement(builder)
|
||||
}
|
||||
if (spans != null) {
|
||||
if (!selectionArgs.isEmpty()) {
|
||||
builder.append(" OR ")
|
||||
}
|
||||
addSpansStatement(spans, builder, selectionArgs)
|
||||
}
|
||||
if (quotedSpans != null) {
|
||||
if (!selectionArgs.isEmpty()) {
|
||||
builder.append(" OR ")
|
||||
}
|
||||
addSpansStatement(quotedSpans, builder, selectionArgs)
|
||||
}
|
||||
if (userKey != null) {
|
||||
if (!selectionArgs.isEmpty()) {
|
||||
builder.append(" OR ")
|
||||
}
|
||||
selectionArgs.add(userKey.toString())
|
||||
createUserKeyStatement(builder)
|
||||
}
|
||||
if (retweetedByKey != null) {
|
||||
if (!selectionArgs.isEmpty()) {
|
||||
builder.append(" OR ")
|
||||
}
|
||||
selectionArgs.add(retweetedByKey.toString())
|
||||
createUserKeyStatement(builder)
|
||||
}
|
||||
if (quotedUserKey != null) {
|
||||
if (!selectionArgs.isEmpty()) {
|
||||
builder.append(" OR ")
|
||||
}
|
||||
selectionArgs.add(quotedUserKey.toString())
|
||||
createUserKeyStatement(builder)
|
||||
}
|
||||
if (source != null) {
|
||||
if (!selectionArgs.isEmpty()) {
|
||||
builder.append(" OR ")
|
||||
}
|
||||
selectionArgs.add(source)
|
||||
appendSourceStatement(builder)
|
||||
}
|
||||
if (quotedSource != null) {
|
||||
if (!selectionArgs.isEmpty()) {
|
||||
builder.append(" OR ")
|
||||
}
|
||||
selectionArgs.add(quotedSource)
|
||||
appendSourceStatement(builder)
|
||||
}
|
||||
return Pair(builder.toString(), selectionArgs.toTypedArray())
|
||||
}
|
||||
|
||||
|
||||
private fun createUserKeyStatement(builder: StringBuilder) {
|
||||
builder.append("(SELECT ")
|
||||
.append("?")
|
||||
.append(" IN (SELECT ")
|
||||
.append(Filters.Users.USER_KEY)
|
||||
.append(" FROM ")
|
||||
.append(Filters.Users.TABLE_NAME)
|
||||
.append("))")
|
||||
}
|
||||
|
||||
private fun appendSourceStatement(builder: StringBuilder) {
|
||||
builder.append("(SELECT 1 IN (SELECT ? LIKE '%>'||")
|
||||
.append(Filters.Sources.TABLE_NAME).append(".")
|
||||
.append(Filters.VALUE).append("||'</a>%' FROM ")
|
||||
.append(Filters.Sources.TABLE_NAME)
|
||||
.append("))")
|
||||
}
|
||||
|
||||
private fun addTextPlainStatement(builder: StringBuilder) {
|
||||
builder.append("(SELECT 1 IN (SELECT ? LIKE '%'||")
|
||||
.append(Filters.Keywords.TABLE_NAME)
|
||||
.append(".")
|
||||
.append(Filters.VALUE)
|
||||
.append("||'%' FROM ")
|
||||
.append(Filters.Keywords.TABLE_NAME)
|
||||
.append("))")
|
||||
}
|
||||
|
||||
private fun addSpansStatement(spans: Array<SpanItem>, builder: StringBuilder, selectionArgs: MutableList<String>) {
|
||||
val spansFlat = StringBuilder()
|
||||
for (span in spans) {
|
||||
spansFlat.append(span.link)
|
||||
spansFlat.append(' ')
|
||||
}
|
||||
selectionArgs.add(spansFlat.toString())
|
||||
builder.append("(SELECT 1 IN (SELECT ? LIKE '%'||")
|
||||
.append(Filters.Links.TABLE_NAME)
|
||||
.append(".")
|
||||
.append(Filters.VALUE)
|
||||
.append("||'%' FROM ")
|
||||
.append(Filters.Links.TABLE_NAME)
|
||||
.append("))")
|
||||
}
|
||||
|
||||
}
|
|
@ -62,7 +62,7 @@ import org.mariotaku.twidere.receiver.NotificationReceiver
|
|||
import org.mariotaku.twidere.service.LengthyOperationsService
|
||||
import org.mariotaku.twidere.util.*
|
||||
import org.mariotaku.twidere.util.Utils
|
||||
import org.mariotaku.twidere.util.database.FilterQueryBuilder
|
||||
import org.mariotaku.twidere.util.database.ContentFiltersUtils
|
||||
import org.oshkimaadziig.george.androidutils.SpanFormatter
|
||||
|
||||
class ContentNotificationManager(
|
||||
|
@ -219,7 +219,7 @@ class ContentNotificationManager(
|
|||
if (pref.isNotificationMentionsOnly && activity.action !in Activity.Action.MENTION_ACTIONS) {
|
||||
return@forEachRow false
|
||||
}
|
||||
if (FilterQueryBuilder.isFiltered(cr, activity)) {
|
||||
if (ContentFiltersUtils.isFiltered(cr, activity, true, FilterScope.INTERACTIONS)) {
|
||||
return@forEachRow false
|
||||
}
|
||||
val sources = ParcelableActivityUtils.filterSources(activity.sources_lite,
|
||||
|
|
Loading…
Reference in New Issue