3891 better hashtag filtering (#3893)
Fixes #3891 (the first two observerations; the rest is either ok or has another issue)
This commit is contained in:
commit
b0150212c3
|
@ -27,6 +27,8 @@ import at.connyduck.calladapter.networkresult.fold
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.keylesspalace.tusky.appstore.EventHub
|
import com.keylesspalace.tusky.appstore.EventHub
|
||||||
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
|
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
|
||||||
|
import com.keylesspalace.tusky.components.filters.EditFilterActivity
|
||||||
|
import com.keylesspalace.tusky.components.filters.FiltersActivity
|
||||||
import com.keylesspalace.tusky.components.timeline.TimelineFragment
|
import com.keylesspalace.tusky.components.timeline.TimelineFragment
|
||||||
import com.keylesspalace.tusky.components.timeline.viewmodel.TimelineViewModel.Kind
|
import com.keylesspalace.tusky.components.timeline.viewmodel.TimelineViewModel.Kind
|
||||||
import com.keylesspalace.tusky.databinding.ActivityStatuslistBinding
|
import com.keylesspalace.tusky.databinding.ActivityStatuslistBinding
|
||||||
|
@ -132,6 +134,8 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
{
|
{
|
||||||
followTagItem?.isVisible = false
|
followTagItem?.isVisible = false
|
||||||
unfollowTagItem?.isVisible = true
|
unfollowTagItem?.isVisible = true
|
||||||
|
|
||||||
|
Snackbar.make(binding.root, getString(R.string.following_hashtag_success_format, tag), Snackbar.LENGTH_SHORT).show()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Snackbar.make(binding.root, getString(R.string.error_following_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
|
Snackbar.make(binding.root, getString(R.string.error_following_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
|
||||||
|
@ -152,6 +156,8 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
{
|
{
|
||||||
followTagItem?.isVisible = true
|
followTagItem?.isVisible = true
|
||||||
unfollowTagItem?.isVisible = false
|
unfollowTagItem?.isVisible = false
|
||||||
|
|
||||||
|
Snackbar.make(binding.root, getString(R.string.unfollowing_hashtag_success_format, tag), Snackbar.LENGTH_SHORT).show()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Snackbar.make(binding.root, getString(R.string.error_unfollowing_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
|
Snackbar.make(binding.root, getString(R.string.error_unfollowing_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
|
||||||
|
@ -169,6 +175,7 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
*/
|
*/
|
||||||
private fun updateMuteTagMenuItems() {
|
private fun updateMuteTagMenuItems() {
|
||||||
val tag = hashtag ?: return
|
val tag = hashtag ?: return
|
||||||
|
val hashedTag = "#$tag"
|
||||||
|
|
||||||
muteTagItem?.isVisible = true
|
muteTagItem?.isVisible = true
|
||||||
muteTagItem?.isEnabled = false
|
muteTagItem?.isEnabled = false
|
||||||
|
@ -178,9 +185,8 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
mastodonApi.getFilters().fold(
|
mastodonApi.getFilters().fold(
|
||||||
{ filters ->
|
{ filters ->
|
||||||
mutedFilter = filters.firstOrNull { filter ->
|
mutedFilter = filters.firstOrNull { filter ->
|
||||||
filter.context.contains(Filter.Kind.HOME.kind) && filter.keywords.any {
|
// TODO shouldn't this be an exact match (only one keyword; exactly the hashtag)?
|
||||||
it.keyword == tag
|
filter.context.contains(Filter.Kind.HOME.kind) && filter.title == hashedTag
|
||||||
}
|
|
||||||
}
|
}
|
||||||
updateTagMuteState(mutedFilter != null)
|
updateTagMuteState(mutedFilter != null)
|
||||||
},
|
},
|
||||||
|
@ -189,7 +195,7 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
mastodonApi.getFiltersV1().fold(
|
mastodonApi.getFiltersV1().fold(
|
||||||
{ filters ->
|
{ filters ->
|
||||||
mutedFilterV1 = filters.firstOrNull { filter ->
|
mutedFilterV1 = filters.firstOrNull { filter ->
|
||||||
tag == filter.phrase && filter.context.contains(FilterV1.HOME)
|
hashedTag == filter.phrase && filter.context.contains(FilterV1.HOME)
|
||||||
}
|
}
|
||||||
updateTagMuteState(mutedFilterV1 != null)
|
updateTagMuteState(mutedFilterV1 != null)
|
||||||
},
|
},
|
||||||
|
@ -221,6 +227,9 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
val tag = hashtag ?: return true
|
val tag = hashtag ?: return true
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
|
var filterCreateSuccess = false
|
||||||
|
val hashedTag = "#$tag"
|
||||||
|
|
||||||
mastodonApi.createFilter(
|
mastodonApi.createFilter(
|
||||||
title = "#$tag",
|
title = "#$tag",
|
||||||
context = listOf(FilterV1.HOME),
|
context = listOf(FilterV1.HOME),
|
||||||
|
@ -228,10 +237,13 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
expiresInSeconds = null
|
expiresInSeconds = null
|
||||||
).fold(
|
).fold(
|
||||||
{ filter ->
|
{ filter ->
|
||||||
if (mastodonApi.addFilterKeyword(filterId = filter.id, keyword = tag, wholeWord = true).isSuccess) {
|
if (mastodonApi.addFilterKeyword(filterId = filter.id, keyword = hashedTag, wholeWord = true).isSuccess) {
|
||||||
mutedFilter = filter
|
// must be requested again; otherwise does not contain the keyword (but server does)
|
||||||
updateTagMuteState(true)
|
mutedFilter = mastodonApi.getFilter(filter.id).getOrNull()
|
||||||
|
|
||||||
|
// TODO the preference key here ("home") is not meaningful; should probably be another event if any
|
||||||
eventHub.dispatch(PreferenceChangedEvent(filter.context[0]))
|
eventHub.dispatch(PreferenceChangedEvent(filter.context[0]))
|
||||||
|
filterCreateSuccess = true
|
||||||
} else {
|
} else {
|
||||||
Snackbar.make(binding.root, getString(R.string.error_muting_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
|
Snackbar.make(binding.root, getString(R.string.error_muting_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
|
||||||
Log.e(TAG, "Failed to mute #$tag")
|
Log.e(TAG, "Failed to mute #$tag")
|
||||||
|
@ -240,7 +252,7 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
{ throwable ->
|
{ throwable ->
|
||||||
if (throwable is HttpException && throwable.code() == 404) {
|
if (throwable is HttpException && throwable.code() == 404) {
|
||||||
mastodonApi.createFilterV1(
|
mastodonApi.createFilterV1(
|
||||||
tag,
|
hashedTag,
|
||||||
listOf(FilterV1.HOME),
|
listOf(FilterV1.HOME),
|
||||||
irreversible = false,
|
irreversible = false,
|
||||||
wholeWord = true,
|
wholeWord = true,
|
||||||
|
@ -248,8 +260,8 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
).fold(
|
).fold(
|
||||||
{ filter ->
|
{ filter ->
|
||||||
mutedFilterV1 = filter
|
mutedFilterV1 = filter
|
||||||
updateTagMuteState(true)
|
|
||||||
eventHub.dispatch(PreferenceChangedEvent(filter.context[0]))
|
eventHub.dispatch(PreferenceChangedEvent(filter.context[0]))
|
||||||
|
filterCreateSuccess = true
|
||||||
},
|
},
|
||||||
{ throwable ->
|
{ throwable ->
|
||||||
Snackbar.make(binding.root, getString(R.string.error_muting_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
|
Snackbar.make(binding.root, getString(R.string.error_muting_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
|
||||||
|
@ -262,6 +274,24 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (filterCreateSuccess) {
|
||||||
|
updateTagMuteState(true)
|
||||||
|
Snackbar.make(binding.root, getString(R.string.muting_hashtag_success_format, tag), Snackbar.LENGTH_LONG).apply {
|
||||||
|
setAction(R.string.action_view_filter) {
|
||||||
|
val intent = if (mutedFilter != null) {
|
||||||
|
Intent(this@StatusListActivity, EditFilterActivity::class.java).apply {
|
||||||
|
putExtra(EditFilterActivity.FILTER_TO_EDIT, mutedFilter)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Intent(this@StatusListActivity, FiltersActivity::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
startActivityWithSlideInAnimation(intent)
|
||||||
|
}
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -307,6 +337,8 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
eventHub.dispatch(PreferenceChangedEvent(Filter.Kind.HOME.kind))
|
eventHub.dispatch(PreferenceChangedEvent(Filter.Kind.HOME.kind))
|
||||||
mutedFilterV1 = null
|
mutedFilterV1 = null
|
||||||
mutedFilter = null
|
mutedFilter = null
|
||||||
|
|
||||||
|
Snackbar.make(binding.root, getString(R.string.unmuting_hashtag_success_format, tag), Snackbar.LENGTH_SHORT).show()
|
||||||
},
|
},
|
||||||
{ throwable ->
|
{ throwable ->
|
||||||
Snackbar.make(binding.root, getString(R.string.error_unmuting_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
|
Snackbar.make(binding.root, getString(R.string.error_unmuting_hashtag_format, tag), Snackbar.LENGTH_SHORT).show()
|
||||||
|
|
|
@ -89,6 +89,11 @@ interface MastodonApi {
|
||||||
@GET("api/v1/filters")
|
@GET("api/v1/filters")
|
||||||
suspend fun getFiltersV1(): NetworkResult<List<FilterV1>>
|
suspend fun getFiltersV1(): NetworkResult<List<FilterV1>>
|
||||||
|
|
||||||
|
@GET("api/v2/filters/{filterId}")
|
||||||
|
suspend fun getFilter(
|
||||||
|
@Path("filterId") filterId: String
|
||||||
|
): NetworkResult<Filter>
|
||||||
|
|
||||||
@GET("api/v2/filters")
|
@GET("api/v2/filters")
|
||||||
suspend fun getFilters(): NetworkResult<List<Filter>>
|
suspend fun getFilters(): NetworkResult<List<Filter>>
|
||||||
|
|
||||||
|
|
|
@ -614,6 +614,12 @@
|
||||||
<string name="notifications_apply_filter">Filter notifications</string>
|
<string name="notifications_apply_filter">Filter notifications</string>
|
||||||
<string name="filter_apply">Apply</string>
|
<string name="filter_apply">Apply</string>
|
||||||
|
|
||||||
|
<string name="muting_hashtag_success_format">Muting hashtag #%s as a warning</string>
|
||||||
|
<string name="unmuting_hashtag_success_format">Unmuting hashtag #%s</string>
|
||||||
|
<string name="action_view_filter">View filter</string>
|
||||||
|
<string name="following_hashtag_success_format">Now following hashtag #%s</string>
|
||||||
|
<string name="unfollowing_hashtag_success_format">No longer following hashtag #%s</string>
|
||||||
|
|
||||||
<string name="compose_shortcut_long_label">Compose post</string>
|
<string name="compose_shortcut_long_label">Compose post</string>
|
||||||
<string name="compose_shortcut_short_label">Compose</string>
|
<string name="compose_shortcut_short_label">Compose</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue