feat: Edit a matching filter directly from the timeline (#819)

Previously, if a status was filtered with "WARN" and was shown in the
timeline with the name of the filter, and the user then decided to
change
that filter, they had to:

1. Open the left navigation menu
2. Navigate to "Account preferences"
3. Open "Filters"
4. Find the filter they want to edit, tap it
5. Make the change, and save
6. "Back" to the list of filters
7. "Back" to "Account preferences"
8. "Back" to the timeline

That's a lot of clicks for a simple action.

Change this. Now the filtered status includes an "Edit filter" button
that takes the user directly to step 5, and when they press "Back" they
return directly to the timeline.

To do this create a new filter action, `onEditFilterById`. Update the
listeners to launch `EditFilterActivity` if appropriate.

Modify `item_status_filtered.xml` to show the new button.

Update the accessibility delegate to show just the "Show anyway" and
"Edit filter" actions. Modify `FilterableStatusViewHolder` to expose
the information it needs to do this.
This commit is contained in:
Nik Clayton 2024-07-19 13:45:24 +02:00 committed by GitHub
parent 7ef692c2c8
commit 6b55d107c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 185 additions and 93 deletions

View File

@ -18,6 +18,7 @@
package app.pachli.adapter
import android.view.View
import androidx.core.text.HtmlCompat
import app.pachli.R
import app.pachli.core.data.model.StatusDisplayOptions
import app.pachli.core.network.model.Filter
@ -28,6 +29,8 @@ import app.pachli.viewdata.IStatusViewData
open class FilterableStatusViewHolder<T : IStatusViewData>(
private val binding: ItemStatusWrapperBinding,
) : StatusViewHolder<T>(binding.statusContainer, binding.root) {
/** The filter that matched the status, null if the status is not being filtered. */
var matchedFilter: Filter? = null
override fun setupWithStatus(
viewData: T,
@ -44,42 +47,38 @@ open class FilterableStatusViewHolder<T : IStatusViewData>(
listener: StatusActionListener<T>,
) {
if (status.filterAction !== Filter.Action.WARN) {
showFilteredPlaceholder(false)
matchedFilter = null
setPlaceholderVisibility(false)
return
}
// Shouldn't be necessary given the previous test against getFilterAction(),
// but guards against a possible NPE. See the TODO in StatusViewData.filterAction
// for more details.
val filterResults = status.actionable.filtered
if (filterResults.isNullOrEmpty()) {
showFilteredPlaceholder(false)
return
}
var matchedFilter: Filter? = null
for ((filter) in filterResults) {
if (filter.action === Filter.Action.WARN) {
matchedFilter = filter
break
}
}
status.actionable.filtered?.find { it.filter.action === Filter.Action.WARN }?.let { result ->
this.matchedFilter = result.filter
setPlaceholderVisibility(true)
// Guard against a possible NPE
if (matchedFilter == null) {
showFilteredPlaceholder(false)
return
}
showFilteredPlaceholder(true)
binding.statusFilteredPlaceholder.statusFilterLabel.text = context.getString(
val label = HtmlCompat.fromHtml(
context.getString(
R.string.status_filter_placeholder_label_format,
matchedFilter.title,
result.filter.title,
),
HtmlCompat.FROM_HTML_MODE_LEGACY,
)
binding.root.contentDescription = label
binding.statusFilteredPlaceholder.statusFilterLabel.text = label
binding.statusFilteredPlaceholder.statusFilterShowAnyway.setOnClickListener {
listener.clearWarningAction(status)
}
binding.statusFilteredPlaceholder.statusFilterEditFilter.setOnClickListener {
listener.onEditFilterById(result.filter.id)
}
} ?: {
matchedFilter = null
setPlaceholderVisibility(false)
}
}
private fun showFilteredPlaceholder(show: Boolean) {
private fun setPlaceholderVisibility(show: Boolean) {
binding.statusContainer.root.visibility = if (show) View.GONE else View.VISIBLE
binding.statusFilteredPlaceholder.root.visibility = if (show) View.VISIBLE else View.GONE
}

View File

@ -11,7 +11,6 @@ import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources
@ -100,7 +99,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(i
private val contentWarningDescription: TextView = itemView.findViewById(R.id.status_content_warning_description)
private val pollView: PollView = itemView.findViewById(R.id.status_poll)
private val cardView: PreviewCardView? = itemView.findViewById(R.id.status_card_view)
private val filteredPlaceholder: LinearLayout? = itemView.findViewById(R.id.status_filtered_placeholder)
private val filteredPlaceholder: ConstraintLayout? = itemView.findViewById(R.id.status_filtered_placeholder)
private val filteredPlaceholderLabel: TextView? = itemView.findViewById(R.id.status_filter_label)
private val filteredPlaceholderShowButton: Button? = itemView.findViewById(R.id.status_filter_show_anyway)
private val statusContainer: ConstraintLayout? = itemView.findViewById(R.id.status_container)

View File

@ -346,6 +346,9 @@ class ConversationsFragment :
override fun clearWarningAction(viewData: ConversationViewData) {
}
// Filters don't apply in conversations
override fun onEditFilterById(filterId: String) {}
override fun onReselect() {
if (isAdded) {
binding.recyclerView.layoutManager?.scrollToPosition(0)

View File

@ -49,11 +49,14 @@ import app.pachli.R
import app.pachli.adapter.StatusBaseViewHolder
import app.pachli.components.timeline.TimelineLoadStateAdapter
import app.pachli.core.activity.ReselectableFragment
import app.pachli.core.activity.extensions.TransitionKind
import app.pachli.core.activity.extensions.startActivityWithTransition
import app.pachli.core.activity.openLink
import app.pachli.core.common.extensions.hide
import app.pachli.core.common.extensions.show
import app.pachli.core.common.extensions.viewBinding
import app.pachli.core.navigation.AttachmentViewData.Companion.list
import app.pachli.core.navigation.EditFilterActivityIntent
import app.pachli.core.network.model.Filter
import app.pachli.core.network.model.Notification
import app.pachli.core.network.model.Poll
@ -589,6 +592,13 @@ class NotificationsFragment :
}
}
override fun onEditFilterById(filterId: String) {
requireActivity().startActivityWithTransition(
EditFilterActivityIntent.edit(requireContext(), filterId),
TransitionKind.SLIDE_FROM_END,
)
}
override fun onNotificationContentCollapsedChange(
isCollapsed: Boolean,
viewData: NotificationViewData,

View File

@ -40,13 +40,16 @@ import app.pachli.R
import app.pachli.components.search.adapter.SearchStatusesAdapter
import app.pachli.core.activity.AccountSelectionListener
import app.pachli.core.activity.BaseActivity
import app.pachli.core.activity.extensions.TransitionKind
import app.pachli.core.activity.extensions.startActivityWithDefaultTransition
import app.pachli.core.activity.extensions.startActivityWithTransition
import app.pachli.core.activity.openLink
import app.pachli.core.data.repository.StatusDisplayOptionsRepository
import app.pachli.core.database.model.AccountEntity
import app.pachli.core.navigation.AttachmentViewData
import app.pachli.core.navigation.ComposeActivityIntent
import app.pachli.core.navigation.ComposeActivityIntent.ComposeOptions
import app.pachli.core.navigation.EditFilterActivityIntent
import app.pachli.core.navigation.ReportActivityIntent
import app.pachli.core.navigation.ViewMediaActivityIntent
import app.pachli.core.network.model.Attachment
@ -162,6 +165,13 @@ class SearchStatusesFragment : SearchFragment<StatusViewData>(), StatusActionLis
viewModel.reblog(viewData, reblog)
}
override fun onEditFilterById(filterId: String) {
requireActivity().startActivityWithTransition(
EditFilterActivityIntent.edit(requireContext(), filterId),
TransitionKind.SLIDE_FROM_END,
)
}
companion object {
fun newInstance() = SearchStatusesFragment()
}

View File

@ -51,7 +51,9 @@ import app.pachli.components.timeline.viewmodel.TimelineViewModel
import app.pachli.components.timeline.viewmodel.UiSuccess
import app.pachli.core.activity.RefreshableFragment
import app.pachli.core.activity.ReselectableFragment
import app.pachli.core.activity.extensions.TransitionKind
import app.pachli.core.activity.extensions.startActivityWithDefaultTransition
import app.pachli.core.activity.extensions.startActivityWithTransition
import app.pachli.core.common.extensions.hide
import app.pachli.core.common.extensions.show
import app.pachli.core.common.extensions.viewBinding
@ -59,6 +61,7 @@ import app.pachli.core.database.model.TranslationState
import app.pachli.core.model.Timeline
import app.pachli.core.navigation.AccountListActivityIntent
import app.pachli.core.navigation.AttachmentViewData
import app.pachli.core.navigation.EditFilterActivityIntent
import app.pachli.core.network.model.Poll
import app.pachli.core.network.model.Status
import app.pachli.core.ui.ActionButtonScrollListener
@ -615,6 +618,13 @@ class TimelineFragment :
viewModel.clearWarning(viewData)
}
override fun onEditFilterById(filterId: String) {
requireActivity().startActivityWithTransition(
EditFilterActivityIntent.edit(requireContext(), filterId),
TransitionKind.SLIDE_FROM_END,
)
}
override fun onMore(view: View, viewData: StatusViewData) {
super.more(view, viewData)
}

View File

@ -33,7 +33,9 @@ import androidx.recyclerview.widget.SimpleItemAnimator
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
import app.pachli.R
import app.pachli.components.viewthread.edits.ViewEditsFragment
import app.pachli.core.activity.extensions.TransitionKind
import app.pachli.core.activity.extensions.startActivityWithDefaultTransition
import app.pachli.core.activity.extensions.startActivityWithTransition
import app.pachli.core.activity.openLink
import app.pachli.core.common.extensions.hide
import app.pachli.core.common.extensions.show
@ -41,6 +43,7 @@ import app.pachli.core.common.extensions.viewBinding
import app.pachli.core.designsystem.R as DR
import app.pachli.core.navigation.AccountListActivityIntent
import app.pachli.core.navigation.AttachmentViewData.Companion.list
import app.pachli.core.navigation.EditFilterActivityIntent
import app.pachli.core.network.model.Poll
import app.pachli.core.network.model.Status
import app.pachli.core.ui.extensions.getErrorString
@ -323,6 +326,13 @@ class ViewThreadFragment :
// there are no reblogs in threads
}
override fun onEditFilterById(filterId: String) {
requireActivity().startActivityWithTransition(
EditFilterActivityIntent.edit(requireContext(), filterId),
TransitionKind.SLIDE_FROM_END,
)
}
override fun onExpandedChange(viewData: StatusViewData, expanded: Boolean) {
viewModel.changeExpanded(expanded, viewData)
}

View File

@ -59,4 +59,7 @@ interface StatusActionListener<T : IStatusViewData> : LinkListener {
fun onVoteInPoll(viewData: T, poll: Poll, choices: List<Int>)
fun onShowEdits(statusId: String) {}
fun clearWarningAction(viewData: T)
/** Edit the filter that matched this status. */
fun onEditFilterById(filterId: String)
}

View File

@ -15,6 +15,7 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.Accessibilit
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate
import app.pachli.R
import app.pachli.adapter.FilterableStatusViewHolder
import app.pachli.adapter.StatusBaseViewHolder
import app.pachli.core.activity.openLink
import app.pachli.core.network.model.Status.Companion.MAX_MEDIA_ATTACHMENTS
@ -48,6 +49,13 @@ class ListStatusAccessibilityDelegate<T : IStatusViewData>(
) {
super.onInitializeAccessibilityNodeInfo(host, info)
val viewHolder = recyclerView.findContainingViewHolder(host)
if (viewHolder is FilterableStatusViewHolder<*> && viewHolder.matchedFilter != null) {
info.addAction(showAnywayAction)
info.addAction(editFilterAction)
return
}
val pos = recyclerView.getChildAdapterPosition(host)
val status = statusProvider.getStatus(pos) ?: return
@ -183,6 +191,14 @@ class ListStatusAccessibilityDelegate<T : IStatusViewData>(
app.pachli.core.ui.R.id.action_more -> {
statusActionListener.onMore(host, status)
}
app.pachli.core.ui.R.id.action_show_anyway -> statusActionListener.clearWarningAction(status)
app.pachli.core.ui.R.id.action_edit_filter -> {
(recyclerView.findContainingViewHolder(host) as? FilterableStatusViewHolder<*>)?.matchedFilter?.let {
statusActionListener.onEditFilterById(it.id)
return@let true
} ?: false
}
else -> return super.performAccessibilityAction(host, action, args)
}
return true
@ -378,5 +394,15 @@ class ListStatusAccessibilityDelegate<T : IStatusViewData>(
context.getString(app.pachli.core.ui.R.string.action_more),
)
private val showAnywayAction = AccessibilityActionCompat(
app.pachli.core.ui.R.id.action_show_anyway,
context.getString(R.string.status_filtered_show_anyway),
)
private val editFilterAction = AccessibilityActionCompat(
app.pachli.core.ui.R.id.action_edit_filter,
context.getString(R.string.filter_edit_title),
)
private data class LinkSpanInfo(val text: String, val link: String)
}

View File

@ -1,33 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/status_filtered_placeholder"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content"
android:paddingStart="14dp"
android:paddingEnd="14dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:minHeight="48dp">
<TextView
android:id="@+id/status_filter_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
android:layout_marginBottom="0dp"
android:textColor="?android:textColorTertiary"
android:textSize="?attr/status_text_medium"
android:textAlignment="center"
android:textIsSelectable="false"
tools:text="Filter: MyFilter"
/>
tools:text="Filter: MyFilter" />
<Button
android:id="@+id/status_filter_edit_filter"
style="@style/AppButton.TextButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:text="@string/filter_edit_title"
android:textSize="?attr/status_text_medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/status_filter_show_anyway"
app:layout_constraintTop_toTopOf="@+id/status_filter_show_anyway" />
<Button
android:id="@+id/status_filter_show_anyway"
android:layout_width="match_parent"
style="@style/AppButton.Outlined"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
style="@style/AppButton.TextButton"
android:textStyle="bold"
android:textSize="?attr/status_text_medium"
android:importantForAccessibility="no"
android:layout_marginTop="8dp"
android:text="@string/status_filtered_show_anyway"
/>
</LinearLayout>
android:textSize="?attr/status_text_medium"
app:layout_constraintStart_toEndOf="@id/status_filter_edit_filter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/status_filter_label" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -587,7 +587,7 @@
<string name="filter_action_warn">تحذير</string>
<string name="title_public_trending_links">الروابط الشائعة</string>
<string name="title_tab_public_trending_links">الروابط</string>
<string name="status_filter_placeholder_label_format">مُصفّى: %s</string>
<string name="status_filter_placeholder_label_format">مُصفّى: &lt;b>%1$s&lt;/b></string>
<string name="update_dialog_neutral">لا تذكرني بهذه النسخة</string>
<string name="ui_error_reject_follow_request">فشل رفض طلب المتابعة: %s</string>
<string name="reaction_name_and_count">%1$s %2$d</string>

View File

@ -551,7 +551,7 @@
<string name="description_login">Працуе амаль заўсёды. Даныя не ўцякаюць у іншыя праграмы.</string>
<string name="notification_unknown_name">Невядома</string>
<string name="status_filtered_show_anyway">Усё роўна паказаць</string>
<string name="status_filter_placeholder_label_format">Адфільтрована: %s</string>
<string name="status_filter_placeholder_label_format">Адфільтрована: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Профілі</string>
<string name="title_public_trending_hashtags">Папулярныя хэштэгі</string>
<string name="description_browser_login">Можа падтрымліваць дадатковыя метады праверкі сапраўднасці, але для гэтага патрэбны адпаведны браузер.</string>

View File

@ -537,7 +537,7 @@
<string name="dialog_follow_hashtag_title">Segueix hashtag</string>
<string name="dialog_follow_hashtag_hint">#hashtag</string>
<string name="notification_unknown_name">Desconegut</string>
<string name="status_filter_placeholder_label_format">Filtrat: %s</string>
<string name="status_filter_placeholder_label_format">Filtrat: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Perfils</string>
<string name="status_filtered_show_anyway">Mostra de totes maneres</string>
<string name="socket_timeout_exception">El contacte amb el teu servidor ha trigat massa</string>

View File

@ -585,7 +585,7 @@
<string name="dialog_follow_hashtag_hint">#hashnod</string>
<string name="notification_unknown_name">Anhysbys</string>
<string name="status_filtered_show_anyway">Dangos beth bynnag</string>
<string name="status_filter_placeholder_label_format">Hidlwyd: %s</string>
<string name="status_filter_placeholder_label_format">Hidlwyd: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Proffiliau</string>
<string name="socket_timeout_exception">Cymrodd hi\'n rhy hir i gysylltu â\'ch gweinydd</string>
<string name="ui_error_bookmark_fmt">Methodd tudalnodi\'r neges: %1$s</string>

View File

@ -554,7 +554,7 @@
<string name="notification_unknown_name">Unbekannt</string>
<string name="ui_error_clear_notifications">Löschen der Benachrichtigungen schlug fehl: %s</string>
<string name="ui_error_reject_follow_request">Ablehnen der Folgeanfrage schlug fehl: %s</string>
<string name="status_filter_placeholder_label_format">Gefiltert: %s</string>
<string name="status_filter_placeholder_label_format">Gefiltert: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Profile</string>
<string name="hint_filter_title">Mein Filter</string>
<string name="label_filter_title">Titel</string>

View File

@ -554,7 +554,7 @@
<string name="pref_title_account_filter_keywords">Perfiles</string>
<string name="notification_unknown_name">Desconocido</string>
<string name="status_filtered_show_anyway">Mostrar de todas formas</string>
<string name="status_filter_placeholder_label_format">Filtrado: %s</string>
<string name="status_filter_placeholder_label_format">Filtrado: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_show_stat_inline">Mostrar estadísticas de la entrada en la línea de tiempo</string>
<string name="socket_timeout_exception">Contactar con tu servidor ha tardado demasiado tiempo</string>
<string name="select_list_empty">Todavía no tienes listas</string>

View File

@ -551,7 +551,7 @@
<string name="ui_error_reblog_fmt">%1$s: تقویت فرسته شکست خورد</string>
<string name="ui_error_reject_follow_request">رد کردن درخواست پی‌گیری شکست خورد: %s</string>
<string name="status_filtered_show_anyway">نمایش به هر روی</string>
<string name="status_filter_placeholder_label_format">پالوده: %s</string>
<string name="status_filter_placeholder_label_format">پالوده: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">نمایه‌ها</string>
<string name="hint_filter_title">پالایه‌ام</string>
<string name="label_filter_title">عنوان</string>

View File

@ -364,7 +364,7 @@
<string name="send_post_notification_error_title">Julkaisun lähettäminen epäonnistui</string>
<string name="pref_title_notification_filter_follow_requests">seuraamista pyydetty</string>
<string name="pref_title_notification_filters">Ilmoita kun</string>
<string name="status_filter_placeholder_label_format">Suodatettu: %s</string>
<string name="status_filter_placeholder_label_format">Suodatettu: &lt;b>%1$s&lt;/b></string>
<string name="pref_main_nav_position_option_bottom">Alareuna</string>
<string name="pref_title_notification_filter_poll">päättyneet äänestykset</string>
<string name="abbreviated_in_seconds">%ds</string>

View File

@ -528,7 +528,7 @@
<string name="pref_title_notification_filter_reports">il y a un nouveau signalement</string>
<string name="pref_title_account_filter_keywords">Profils</string>
<string name="status_filtered_show_anyway">Montrer quand même</string>
<string name="status_filter_placeholder_label_format">Caché : %s</string>
<string name="status_filter_placeholder_label_format">Caché : &lt;b>%1$s&lt;/b></string>
<string name="title_public_trending_hashtags">Hashtags tendance</string>
<string name="send_account_username_to">Partager le nom du compte avec…</string>
<string name="status_created_at_now">maintenant</string>

View File

@ -569,7 +569,7 @@
<string name="select_list_empty">Chan eil liosta agad fhathast</string>
<string name="error_list_load">Mearachd a luchdadh nan liostaichean</string>
<string name="status_filtered_show_anyway">Seall e co-dhiù</string>
<string name="status_filter_placeholder_label_format">Criathraichte: %s</string>
<string name="status_filter_placeholder_label_format">Criathraichte: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Pròifilean</string>
<string name="hint_filter_title">A chriathrag agam</string>
<string name="filter_description_warn">Falaich le rabhadh</string>

View File

@ -550,7 +550,7 @@
<string name="ui_success_accepted_follow_request">Aceptado o seguimento</string>
<string name="ui_success_rejected_follow_request">Bloqueada a solicitude de seguimento</string>
<string name="status_filtered_show_anyway">Mostrar igualmente</string>
<string name="status_filter_placeholder_label_format">Filtrado: %s</string>
<string name="status_filter_placeholder_label_format">Filtrado: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Perfís</string>
<string name="label_filter_title">Título</string>
<string name="filter_action_warn">Aviso</string>

View File

@ -545,7 +545,7 @@
<string name="ui_error_vote_fmt">Szavazat leadása a szavazásba sikertelen: %1$s</string>
<string name="ui_error_accept_follow_request">Követési kérelem elfogadása sikertelen: %s</string>
<string name="status_filtered_show_anyway">Mutatás mindenképpen</string>
<string name="status_filter_placeholder_label_format">Szűrve: %s</string>
<string name="status_filter_placeholder_label_format">Szűrve: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Profil</string>
<string name="socket_timeout_exception">A kapcsolatfelvétel a kiszolgálóddal túl sokáig tartott</string>
<string name="ui_error_bookmark_fmt">Bejegyzés könyvjelzőzése sikertelen: %1$s</string>

View File

@ -534,7 +534,7 @@
<string name="dialog_follow_hashtag_hint">#myllumerki</string>
<string name="notification_unknown_name">Óþekkt</string>
<string name="status_filtered_show_anyway">Birta samt</string>
<string name="status_filter_placeholder_label_format">Síað: %s</string>
<string name="status_filter_placeholder_label_format">Síað: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Notendasnið</string>
<string name="pref_title_show_stat_inline">Sýna tölfræði færslu í tímalínu</string>
<string name="ui_error_favourite_fmt">Mistókst að setja færslu í eftirlæti: %1$s</string>

View File

@ -593,7 +593,7 @@
<string name="select_list_manage">Gestisci liste</string>
<string name="error_list_load">Errore nel caricamento delle liste</string>
<string name="status_filtered_show_anyway">Mostra comunque</string>
<string name="status_filter_placeholder_label_format">Filtrato: %s</string>
<string name="status_filter_placeholder_label_format">Filtrato: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Profili</string>
<string name="hint_filter_title">I miei filtri</string>
<string name="action_add">Aggiungi</string>

View File

@ -595,7 +595,7 @@
<string name="pref_title_font_family">フォント</string>
<string name="description_poll">選択肢付きの投票: %1$s, %2$s, %3$s, %4$s; %5$s</string>
<string name="label_image">画像</string>
<string name="status_filter_placeholder_label_format">フィルタ済み: %s</string>
<string name="status_filter_placeholder_label_format">フィルタ済み: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_show_self_boosts_description">自分の投稿をブーストすること</string>
<string name="confirmation_hashtag_unmuted">%s を非表示にしました</string>
<string name="pref_title_show_self_boosts">セルフブーストを表示</string>

View File

@ -564,7 +564,7 @@
<string name="account_username_copied">Brukernavn kopiert</string>
<string name="error_status_source_load">Kunne ikke laste status fra tjeneren.</string>
<string name="status_filtered_show_anyway">Vis allikevel</string>
<string name="status_filter_placeholder_label_format">Filtrert: %s</string>
<string name="status_filter_placeholder_label_format">Filtrert: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Profiler</string>
<string name="action_add">Legg til</string>
<string name="filter_keyword_display_format">%s (helt ord)</string>

View File

@ -543,7 +543,7 @@
<string name="select_list_manage">Lijsten beheren</string>
<string name="pref_title_account_filter_keywords">Profielen</string>
<string name="status_filtered_show_anyway">Toch tonen</string>
<string name="status_filter_placeholder_label_format">Gefilterd: %s</string>
<string name="status_filter_placeholder_label_format">Gefilterd: &lt;b>%1$s&lt;/b></string>
<string name="hint_filter_title">Mijn filter</string>
<string name="label_filter_action">Filteractie</string>
<string name="filter_action_warn">Waarschuwen</string>

View File

@ -546,7 +546,7 @@
<string name="ui_success_accepted_follow_request">Demanda dabonament acceptada</string>
<string name="ui_success_rejected_follow_request">Demanda dabonament blocada</string>
<string name="status_filtered_show_anyway">Afichar ça que la</string>
<string name="status_filter_placeholder_label_format">Filtrat : %s</string>
<string name="status_filter_placeholder_label_format">Filtrat : &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Perfils</string>
<string name="hint_filter_title">Mon filtre</string>
<string name="label_filter_title">Títol</string>

View File

@ -531,7 +531,7 @@
<string name="title_public_trending_links">URL em alta</string>
<string name="title_tab_public_trending_links">URL</string>
<string name="title_public_trending_hashtags">Hashtags em alta</string>
<string name="status_filter_placeholder_label_format">Filtrado(s): %s</string>
<string name="status_filter_placeholder_label_format">Filtrado(s): &lt;b>%1$s&lt;/b></string>
<string name="confirmation_hashtag_unfollowed">#%s deixado de seguir</string>
<string name="ui_error_vote_fmt">Votar na enquete falhou: %1$s</string>
<string name="update_dialog_neutral">Não me lembre desta versão</string>

View File

@ -556,7 +556,7 @@
<string name="select_list_manage">Hantera listor</string>
<string name="select_list_empty">Du har inga listor, än</string>
<string name="status_filtered_show_anyway">Visa allafall</string>
<string name="status_filter_placeholder_label_format">Filtrerad: %s</string>
<string name="status_filter_placeholder_label_format">Filtrerad: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Profiler</string>
<string name="label_filter_action">Filteråtgärd</string>
<string name="label_filter_keywords">Nyckelord eller fraser att filtrera</string>

View File

@ -568,7 +568,7 @@
<string name="filter_action_hide">Gizle</string>
<string name="filter_description_warn">Bir uyarı ile gizle</string>
<string name="status_filtered_show_anyway">Yine de göster</string>
<string name="status_filter_placeholder_label_format">Süzgeçlendi: %s</string>
<string name="status_filter_placeholder_label_format">Süzgeçlendi: &lt;b>%1$s&lt;/b></string>
<string name="filter_edit_keyword_title">Anahtar kelimeyi düzenle</string>
<string name="filter_description_format">%s: %s</string>
<string name="pref_title_show_stat_inline">Gönderi istatistiklerini sğ akışında göster</string>

View File

@ -566,7 +566,7 @@
<string name="ui_success_accepted_follow_request">Запит на стеження погоджено</string>
<string name="ui_success_rejected_follow_request">Запит на стеження заблоковано</string>
<string name="status_filtered_show_anyway">Усе одно показати</string>
<string name="status_filter_placeholder_label_format">Відфільтровано: %s</string>
<string name="status_filter_placeholder_label_format">Відфільтровано: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Профілі</string>
<string name="label_filter_title">Заголовок</string>
<string name="filter_action_warn">Попередження</string>

View File

@ -534,7 +534,7 @@
<string name="ui_success_accepted_follow_request">Đã chấp nhận yêu cầu theo dõi</string>
<string name="ui_success_rejected_follow_request">Đã từ chối yêu cầu theo dõi</string>
<string name="status_filtered_show_anyway">Vẫn hiện</string>
<string name="status_filter_placeholder_label_format">Đã lọc: %s</string>
<string name="status_filter_placeholder_label_format">Đã lọc: &lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">Người</string>
<string name="hint_filter_title">Bộ lọc của tôi</string>
<string name="label_filter_title">Tên bộ lọc</string>

View File

@ -548,7 +548,7 @@
<string name="ui_success_accepted_follow_request">关注请求被接受</string>
<string name="ui_success_rejected_follow_request">关注请求被拦截</string>
<string name="status_filtered_show_anyway">仍要显示</string>
<string name="status_filter_placeholder_label_format">已过滤:%s</string>
<string name="status_filter_placeholder_label_format">已过滤:&lt;b>%1$s&lt;/b></string>
<string name="pref_title_account_filter_keywords">个人资料</string>
<string name="hint_filter_title">我的筛选器</string>
<string name="label_filter_title">标题</string>

View File

@ -357,7 +357,7 @@
<string name="status_count_one_plus">1+</string>
<string name="status_created_at_now">now</string>
<string name="status_filtered_show_anyway">Show anyway</string>
<string name="status_filter_placeholder_label_format">Filtered: %s</string>
<string name="status_filter_placeholder_label_format">Filtered: &lt;b>%1$s&lt;/b></string>
<string name="state_follow_requested">Follow requested</string>
<!--These are for timestamps on posts. For example: "16s" or "2d"-->
<string name="abbreviated_in_years">in %dy</string>

View File

@ -49,4 +49,7 @@
<item name="action_dismiss_follow_suggestion" type="id" />
<item name="action_follow_account" type="id" />
<item name="action_show_anyway" type="id" />
<item name="action_edit_filter" type="id" />
</resources>