only check once for filters v2 availability (#4539)

Instead of calling the endpoint every time filters are needed, it will
be called only once and the result cached. This will result in quite
some requests less on instances supporting v2.

I also tested v1 filters and made some small improvements. We should
[remove filters v1
support](https://github.com/tuskyapp/Tusky/issues/4538) some time in the
future though.
This commit is contained in:
Konrad Pozniak 2024-07-03 21:18:09 +02:00 committed by GitHub
commit 8a57bcc3f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 1470 additions and 127 deletions

View file

@ -1,8 +1,13 @@
package com.keylesspalace.tusky.network
import android.util.Log
import at.connyduck.calladapter.networkresult.fold
import at.connyduck.calladapter.networkresult.getOrElse
import com.keylesspalace.tusky.components.instanceinfo.InstanceInfoRepository
import com.keylesspalace.tusky.entity.Filter
import com.keylesspalace.tusky.entity.FilterV1
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.util.isHttpNotFound
import com.keylesspalace.tusky.util.parseAsMastodonHtml
import java.util.Date
import java.util.regex.Pattern
@ -11,17 +16,54 @@ import javax.inject.Inject
/**
* One-stop for status filtering logic using Mastodon's filters.
*
* 1. You init with [initWithFilters], this compiles regex pattern.
* 1. You init with [init], this checks which filter version to use and compiles regex pattern if needed.
* 2. You call [shouldFilterStatus] to figure out what to display when you load statuses.
*/
class FilterModel @Inject constructor() {
class FilterModel @Inject constructor(
private val instanceInfoRepo: InstanceInfoRepository,
private val api: MastodonApi
) {
private var pattern: Pattern? = null
private var v1 = false
lateinit var kind: Filter.Kind
private lateinit var kind: Filter.Kind
fun initWithFilters(filters: List<FilterV1>) {
v1 = true
this.pattern = makeFilter(filters)
/**
* @param kind the [Filter.Kind] that should be filtered
* @return true when filters v1 have been loaded successfully and the currently shown posts may need to be filtered
*/
suspend fun init(kind: Filter.Kind): Boolean {
this.kind = kind
if (instanceInfoRepo.isFilterV2Supported()) {
// nothing to do - Instance supports V2 so posts are filtered by the server
return false
}
api.getFilters().fold(
{
instanceInfoRepo.saveFilterV2Support(true)
return false
},
{ throwable ->
if (throwable.isHttpNotFound()) {
val filters = api.getFiltersV1().getOrElse {
Log.w(TAG, "Failed to fetch filters", it)
return false
}
this.v1 = true
val activeFilters = filters.filter { filter -> filter.context.contains(kind.kind) }
this.pattern = makeFilter(activeFilters)
return activeFilters.isNotEmpty()
} else {
Log.e(TAG, "Error getting filters", throwable)
return false
}
}
)
}
fun shouldFilterStatus(status: Status): Filter.Action {
@ -81,6 +123,7 @@ class FilterModel @Inject constructor() {
}
companion object {
private const val TAG = "FilterModel"
private val ALPHANUMERIC = Pattern.compile("^\\w+$")
}
}