Merge branch 'develop' into prompt_to_save_before_leaving_changed_profile

This commit is contained in:
Martin Marconcini 2023-08-22 13:06:27 +02:00 committed by GitHub
commit 84915e6af5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
77 changed files with 1641 additions and 727 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -256,9 +256,8 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab
public void openAsAccount(@NonNull String url, @NonNull AccountEntity account) { public void openAsAccount(@NonNull String url, @NonNull AccountEntity account) {
accountManager.setActiveAccount(account.getId()); accountManager.setActiveAccount(account.getId());
Intent intent = new Intent(this, MainActivity.class); Intent intent = MainActivity.redirectIntent(this, account.getId(), url);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra(MainActivity.REDIRECT_URL, url);
startActivity(intent); startActivity(intent);
finishWithoutSlideOutAnimation(); finishWithoutSlideOutAnimation();
} }

View File

@ -16,6 +16,8 @@
package com.keylesspalace.tusky package com.keylesspalace.tusky
import android.Manifest import android.Manifest
import android.annotation.SuppressLint
import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent import android.content.Intent
@ -33,6 +35,7 @@ import android.view.KeyEvent
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.MenuItem.SHOW_AS_ACTION_NEVER
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
@ -41,9 +44,12 @@ import androidx.appcompat.content.res.AppCompatResources
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.IntentCompat
import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.view.GravityCompat import androidx.core.view.GravityCompat
import androidx.core.view.MenuProvider import androidx.core.view.MenuProvider
import androidx.core.view.forEach
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.viewpager2.widget.MarginPageTransformer import androidx.viewpager2.widget.MarginPageTransformer
@ -100,7 +106,6 @@ import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.unsafeLazy import com.keylesspalace.tusky.util.unsafeLazy
import com.keylesspalace.tusky.util.updateShortcut import com.keylesspalace.tusky.util.updateShortcut
import com.keylesspalace.tusky.util.viewBinding import com.keylesspalace.tusky.util.viewBinding
import com.keylesspalace.tusky.util.visible
import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.colorInt
@ -175,6 +180,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
/** Adapter for the different timeline tabs */ /** Adapter for the different timeline tabs */
private lateinit var tabAdapter: MainPagerAdapter private lateinit var tabAdapter: MainPagerAdapter
@SuppressLint("RestrictedApi")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -182,30 +188,39 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
?: return // will be redirected to LoginActivity by BaseActivity ?: return // will be redirected to LoginActivity by BaseActivity
var showNotificationTab = false var showNotificationTab = false
if (intent != null) {
// check for savedInstanceState in order to not handle intent events more than once
if (intent != null && savedInstanceState == null) {
val notificationId = intent.getIntExtra(NOTIFICATION_ID, -1)
if (notificationId != -1) {
// opened from a notification action, cancel the notification
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(intent.getStringExtra(NOTIFICATION_TAG), notificationId)
}
/** there are two possibilities the accountId can be passed to MainActivity: /** there are two possibilities the accountId can be passed to MainActivity:
* - from our code as long 'account_id' * - from our code as Long Intent Extra TUSKY_ACCOUNT_ID
* - from share shortcuts as String 'android.intent.extra.shortcut.ID' * - from share shortcuts as String 'android.intent.extra.shortcut.ID'
*/ */
var accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1) var tuskyAccountId = intent.getLongExtra(TUSKY_ACCOUNT_ID, -1)
if (accountId == -1L) { if (tuskyAccountId == -1L) {
val accountIdString = intent.getStringExtra(ShortcutManagerCompat.EXTRA_SHORTCUT_ID) val accountIdString = intent.getStringExtra(ShortcutManagerCompat.EXTRA_SHORTCUT_ID)
if (accountIdString != null) { if (accountIdString != null) {
accountId = accountIdString.toLong() tuskyAccountId = accountIdString.toLong()
} }
} }
val accountRequested = accountId != -1L val accountRequested = tuskyAccountId != -1L
if (accountRequested && accountId != activeAccount.id) { if (accountRequested && tuskyAccountId != activeAccount.id) {
accountManager.setActiveAccount(accountId) accountManager.setActiveAccount(tuskyAccountId)
} }
val openDrafts = intent.getBooleanExtra(OPEN_DRAFTS, false) val openDrafts = intent.getBooleanExtra(OPEN_DRAFTS, false)
if (canHandleMimeType(intent.type)) { if (canHandleMimeType(intent.type) || intent.hasExtra(COMPOSE_OPTIONS)) {
// Sharing to Tusky from an external app // Sharing to Tusky from an external app
if (accountRequested) { if (accountRequested) {
// The correct account is already active // The correct account is already active
forwardShare(intent) forwardToComposeActivity(intent)
} else { } else {
// No account was provided, show the chooser // No account was provided, show the chooser
showAccountChooserDialog( showAccountChooserDialog(
@ -216,10 +231,10 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
val requestedId = account.id val requestedId = account.id
if (requestedId == activeAccount.id) { if (requestedId == activeAccount.id) {
// The correct account is already active // The correct account is already active
forwardShare(intent) forwardToComposeActivity(intent)
} else { } else {
// A different account was requested, restart the activity // A different account was requested, restart the activity
intent.putExtra(NotificationHelper.ACCOUNT_ID, requestedId) intent.putExtra(TUSKY_ACCOUNT_ID, requestedId)
changeAccount(requestedId, intent) changeAccount(requestedId, intent)
} }
} }
@ -229,10 +244,10 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
} else if (openDrafts) { } else if (openDrafts) {
val intent = DraftsActivity.newIntent(this) val intent = DraftsActivity.newIntent(this)
startActivity(intent) startActivity(intent)
} else if (accountRequested && savedInstanceState == null) { } else if (accountRequested && intent.hasExtra(NOTIFICATION_TYPE)) {
// user clicked a notification, show follow requests for type FOLLOW_REQUEST, // user clicked a notification, show follow requests for type FOLLOW_REQUEST,
// otherwise show notification tab // otherwise show notification tab
if (intent.getStringExtra(NotificationHelper.TYPE) == Notification.Type.FOLLOW_REQUEST.name) { if (intent.getSerializableExtra(NOTIFICATION_TYPE) == Notification.Type.FOLLOW_REQUEST) {
val intent = AccountListActivity.newIntent(this, AccountListActivity.Type.FOLLOW_REQUESTS) val intent = AccountListActivity.newIntent(this, AccountListActivity.Type.FOLLOW_REQUESTS)
startActivityWithSlideInAnimation(intent) startActivityWithSlideInAnimation(intent)
} else { } else {
@ -242,7 +257,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
} }
window.statusBarColor = Color.TRANSPARENT // don't draw a status bar, the DrawerLayout and the MaterialDrawerLayout have their own window.statusBarColor = Color.TRANSPARENT // don't draw a status bar, the DrawerLayout and the MaterialDrawerLayout have their own
setContentView(binding.root) setContentView(binding.root)
setSupportActionBar(binding.mainToolbar)
glide = Glide.with(this) glide = Glide.with(this)
@ -251,8 +265,21 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
startActivity(composeIntent) startActivity(composeIntent)
} }
// Determine which of the three toolbars should be the supportActionBar (which hosts
// the options menu).
val hideTopToolbar = preferences.getBoolean(PrefKeys.HIDE_TOP_TOOLBAR, false) val hideTopToolbar = preferences.getBoolean(PrefKeys.HIDE_TOP_TOOLBAR, false)
binding.mainToolbar.visible(!hideTopToolbar) if (hideTopToolbar) {
when (preferences.getString(PrefKeys.MAIN_NAV_POSITION, "top")) {
"top" -> setSupportActionBar(binding.topNav)
"bottom" -> setSupportActionBar(binding.bottomNav)
}
binding.mainToolbar.hide()
// There's not enough space in the top/bottom bars to show the title as well.
supportActionBar?.setDisplayShowTitleEnabled(false)
} else {
setSupportActionBar(binding.mainToolbar)
binding.mainToolbar.show()
}
loadDrawerAvatar(activeAccount.profilePictureUrl, true) loadDrawerAvatar(activeAccount.profilePictureUrl, true)
@ -263,7 +290,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
setupDrawer( setupDrawer(
savedInstanceState, savedInstanceState,
addSearchButton = hideTopToolbar, addSearchButton = hideTopToolbar,
addTrendingButton = !accountManager.activeAccount!!.tabPreferences.hasTab(TRENDING) addTrendingTagsButton = !accountManager.activeAccount!!.tabPreferences.hasTab(TRENDING_TAGS)
) )
/* Fetch user info while we're doing other things. This has to be done after setting up the /* Fetch user info while we're doing other things. This has to be done after setting up the
@ -288,7 +315,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
is MainTabsChangedEvent -> { is MainTabsChangedEvent -> {
refreshMainDrawerItems( refreshMainDrawerItems(
addSearchButton = hideTopToolbar, addSearchButton = hideTopToolbar,
addTrendingButton = !event.newTabs.hasTab(TRENDING) addTrendingTagsButton = !event.newTabs.hasTab(TRENDING_TAGS)
) )
setupTabs(false) setupTabs(false)
@ -350,6 +377,14 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
} }
} }
override fun onPrepareMenu(menu: Menu) {
super.onPrepareMenu(menu)
// If the main toolbar is hidden then there's no space in the top/bottomNav to show
// the menu items as icons, so forceably disable them
if (!binding.mainToolbar.isVisible) menu.forEach { it.setShowAsAction(SHOW_AS_ACTION_NEVER) }
}
override fun onMenuItemSelected(item: MenuItem): Boolean { override fun onMenuItemSelected(item: MenuItem): Boolean {
return when (item.itemId) { return when (item.itemId) {
R.id.action_search -> { R.id.action_search -> {
@ -422,12 +457,19 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
} }
} }
private fun forwardShare(intent: Intent) { private fun forwardToComposeActivity(intent: Intent) {
val composeIntent = Intent(this, ComposeActivity::class.java) val composeOptions = IntentCompat.getParcelableExtra(intent, COMPOSE_OPTIONS, ComposeActivity.ComposeOptions::class.java)
composeIntent.action = intent.action
composeIntent.type = intent.type val composeIntent = if (composeOptions != null) {
composeIntent.putExtras(intent) ComposeActivity.startIntent(this, composeOptions)
composeIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } else {
Intent(this, ComposeActivity::class.java).apply {
action = intent.action
type = intent.type
putExtras(intent)
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
}
startActivity(composeIntent) startActivity(composeIntent)
finish() finish()
} }
@ -435,13 +477,13 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
private fun setupDrawer( private fun setupDrawer(
savedInstanceState: Bundle?, savedInstanceState: Bundle?,
addSearchButton: Boolean, addSearchButton: Boolean,
addTrendingButton: Boolean addTrendingTagsButton: Boolean
) { ) {
val drawerOpenClickListener = View.OnClickListener { binding.mainDrawerLayout.open() } val drawerOpenClickListener = View.OnClickListener { binding.mainDrawerLayout.open() }
binding.mainToolbar.setNavigationOnClickListener(drawerOpenClickListener) binding.mainToolbar.setNavigationOnClickListener(drawerOpenClickListener)
binding.topNavAvatar.setOnClickListener(drawerOpenClickListener) binding.topNav.setNavigationOnClickListener(drawerOpenClickListener)
binding.bottomNavAvatar.setOnClickListener(drawerOpenClickListener) binding.bottomNav.setNavigationOnClickListener(drawerOpenClickListener)
header = AccountHeaderView(this).apply { header = AccountHeaderView(this).apply {
headerBackgroundScaleType = ImageView.ScaleType.CENTER_CROP headerBackgroundScaleType = ImageView.ScaleType.CENTER_CROP
@ -496,12 +538,12 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
}) })
binding.mainDrawer.apply { binding.mainDrawer.apply {
refreshMainDrawerItems(addSearchButton, addTrendingButton) refreshMainDrawerItems(addSearchButton, addTrendingTagsButton)
setSavedInstance(savedInstanceState) setSavedInstance(savedInstanceState)
} }
} }
private fun refreshMainDrawerItems(addSearchButton: Boolean, addTrendingButton: Boolean) { private fun refreshMainDrawerItems(addSearchButton: Boolean, addTrendingTagsButton: Boolean) {
binding.mainDrawer.apply { binding.mainDrawer.apply {
itemAdapter.clear() itemAdapter.clear()
tintStatusBar = true tintStatusBar = true
@ -618,7 +660,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
) )
} }
if (addTrendingButton) { if (addTrendingTagsButton) {
binding.mainDrawer.addItemsAtPosition( binding.mainDrawer.addItemsAtPosition(
5, 5,
primaryDrawerItem { primaryDrawerItem {
@ -876,112 +918,75 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
val hideTopToolbar = preferences.getBoolean(PrefKeys.HIDE_TOP_TOOLBAR, false) val hideTopToolbar = preferences.getBoolean(PrefKeys.HIDE_TOP_TOOLBAR, false)
val animateAvatars = preferences.getBoolean("animateGifAvatars", false) val animateAvatars = preferences.getBoolean("animateGifAvatars", false)
if (hideTopToolbar) { val activeToolbar = if (hideTopToolbar) {
val navOnBottom = preferences.getString("mainNavPosition", "top") == "bottom" val navOnBottom = preferences.getString("mainNavPosition", "top") == "bottom"
if (navOnBottom) {
val avatarView = if (navOnBottom) { binding.bottomNav
binding.bottomNavAvatar.show()
binding.bottomNavAvatar
} else { } else {
binding.topNavAvatar.show() binding.topNav
binding.topNavAvatar
}
if (animateAvatars) {
Glide.with(this)
.load(avatarUrl)
.placeholder(R.drawable.avatar_default)
.into(avatarView)
} else {
Glide.with(this)
.asBitmap()
.load(avatarUrl)
.placeholder(R.drawable.avatar_default)
.into(avatarView)
} }
} else { } else {
binding.bottomNavAvatar.hide() binding.mainToolbar
binding.topNavAvatar.hide() }
val navIconSize = resources.getDimensionPixelSize(R.dimen.avatar_toolbar_nav_icon_size) val navIconSize = resources.getDimensionPixelSize(R.dimen.avatar_toolbar_nav_icon_size)
if (animateAvatars) { if (animateAvatars) {
glide.asDrawable() glide.asDrawable().load(avatarUrl).transform(RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp)))
.load(avatarUrl) .apply {
.transform( if (showPlaceholder) placeholder(R.drawable.avatar_default)
RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp)) }
) .into(object : CustomTarget<Drawable>(navIconSize, navIconSize) {
.apply {
if (showPlaceholder) { override fun onLoadStarted(placeholder: Drawable?) {
placeholder(R.drawable.avatar_default) placeholder?.let {
activeToolbar.navigationIcon = FixedSizeDrawable(it, navIconSize, navIconSize)
} }
} }
.into(object : CustomTarget<Drawable>(navIconSize, navIconSize) {
override fun onLoadStarted(placeholder: Drawable?) { override fun onResourceReady(
if (placeholder != null) { resource: Drawable,
binding.mainToolbar.navigationIcon = transition: Transition<in Drawable>?
FixedSizeDrawable(placeholder, navIconSize, navIconSize) ) {
} if (resource is Animatable) resource.start()
} activeToolbar.navigationIcon = FixedSizeDrawable(resource, navIconSize, navIconSize)
}
override fun onResourceReady( override fun onLoadCleared(placeholder: Drawable?) {
resource: Drawable, placeholder?.let {
transition: Transition<in Drawable>? activeToolbar.navigationIcon = FixedSizeDrawable(it, navIconSize, navIconSize)
) {
if (resource is Animatable) {
resource.start()
}
binding.mainToolbar.navigationIcon =
FixedSizeDrawable(resource, navIconSize, navIconSize)
}
override fun onLoadCleared(placeholder: Drawable?) {
if (placeholder != null) {
binding.mainToolbar.navigationIcon =
FixedSizeDrawable(placeholder, navIconSize, navIconSize)
}
}
})
} else {
glide.asBitmap()
.load(avatarUrl)
.transform(
RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp))
)
.apply {
if (showPlaceholder) {
placeholder(R.drawable.avatar_default)
} }
} }
.into(object : CustomTarget<Bitmap>(navIconSize, navIconSize) { })
} else {
override fun onLoadStarted(placeholder: Drawable?) { glide.asBitmap().load(avatarUrl).transform(RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp)))
if (placeholder != null) { .apply {
binding.mainToolbar.navigationIcon = if (showPlaceholder) placeholder(R.drawable.avatar_default)
FixedSizeDrawable(placeholder, navIconSize, navIconSize) }
} .into(object : CustomTarget<Bitmap>(navIconSize, navIconSize) {
override fun onLoadStarted(placeholder: Drawable?) {
placeholder?.let {
activeToolbar.navigationIcon = FixedSizeDrawable(it, navIconSize, navIconSize)
} }
}
override fun onResourceReady( override fun onResourceReady(
resource: Bitmap, resource: Bitmap,
transition: Transition<in Bitmap>? transition: Transition<in Bitmap>?
) { ) {
binding.mainToolbar.navigationIcon = FixedSizeDrawable( activeToolbar.navigationIcon = FixedSizeDrawable(
BitmapDrawable(resources, resource), BitmapDrawable(resources, resource),
navIconSize, navIconSize,
navIconSize navIconSize
) )
} }
override fun onLoadCleared(placeholder: Drawable?) { override fun onLoadCleared(placeholder: Drawable?) {
if (placeholder != null) { placeholder?.let {
binding.mainToolbar.navigationIcon = activeToolbar.navigationIcon = FixedSizeDrawable(it, navIconSize, navIconSize)
FixedSizeDrawable(placeholder, navIconSize, navIconSize)
}
} }
}) }
} })
} }
} }
@ -1043,8 +1048,75 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
private const val TAG = "MainActivity" // logging tag private const val TAG = "MainActivity" // logging tag
private const val DRAWER_ITEM_ADD_ACCOUNT: Long = -13 private const val DRAWER_ITEM_ADD_ACCOUNT: Long = -13
private const val DRAWER_ITEM_ANNOUNCEMENTS: Long = 14 private const val DRAWER_ITEM_ANNOUNCEMENTS: Long = 14
const val REDIRECT_URL = "redirectUrl" private const val REDIRECT_URL = "redirectUrl"
const val OPEN_DRAFTS = "draft" private const val OPEN_DRAFTS = "draft"
private const val TUSKY_ACCOUNT_ID = "tuskyAccountId"
private const val COMPOSE_OPTIONS = "composeOptions"
private const val NOTIFICATION_TYPE = "notificationType"
private const val NOTIFICATION_TAG = "notificationTag"
private const val NOTIFICATION_ID = "notificationId"
/**
* Switches the active account to the provided accountId and then stays on MainActivity
*/
@JvmStatic
fun accountSwitchIntent(context: Context, tuskyAccountId: Long): Intent {
return Intent(context, MainActivity::class.java).apply {
putExtra(TUSKY_ACCOUNT_ID, tuskyAccountId)
}
}
/**
* Switches the active account to the accountId and takes the user to the correct place according to the notification they clicked
*/
@JvmStatic
fun openNotificationIntent(context: Context, tuskyAccountId: Long, type: Notification.Type): Intent {
return accountSwitchIntent(context, tuskyAccountId).apply {
putExtra(NOTIFICATION_TYPE, type)
}
}
/**
* Switches the active account to the accountId and then opens ComposeActivity with the provided options
* @param tuskyAccountId the id of the Tusky account to open the screen with. Set to -1 for current account.
* @param notificationId optional id of the notification that should be cancelled when this intent is opened
* @param notificationTag optional tag of the notification that should be cancelled when this intent is opened
*/
@JvmStatic
fun composeIntent(
context: Context,
options: ComposeActivity.ComposeOptions,
tuskyAccountId: Long = -1,
notificationTag: String? = null,
notificationId: Int = -1
): Intent {
return accountSwitchIntent(context, tuskyAccountId).apply {
action = Intent.ACTION_SEND // so it can be opened via shortcuts
putExtra(COMPOSE_OPTIONS, options)
putExtra(NOTIFICATION_TAG, notificationTag)
putExtra(NOTIFICATION_ID, notificationId)
}
}
/**
* switches the active account to the accountId and then tries to resolve and show the provided url
*/
@JvmStatic
fun redirectIntent(context: Context, tuskyAccountId: Long, url: String): Intent {
return accountSwitchIntent(context, tuskyAccountId).apply {
putExtra(REDIRECT_URL, url)
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
}
/**
* switches the active account to the provided accountId and then opens drafts
*/
fun draftIntent(context: Context, tuskyAccountId: Long): Intent {
return accountSwitchIntent(context, tuskyAccountId).apply {
putExtra(OPEN_DRAFTS, true)
}
}
} }
} }

View File

@ -23,7 +23,7 @@ import com.keylesspalace.tusky.components.conversation.ConversationsFragment
import com.keylesspalace.tusky.components.notifications.NotificationsFragment import com.keylesspalace.tusky.components.notifications.NotificationsFragment
import com.keylesspalace.tusky.components.timeline.TimelineFragment import com.keylesspalace.tusky.components.timeline.TimelineFragment
import com.keylesspalace.tusky.components.timeline.viewmodel.TimelineViewModel import com.keylesspalace.tusky.components.timeline.viewmodel.TimelineViewModel
import com.keylesspalace.tusky.components.trending.TrendingFragment import com.keylesspalace.tusky.components.trending.TrendingTagsFragment
import java.util.Objects import java.util.Objects
/** this would be a good case for a sealed class, but that does not work nice with Room */ /** this would be a good case for a sealed class, but that does not work nice with Room */
@ -33,7 +33,7 @@ const val NOTIFICATIONS = "Notifications"
const val LOCAL = "Local" const val LOCAL = "Local"
const val FEDERATED = "Federated" const val FEDERATED = "Federated"
const val DIRECT = "Direct" const val DIRECT = "Direct"
const val TRENDING = "Trending" const val TRENDING_TAGS = "TrendingTags"
const val HASHTAG = "Hashtag" const val HASHTAG = "Hashtag"
const val LIST = "List" const val LIST = "List"
@ -92,11 +92,11 @@ fun createTabDataFromId(id: String, arguments: List<String> = emptyList()): TabD
icon = R.drawable.ic_reblog_direct_24dp, icon = R.drawable.ic_reblog_direct_24dp,
fragment = { ConversationsFragment.newInstance() } fragment = { ConversationsFragment.newInstance() }
) )
TRENDING -> TabData( TRENDING_TAGS -> TabData(
id = TRENDING, id = TRENDING_TAGS,
text = R.string.title_public_trending_hashtags, text = R.string.title_public_trending_hashtags,
icon = R.drawable.ic_trending_up_24px, icon = R.drawable.ic_trending_up_24px,
fragment = { TrendingFragment.newInstance() } fragment = { TrendingTagsFragment.newInstance() }
) )
HASHTAG -> TabData( HASHTAG -> TabData(
id = HASHTAG, id = HASHTAG,

View File

@ -378,9 +378,9 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene
if (!currentTabs.contains(directMessagesTab)) { if (!currentTabs.contains(directMessagesTab)) {
addableTabs.add(directMessagesTab) addableTabs.add(directMessagesTab)
} }
val trendingTab = createTabDataFromId(TRENDING) val trendingTagsTab = createTabDataFromId(TRENDING_TAGS)
if (!currentTabs.contains(trendingTab)) { if (!currentTabs.contains(trendingTagsTab)) {
addableTabs.add(trendingTab) addableTabs.add(trendingTagsTab)
} }
addableTabs.add(createTabDataFromId(HASHTAG)) addableTabs.add(createTabDataFromId(HASHTAG))

View File

@ -130,6 +130,12 @@ class TuskyApplication : Application(), HasAndroidInjector {
editor.remove(PrefKeys.MEDIA_PREVIEW_ENABLED) editor.remove(PrefKeys.MEDIA_PREVIEW_ENABLED)
} }
if (oldVersion < 2023072401) {
// The notifications filter / clear options are shown on a menu, not a separate bar,
// the preference to display them is not needed.
editor.remove(PrefKeys.Deprecated.SHOW_NOTIFICATIONS_FILTER)
}
editor.putInt(PrefKeys.SCHEMA_VERSION, newVersion) editor.putInt(PrefKeys.SCHEMA_VERSION, newVersion)
editor.apply() editor.apply()
} }

View File

@ -772,13 +772,16 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide
loadedAccount?.let { loadedAccount -> loadedAccount?.let { loadedAccount ->
val muteDomain = menu.findItem(R.id.action_mute_domain) val muteDomain = menu.findItem(R.id.action_mute_domain)
domain = getDomain(loadedAccount.url) domain = getDomain(loadedAccount.url)
if (domain.isEmpty()) { when {
// If we can't get the domain, there's no way we can mute it anyway... // If we can't get the domain, there's no way we can mute it anyway...
menu.removeItem(R.id.action_mute_domain) // If the account is from our own domain, muting it is no-op
} else { domain.isEmpty() || viewModel.isFromOwnDomain -> {
if (blockingDomain) { menu.removeItem(R.id.action_mute_domain)
}
blockingDomain -> {
muteDomain.title = getString(R.string.action_unmute_domain, domain) muteDomain.title = getString(R.string.action_unmute_domain, domain)
} else { }
else -> {
muteDomain.title = getString(R.string.action_mute_domain, domain) muteDomain.title = getString(R.string.action_mute_domain, domain)
} }
} }

View File

@ -19,6 +19,7 @@ import com.keylesspalace.tusky.util.Error
import com.keylesspalace.tusky.util.Loading import com.keylesspalace.tusky.util.Loading
import com.keylesspalace.tusky.util.Resource import com.keylesspalace.tusky.util.Resource
import com.keylesspalace.tusky.util.Success import com.keylesspalace.tusky.util.Success
import com.keylesspalace.tusky.util.getDomain
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -27,7 +28,7 @@ import javax.inject.Inject
class AccountViewModel @Inject constructor( class AccountViewModel @Inject constructor(
private val mastodonApi: MastodonApi, private val mastodonApi: MastodonApi,
private val eventHub: EventHub, private val eventHub: EventHub,
private val accountManager: AccountManager accountManager: AccountManager
) : ViewModel() { ) : ViewModel() {
val accountData = MutableLiveData<Resource<Account>>() val accountData = MutableLiveData<Resource<Account>>()
@ -41,8 +42,13 @@ class AccountViewModel @Inject constructor(
lateinit var accountId: String lateinit var accountId: String
var isSelf = false var isSelf = false
/** True if the viewed account has the same domain as the active account */
var isFromOwnDomain = false
private var noteUpdateJob: Job? = null private var noteUpdateJob: Job? = null
private val activeAccount = accountManager.activeAccount!!
init { init {
viewModelScope.launch { viewModelScope.launch {
eventHub.events.collect { event -> eventHub.events.collect { event ->
@ -65,6 +71,8 @@ class AccountViewModel @Inject constructor(
accountData.postValue(Success(account)) accountData.postValue(Success(account))
isDataLoading = false isDataLoading = false
isRefreshing.postValue(false) isRefreshing.postValue(false)
isFromOwnDomain = getDomain(account.url) == activeAccount.domain
}, },
{ t -> { t ->
Log.w(TAG, "failed obtaining account", t) Log.w(TAG, "failed obtaining account", t)
@ -298,7 +306,7 @@ class AccountViewModel @Inject constructor(
fun setAccountInfo(accountId: String) { fun setAccountInfo(accountId: String) {
this.accountId = accountId this.accountId = accountId
this.isSelf = accountManager.activeAccount?.accountId == accountId this.isSelf = activeAccount.accountId == accountId
reload(false) reload(false)
} }

View File

@ -16,7 +16,6 @@
package com.keylesspalace.tusky.components.compose package com.keylesspalace.tusky.components.compose
import android.Manifest import android.Manifest
import android.app.NotificationManager
import android.app.ProgressDialog import android.app.ProgressDialog
import android.content.ClipData import android.content.ClipData
import android.content.Context import android.content.Context
@ -207,22 +206,7 @@ class ComposeActivity :
public override fun onCreate(savedInstanceState: Bundle?) { public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val notificationId = intent.getIntExtra(NOTIFICATION_ID_EXTRA, -1) activeAccount = accountManager.activeAccount ?: return
if (notificationId != -1) {
// ComposeActivity was opened from a notification, delete the notification
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(notificationId)
}
// If started from an intent then compose as the account ID from the intent.
// Otherwise use the active account. If null then the user is not logged in,
// and return from the activity.
val intentAccountId = intent.getLongExtra(ACCOUNT_ID_EXTRA, -1)
activeAccount = if (intentAccountId != -1L) {
accountManager.getAccountById(intentAccountId)
} else {
accountManager.activeAccount
} ?: return
val theme = preferences.getString("appTheme", APP_THEME_DEFAULT) val theme = preferences.getString("appTheme", APP_THEME_DEFAULT)
if (theme == "black") { if (theme == "black") {
@ -280,7 +264,7 @@ class ComposeActivity :
binding.composeScheduleView.setDateTime(composeOptions?.scheduledAt) binding.composeScheduleView.setDateTime(composeOptions?.scheduledAt)
} }
setupLanguageSpinner(getInitialLanguages(composeOptions?.language, accountManager.activeAccount)) setupLanguageSpinner(getInitialLanguages(composeOptions?.language, activeAccount))
setupComposeField(preferences, viewModel.startingText) setupComposeField(preferences, viewModel.startingText)
setupContentWarningField(composeOptions?.contentWarning) setupContentWarningField(composeOptions?.contentWarning)
setupPollView() setupPollView()
@ -1355,8 +1339,6 @@ class ComposeActivity :
private const val PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1 private const val PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1
internal const val COMPOSE_OPTIONS_EXTRA = "COMPOSE_OPTIONS" internal const val COMPOSE_OPTIONS_EXTRA = "COMPOSE_OPTIONS"
private const val NOTIFICATION_ID_EXTRA = "NOTIFICATION_ID"
private const val ACCOUNT_ID_EXTRA = "ACCOUNT_ID"
private const val PHOTO_UPLOAD_URI_KEY = "PHOTO_UPLOAD_URI" private const val PHOTO_UPLOAD_URI_KEY = "PHOTO_UPLOAD_URI"
private const val VISIBILITY_KEY = "VISIBILITY" private const val VISIBILITY_KEY = "VISIBILITY"
private const val SCHEDULED_TIME_KEY = "SCHEDULE" private const val SCHEDULED_TIME_KEY = "SCHEDULE"
@ -1364,26 +1346,15 @@ class ComposeActivity :
/** /**
* @param options ComposeOptions to configure the ComposeActivity * @param options ComposeOptions to configure the ComposeActivity
* @param notificationId the id of the notification that starts the Activity
* @param accountId the id of the account to compose with, null for the current account
* @return an Intent to start the ComposeActivity * @return an Intent to start the ComposeActivity
*/ */
@JvmStatic @JvmStatic
@JvmOverloads
fun startIntent( fun startIntent(
context: Context, context: Context,
options: ComposeOptions, options: ComposeOptions
notificationId: Int? = null,
accountId: Long? = null
): Intent { ): Intent {
return Intent(context, ComposeActivity::class.java).apply { return Intent(context, ComposeActivity::class.java).apply {
putExtra(COMPOSE_OPTIONS_EXTRA, options) putExtra(COMPOSE_OPTIONS_EXTRA, options)
if (notificationId != null) {
putExtra(NOTIFICATION_ID_EXTRA, notificationId)
}
if (accountId != null) {
putExtra(ACCOUNT_ID_EXTRA, accountId)
}
} }
} }

View File

@ -85,13 +85,6 @@ public class NotificationHelper {
/** Dynamic notification IDs start here */ /** Dynamic notification IDs start here */
private static int notificationId = NOTIFICATION_ID_PRUNE_CACHE + 1; private static int notificationId = NOTIFICATION_ID_PRUNE_CACHE + 1;
/**
* constants used in Intents
*/
public static final String ACCOUNT_ID = "account_id";
public static final String TYPE = APPLICATION_ID + ".notification.type";
private static final String TAG = "NotificationHelper"; private static final String TAG = "NotificationHelper";
public static final String REPLY_ACTION = "REPLY_ACTION"; public static final String REPLY_ACTION = "REPLY_ACTION";
@ -325,11 +318,10 @@ public class NotificationHelper {
// Create a notification that summarises the other notifications in this group // Create a notification that summarises the other notifications in this group
// All notifications in this group have the same type, so get it from the first. // All notifications in this group have the same type, so get it from the first.
String notificationType = members.get(0).getNotification().extras.getString(EXTRA_NOTIFICATION_TYPE); Notification.Type notificationType = (Notification.Type)members.get(0).getNotification().extras.getSerializable(EXTRA_NOTIFICATION_TYPE);
Intent summaryResultIntent = MainActivity.openNotificationIntent(context, accountId, notificationType);
Intent summaryResultIntent = new Intent(context, MainActivity.class);
summaryResultIntent.putExtra(ACCOUNT_ID, (long) accountId);
summaryResultIntent.putExtra(TYPE, notificationType);
TaskStackBuilder summaryStackBuilder = TaskStackBuilder.create(context); TaskStackBuilder summaryStackBuilder = TaskStackBuilder.create(context);
summaryStackBuilder.addParentStack(MainActivity.class); summaryStackBuilder.addParentStack(MainActivity.class);
summaryStackBuilder.addNextIntent(summaryResultIntent); summaryStackBuilder.addNextIntent(summaryResultIntent);
@ -373,10 +365,8 @@ public class NotificationHelper {
private static NotificationCompat.Builder newAndroidNotification(Context context, Notification body, AccountEntity account) { private static NotificationCompat.Builder newAndroidNotification(Context context, Notification body, AccountEntity account) {
// we have to switch account here Intent eventResultIntent = MainActivity.openNotificationIntent(context, account.getId(), body.getType());
Intent eventResultIntent = new Intent(context, MainActivity.class);
eventResultIntent.putExtra(ACCOUNT_ID, account.getId());
eventResultIntent.putExtra(TYPE, body.getType().name());
TaskStackBuilder eventStackBuilder = TaskStackBuilder.create(context); TaskStackBuilder eventStackBuilder = TaskStackBuilder.create(context);
eventStackBuilder.addParentStack(MainActivity.class); eventStackBuilder.addParentStack(MainActivity.class);
eventStackBuilder.addNextIntent(eventResultIntent); eventStackBuilder.addNextIntent(eventResultIntent);
@ -464,12 +454,7 @@ public class NotificationHelper {
composeOptions.setLanguage(actionableStatus.getLanguage()); composeOptions.setLanguage(actionableStatus.getLanguage());
composeOptions.setKind(ComposeActivity.ComposeKind.NEW); composeOptions.setKind(ComposeActivity.ComposeKind.NEW);
Intent composeIntent = ComposeActivity.startIntent( Intent composeIntent = MainActivity.composeIntent(context, composeOptions, account.getId(), body.getId(), (int)account.getId());
context,
composeOptions,
notificationId,
account.getId()
);
composeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); composeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

View File

@ -28,7 +28,6 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.MenuProvider import androidx.core.view.MenuProvider
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
@ -46,7 +45,6 @@ import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
import at.connyduck.sparkbutton.helpers.Utils import at.connyduck.sparkbutton.helpers.Utils
import com.google.android.material.appbar.AppBarLayout.ScrollingViewBehavior
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
@ -123,21 +121,6 @@ class NotificationsFragment :
return inflater.inflate(R.layout.fragment_timeline_notifications, container, false) return inflater.inflate(R.layout.fragment_timeline_notifications, container, false)
} }
private fun updateFilterVisibility(showFilter: Boolean) {
val params = binding.swipeRefreshLayout.layoutParams as CoordinatorLayout.LayoutParams
if (showFilter) {
binding.appBarOptions.setExpanded(true, false)
binding.appBarOptions.visibility = View.VISIBLE
// Set content behaviour to hide filter on scroll
params.behavior = ScrollingViewBehavior()
} else {
binding.appBarOptions.setExpanded(false, false)
binding.appBarOptions.visibility = View.GONE
// Clear behaviour to hide app bar
params.behavior = null
}
}
private fun confirmClearNotifications() { private fun confirmClearNotifications() {
AlertDialog.Builder(requireContext()) AlertDialog.Builder(requireContext())
.setMessage(R.string.notification_clear_text) .setMessage(R.string.notification_clear_text)
@ -215,8 +198,6 @@ class NotificationsFragment :
footer = NotificationsLoadStateAdapter { adapter.retry() } footer = NotificationsLoadStateAdapter { adapter.retry() }
) )
binding.buttonClear.setOnClickListener { confirmClearNotifications() }
binding.buttonFilter.setOnClickListener { showFilterDialog() }
(binding.recyclerView.itemAnimator as SimpleItemAnimator?)!!.supportsChangeAnimations = (binding.recyclerView.itemAnimator as SimpleItemAnimator?)!!.supportsChangeAnimations =
false false
@ -369,10 +350,10 @@ class NotificationsFragment :
} }
} }
// Update filter option visibility from uiState // Collect the uiState. Nothing is done with it, but if you don't collect it then
launch { // accessing viewModel.uiState.value (e.g., when the filter dialog is created)
viewModel.uiState.collectLatest { updateFilterVisibility(it.showFilterOptions) } // returns an empty object.
} launch { viewModel.uiState.collect() }
// Update status display from statusDisplayOptions. If the new options request // Update status display from statusDisplayOptions. If the new options request
// relative time display collect the flow to periodically update the timestamp in the list gui elements. // relative time display collect the flow to periodically update the timestamp in the list gui elements.
@ -439,10 +420,17 @@ class NotificationsFragment :
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.fragment_notifications, menu) menuInflater.inflate(R.menu.fragment_notifications, menu)
val iconColor = MaterialColors.getColor(binding.root, android.R.attr.textColorPrimary)
menu.findItem(R.id.action_refresh)?.apply { menu.findItem(R.id.action_refresh)?.apply {
icon = IconicsDrawable(requireContext(), GoogleMaterial.Icon.gmd_refresh).apply { icon = IconicsDrawable(requireContext(), GoogleMaterial.Icon.gmd_refresh).apply {
sizeDp = 20 sizeDp = 20
colorInt = MaterialColors.getColor(binding.root, android.R.attr.textColorPrimary) colorInt = iconColor
}
}
menu.findItem(R.id.action_edit_notification_filter)?.apply {
icon = IconicsDrawable(requireContext(), GoogleMaterial.Icon.gmd_tune).apply {
sizeDp = 20
colorInt = iconColor
} }
} }
} }
@ -458,6 +446,14 @@ class NotificationsFragment :
viewModel.accept(InfallibleUiAction.LoadNewest) viewModel.accept(InfallibleUiAction.LoadNewest)
true true
} }
R.id.action_edit_notification_filter -> {
showFilterDialog()
true
}
R.id.action_clear_notifications -> {
confirmClearNotifications()
true
}
else -> false else -> false
} }
} }
@ -625,7 +621,6 @@ class NotificationsFragment :
override fun onReselect() { override fun onReselect() {
if (isAdded) { if (isAdded) {
binding.appBarOptions.setExpanded(true, false)
layoutManager.scrollToPosition(0) layoutManager.scrollToPosition(0)
} }
} }

View File

@ -74,23 +74,18 @@ data class UiState(
/** Filtered notification types */ /** Filtered notification types */
val activeFilter: Set<Notification.Type> = emptySet(), val activeFilter: Set<Notification.Type> = emptySet(),
/** True if the UI to filter and clear notifications should be shown */
val showFilterOptions: Boolean = false,
/** True if the FAB should be shown while scrolling */ /** True if the FAB should be shown while scrolling */
val showFabWhileScrolling: Boolean = true val showFabWhileScrolling: Boolean = true
) )
/** Preferences the UI reacts to */ /** Preferences the UI reacts to */
data class UiPrefs( data class UiPrefs(
val showFabWhileScrolling: Boolean, val showFabWhileScrolling: Boolean
val showFilter: Boolean
) { ) {
companion object { companion object {
/** Relevant preference keys. Changes to any of these trigger a display update */ /** Relevant preference keys. Changes to any of these trigger a display update */
val prefKeys = setOf( val prefKeys = setOf(
PrefKeys.FAB_HIDE, PrefKeys.FAB_HIDE
PrefKeys.SHOW_NOTIFICATIONS_FILTER
) )
} }
} }
@ -495,7 +490,6 @@ class NotificationsViewModel @Inject constructor(
uiState = combine(notificationFilter, getUiPrefs()) { filter, prefs -> uiState = combine(notificationFilter, getUiPrefs()) { filter, prefs ->
UiState( UiState(
activeFilter = filter.filter, activeFilter = filter.filter,
showFilterOptions = prefs.showFilter,
showFabWhileScrolling = prefs.showFabWhileScrolling showFabWhileScrolling = prefs.showFabWhileScrolling
) )
}.stateIn( }.stateIn(
@ -544,8 +538,7 @@ class NotificationsViewModel @Inject constructor(
.onStart { emit(toPrefs()) } .onStart { emit(toPrefs()) }
private fun toPrefs() = UiPrefs( private fun toPrefs() = UiPrefs(
showFabWhileScrolling = !preferences.getBoolean(PrefKeys.FAB_HIDE, false), showFabWhileScrolling = !preferences.getBoolean(PrefKeys.FAB_HIDE, false)
showFilter = preferences.getBoolean(PrefKeys.SHOW_NOTIFICATIONS_FILTER, true)
) )
companion object { companion object {

View File

@ -208,13 +208,6 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
isSingleLineTitle = false isSingleLineTitle = false
} }
switchPreference {
setDefaultValue(true)
key = PrefKeys.SHOW_NOTIFICATIONS_FILTER
setTitle(R.string.pref_title_show_notifications_filter)
isSingleLineTitle = false
}
switchPreference { switchPreference {
setDefaultValue(true) setDefaultValue(true)
key = PrefKeys.CONFIRM_REBLOGS key = PrefKeys.CONFIRM_REBLOGS

View File

@ -48,7 +48,7 @@ class TrendingActivity : BaseActivity(), HasAndroidInjector {
if (supportFragmentManager.findFragmentById(R.id.fragmentContainer) == null) { if (supportFragmentManager.findFragmentById(R.id.fragmentContainer) == null) {
supportFragmentManager.commit { supportFragmentManager.commit {
val fragment = TrendingFragment.newInstance() val fragment = TrendingTagsFragment.newInstance()
replace(R.id.fragmentContainer, fragment) replace(R.id.fragmentContainer, fragment)
} }
} }

View File

@ -24,7 +24,7 @@ import com.keylesspalace.tusky.databinding.ItemTrendingCellBinding
import com.keylesspalace.tusky.databinding.ItemTrendingDateBinding import com.keylesspalace.tusky.databinding.ItemTrendingDateBinding
import com.keylesspalace.tusky.viewdata.TrendingViewData import com.keylesspalace.tusky.viewdata.TrendingViewData
class TrendingAdapter( class TrendingTagsAdapter(
private val onViewTag: (String) -> Unit private val onViewTag: (String) -> Unit
) : ListAdapter<TrendingViewData, RecyclerView.ViewHolder>(TrendingDifferCallback) { ) : ListAdapter<TrendingViewData, RecyclerView.ViewHolder>(TrendingDifferCallback) {

View File

@ -33,8 +33,8 @@ import at.connyduck.sparkbutton.helpers.Utils
import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.StatusListActivity import com.keylesspalace.tusky.StatusListActivity
import com.keylesspalace.tusky.components.trending.viewmodel.TrendingViewModel import com.keylesspalace.tusky.components.trending.viewmodel.TrendingTagsViewModel
import com.keylesspalace.tusky.databinding.FragmentTrendingBinding import com.keylesspalace.tusky.databinding.FragmentTrendingTagsBinding
import com.keylesspalace.tusky.di.Injectable import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.di.ViewModelFactory import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.interfaces.ActionButtonActivity import com.keylesspalace.tusky.interfaces.ActionButtonActivity
@ -48,8 +48,8 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
class TrendingFragment : class TrendingTagsFragment :
Fragment(R.layout.fragment_trending), Fragment(R.layout.fragment_trending_tags),
OnRefreshListener, OnRefreshListener,
Injectable, Injectable,
ReselectableFragment, ReselectableFragment,
@ -58,11 +58,11 @@ class TrendingFragment :
@Inject @Inject
lateinit var viewModelFactory: ViewModelFactory lateinit var viewModelFactory: ViewModelFactory
private val viewModel: TrendingViewModel by viewModels { viewModelFactory } private val viewModel: TrendingTagsViewModel by viewModels { viewModelFactory }
private val binding by viewBinding(FragmentTrendingBinding::bind) private val binding by viewBinding(FragmentTrendingTagsBinding::bind)
private val adapter = TrendingAdapter(::onViewTag) private val adapter = TrendingTagsAdapter(::onViewTag)
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
@ -111,8 +111,8 @@ class TrendingFragment :
spanSizeLookup = object : SpanSizeLookup() { spanSizeLookup = object : SpanSizeLookup() {
override fun getSpanSize(position: Int): Int { override fun getSpanSize(position: Int): Int {
return when (adapter.getItemViewType(position)) { return when (adapter.getItemViewType(position)) {
TrendingAdapter.VIEW_TYPE_HEADER -> columnCount TrendingTagsAdapter.VIEW_TYPE_HEADER -> columnCount
TrendingAdapter.VIEW_TYPE_TAG -> 1 TrendingTagsAdapter.VIEW_TYPE_TAG -> 1
else -> -1 else -> -1
} }
} }
@ -139,15 +139,15 @@ class TrendingFragment :
(requireActivity() as BaseActivity).startActivityWithSlideInAnimation(StatusListActivity.newHashtagIntent(requireContext(), tag)) (requireActivity() as BaseActivity).startActivityWithSlideInAnimation(StatusListActivity.newHashtagIntent(requireContext(), tag))
} }
private fun processViewState(uiState: TrendingViewModel.TrendingUiState) { private fun processViewState(uiState: TrendingTagsViewModel.TrendingTagsUiState) {
Log.d(TAG, uiState.loadingState.name) Log.d(TAG, uiState.loadingState.name)
when (uiState.loadingState) { when (uiState.loadingState) {
TrendingViewModel.LoadingState.INITIAL -> clearLoadingState() TrendingTagsViewModel.LoadingState.INITIAL -> clearLoadingState()
TrendingViewModel.LoadingState.LOADING -> applyLoadingState() TrendingTagsViewModel.LoadingState.LOADING -> applyLoadingState()
TrendingViewModel.LoadingState.REFRESHING -> applyRefreshingState() TrendingTagsViewModel.LoadingState.REFRESHING -> applyRefreshingState()
TrendingViewModel.LoadingState.LOADED -> applyLoadedState(uiState.trendingViewData) TrendingTagsViewModel.LoadingState.LOADED -> applyLoadedState(uiState.trendingViewData)
TrendingViewModel.LoadingState.ERROR_NETWORK -> networkError() TrendingTagsViewModel.LoadingState.ERROR_NETWORK -> networkError()
TrendingViewModel.LoadingState.ERROR_OTHER -> otherError() TrendingTagsViewModel.LoadingState.ERROR_OTHER -> otherError()
} }
} }
@ -247,8 +247,8 @@ class TrendingFragment :
} }
companion object { companion object {
private const val TAG = "TrendingFragment" private const val TAG = "TrendingTagsFragment"
fun newInstance() = TrendingFragment() fun newInstance() = TrendingTagsFragment()
} }
} }

View File

@ -35,7 +35,7 @@ import kotlinx.coroutines.launch
import java.io.IOException import java.io.IOException
import javax.inject.Inject import javax.inject.Inject
class TrendingViewModel @Inject constructor( class TrendingTagsViewModel @Inject constructor(
private val mastodonApi: MastodonApi, private val mastodonApi: MastodonApi,
private val eventHub: EventHub private val eventHub: EventHub
) : ViewModel() { ) : ViewModel() {
@ -43,13 +43,13 @@ class TrendingViewModel @Inject constructor(
INITIAL, LOADING, REFRESHING, LOADED, ERROR_NETWORK, ERROR_OTHER INITIAL, LOADING, REFRESHING, LOADED, ERROR_NETWORK, ERROR_OTHER
} }
data class TrendingUiState( data class TrendingTagsUiState(
val trendingViewData: List<TrendingViewData>, val trendingViewData: List<TrendingViewData>,
val loadingState: LoadingState val loadingState: LoadingState
) )
val uiState: Flow<TrendingUiState> get() = _uiState val uiState: Flow<TrendingTagsUiState> get() = _uiState
private val _uiState = MutableStateFlow(TrendingUiState(listOf(), LoadingState.INITIAL)) private val _uiState = MutableStateFlow(TrendingTagsUiState(listOf(), LoadingState.INITIAL))
init { init {
invalidate() invalidate()
@ -73,9 +73,9 @@ class TrendingViewModel @Inject constructor(
*/ */
fun invalidate(refresh: Boolean = false) = viewModelScope.launch { fun invalidate(refresh: Boolean = false) = viewModelScope.launch {
if (refresh) { if (refresh) {
_uiState.value = TrendingUiState(emptyList(), LoadingState.REFRESHING) _uiState.value = TrendingTagsUiState(emptyList(), LoadingState.REFRESHING)
} else { } else {
_uiState.value = TrendingUiState(emptyList(), LoadingState.LOADING) _uiState.value = TrendingTagsUiState(emptyList(), LoadingState.LOADING)
} }
val deferredFilters = async { mastodonApi.getFilters() } val deferredFilters = async { mastodonApi.getFilters() }
@ -85,7 +85,7 @@ class TrendingViewModel @Inject constructor(
val firstTag = tagResponse.firstOrNull() val firstTag = tagResponse.firstOrNull()
_uiState.value = if (firstTag == null) { _uiState.value = if (firstTag == null) {
TrendingUiState(emptyList(), LoadingState.LOADED) TrendingTagsUiState(emptyList(), LoadingState.LOADED)
} else { } else {
val homeFilters = deferredFilters.await().getOrNull()?.filter { filter -> val homeFilters = deferredFilters.await().getOrNull()?.filter { filter ->
filter.context.contains(Filter.Kind.HOME.kind) filter.context.contains(Filter.Kind.HOME.kind)
@ -100,15 +100,15 @@ class TrendingViewModel @Inject constructor(
.toViewData() .toViewData()
val header = TrendingViewData.Header(firstTag.start(), firstTag.end()) val header = TrendingViewData.Header(firstTag.start(), firstTag.end())
TrendingUiState(listOf(header) + tags, LoadingState.LOADED) TrendingTagsUiState(listOf(header) + tags, LoadingState.LOADED)
} }
}, },
{ error -> { error ->
Log.w(TAG, "failed loading trending tags", error) Log.w(TAG, "failed loading trending tags", error)
if (error is IOException) { if (error is IOException) {
_uiState.value = TrendingUiState(emptyList(), LoadingState.ERROR_NETWORK) _uiState.value = TrendingTagsUiState(emptyList(), LoadingState.ERROR_NETWORK)
} else { } else {
_uiState.value = TrendingUiState(emptyList(), LoadingState.ERROR_OTHER) _uiState.value = TrendingTagsUiState(emptyList(), LoadingState.ERROR_OTHER)
} }
} }
) )

View File

@ -42,12 +42,12 @@ import java.io.File;
TimelineAccountEntity.class, TimelineAccountEntity.class,
ConversationEntity.class ConversationEntity.class
}, },
version = 52, version = 53,
autoMigrations = { autoMigrations = {
@AutoMigration(from = 48, to = 49), @AutoMigration(from = 48, to = 49),
@AutoMigration(from = 49, to = 50, spec = AppDatabase.MIGRATION_49_50.class), @AutoMigration(from = 49, to = 50, spec = AppDatabase.MIGRATION_49_50.class),
@AutoMigration(from = 50, to = 51), @AutoMigration(from = 50, to = 51),
@AutoMigration(from = 51, to = 52) @AutoMigration(from = 51, to = 52),
} }
) )
public abstract class AppDatabase extends RoomDatabase { public abstract class AppDatabase extends RoomDatabase {
@ -674,4 +674,15 @@ public abstract class AppDatabase extends RoomDatabase {
@DeleteColumn(tableName = "AccountEntity", columnName = "activeNotifications") @DeleteColumn(tableName = "AccountEntity", columnName = "activeNotifications")
static class MIGRATION_49_50 implements AutoMigrationSpec { } static class MIGRATION_49_50 implements AutoMigrationSpec { }
/**
* TabData.TRENDING was renamed to TabData.TRENDING_TAGS, and the text
* representation was changed from "Trending" to "TrendingTags".
*/
public static final Migration MIGRATION_52_53 = new Migration(52, 53) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("UPDATE `AccountEntity` SET `tabpreferences` = REPLACE(tabpreferences, 'Trending:', 'TrendingTags:')");
}
};
} }

View File

@ -68,7 +68,7 @@ class AppModule {
AppDatabase.MIGRATION_38_39, AppDatabase.MIGRATION_39_40, AppDatabase.MIGRATION_40_41, AppDatabase.MIGRATION_38_39, AppDatabase.MIGRATION_39_40, AppDatabase.MIGRATION_40_41,
AppDatabase.MIGRATION_41_42, AppDatabase.MIGRATION_42_43, AppDatabase.MIGRATION_43_44, AppDatabase.MIGRATION_41_42, AppDatabase.MIGRATION_42_43, AppDatabase.MIGRATION_43_44,
AppDatabase.MIGRATION_44_45, AppDatabase.MIGRATION_45_46, AppDatabase.MIGRATION_46_47, AppDatabase.MIGRATION_44_45, AppDatabase.MIGRATION_45_46, AppDatabase.MIGRATION_46_47,
AppDatabase.MIGRATION_47_48 AppDatabase.MIGRATION_47_48, AppDatabase.MIGRATION_52_53
) )
.build() .build()
} }

View File

@ -32,7 +32,7 @@ import com.keylesspalace.tusky.components.search.fragments.SearchAccountsFragmen
import com.keylesspalace.tusky.components.search.fragments.SearchHashtagsFragment import com.keylesspalace.tusky.components.search.fragments.SearchHashtagsFragment
import com.keylesspalace.tusky.components.search.fragments.SearchStatusesFragment import com.keylesspalace.tusky.components.search.fragments.SearchStatusesFragment
import com.keylesspalace.tusky.components.timeline.TimelineFragment import com.keylesspalace.tusky.components.timeline.TimelineFragment
import com.keylesspalace.tusky.components.trending.TrendingFragment import com.keylesspalace.tusky.components.trending.TrendingTagsFragment
import com.keylesspalace.tusky.components.viewthread.ViewThreadFragment import com.keylesspalace.tusky.components.viewthread.ViewThreadFragment
import com.keylesspalace.tusky.components.viewthread.edits.ViewEditsFragment import com.keylesspalace.tusky.components.viewthread.edits.ViewEditsFragment
import com.keylesspalace.tusky.fragment.ViewVideoFragment import com.keylesspalace.tusky.fragment.ViewVideoFragment
@ -99,7 +99,7 @@ abstract class FragmentBuildersModule {
abstract fun listsForAccountFragment(): ListsForAccountFragment abstract fun listsForAccountFragment(): ListsForAccountFragment
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun trendingFragment(): TrendingFragment abstract fun trendingTagsFragment(): TrendingTagsFragment
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun viewVideoFragment(): ViewVideoFragment abstract fun viewVideoFragment(): ViewVideoFragment

View File

@ -38,7 +38,7 @@ import com.keylesspalace.tusky.components.scheduled.ScheduledStatusViewModel
import com.keylesspalace.tusky.components.search.SearchViewModel import com.keylesspalace.tusky.components.search.SearchViewModel
import com.keylesspalace.tusky.components.timeline.viewmodel.CachedTimelineViewModel import com.keylesspalace.tusky.components.timeline.viewmodel.CachedTimelineViewModel
import com.keylesspalace.tusky.components.timeline.viewmodel.NetworkTimelineViewModel import com.keylesspalace.tusky.components.timeline.viewmodel.NetworkTimelineViewModel
import com.keylesspalace.tusky.components.trending.viewmodel.TrendingViewModel import com.keylesspalace.tusky.components.trending.viewmodel.TrendingTagsViewModel
import com.keylesspalace.tusky.components.viewthread.ViewThreadViewModel import com.keylesspalace.tusky.components.viewthread.ViewThreadViewModel
import com.keylesspalace.tusky.components.viewthread.edits.ViewEditsViewModel import com.keylesspalace.tusky.components.viewthread.edits.ViewEditsViewModel
import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel
@ -172,8 +172,8 @@ abstract class ViewModelModule {
@Binds @Binds
@IntoMap @IntoMap
@ViewModelKey(TrendingViewModel::class) @ViewModelKey(TrendingTagsViewModel::class)
internal abstract fun trendingViewModel(viewModel: TrendingViewModel): ViewModel internal abstract fun trendingTagsViewModel(viewModel: TrendingTagsViewModel): ViewModel
@Binds @Binds
@IntoMap @IntoMap

View File

@ -379,9 +379,7 @@ class SendStatusService : Service(), Injectable {
accountId: Long, accountId: Long,
statusId: Int statusId: Int
): Notification { ): Notification {
val intent = Intent(this, MainActivity::class.java) val intent = MainActivity.draftIntent(this, accountId)
intent.putExtra(NotificationHelper.ACCOUNT_ID, accountId)
intent.putExtra(MainActivity.OPEN_DRAFTS, true)
val pendingIntent = PendingIntent.getActivity( val pendingIntent = PendingIntent.getActivity(
this, this,

View File

@ -19,6 +19,7 @@ import android.annotation.TargetApi
import android.content.Intent import android.content.Intent
import android.service.quicksettings.TileService import android.service.quicksettings.TileService
import com.keylesspalace.tusky.MainActivity import com.keylesspalace.tusky.MainActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity
/** /**
* Small Addition that adds in a QuickSettings tile * Small Addition that adds in a QuickSettings tile
@ -29,11 +30,8 @@ import com.keylesspalace.tusky.MainActivity
class TuskyTileService : TileService() { class TuskyTileService : TileService() {
override fun onClick() { override fun onClick() {
val intent = Intent(this, MainActivity::class.java).apply { val intent = MainActivity.composeIntent(this, ComposeActivity.ComposeOptions())
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
action = Intent.ACTION_SEND
type = "text/plain"
}
startActivityAndCollapse(intent) startActivityAndCollapse(intent)
} }
} }

View File

@ -41,7 +41,7 @@ enum class AppTheme(val value: String) {
* *
* - Adding a new preference that does not change the interpretation of an existing preference * - Adding a new preference that does not change the interpretation of an existing preference
*/ */
const val SCHEMA_VERSION = 2023022701 const val SCHEMA_VERSION = 2023072401
object PrefKeys { object PrefKeys {
// Note: not all of these keys are actually used as SharedPreferences keys but we must give // Note: not all of these keys are actually used as SharedPreferences keys but we must give
@ -61,7 +61,6 @@ object PrefKeys {
const val ANIMATE_GIF_AVATARS = "animateGifAvatars" const val ANIMATE_GIF_AVATARS = "animateGifAvatars"
const val USE_BLURHASH = "useBlurhash" const val USE_BLURHASH = "useBlurhash"
const val SHOW_SELF_USERNAME = "showSelfUsername" const val SHOW_SELF_USERNAME = "showSelfUsername"
const val SHOW_NOTIFICATIONS_FILTER = "showNotificationsFilter"
const val SHOW_CARDS_IN_TIMELINES = "showCardsInTimelines" const val SHOW_CARDS_IN_TIMELINES = "showCardsInTimelines"
const val CONFIRM_REBLOGS = "confirmReblogs" const val CONFIRM_REBLOGS = "confirmReblogs"
const val CONFIRM_FAVOURITES = "confirmFavourites" const val CONFIRM_FAVOURITES = "confirmFavourites"
@ -104,4 +103,9 @@ object PrefKeys {
/** UI text scaling factor, stored as float, 100 = 100% = no scaling */ /** UI text scaling factor, stored as float, 100 = 100% = no scaling */
const val UI_TEXT_SCALE_RATIO = "uiTextScaleRatio" const val UI_TEXT_SCALE_RATIO = "uiTextScaleRatio"
/** Keys that are no longer used (e.g., the preference has been removed */
object Deprecated {
const val SHOW_NOTIFICATIONS_FILTER = "showNotificationsFilter"
}
} }

View File

@ -29,7 +29,6 @@ import androidx.core.graphics.drawable.IconCompat
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.keylesspalace.tusky.MainActivity import com.keylesspalace.tusky.MainActivity
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.notifications.NotificationHelper
import com.keylesspalace.tusky.db.AccountEntity import com.keylesspalace.tusky.db.AccountEntity
import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
@ -72,7 +71,7 @@ fun updateShortcut(context: Context, account: AccountEntity) {
val intent = Intent(context, MainActivity::class.java).apply { val intent = Intent(context, MainActivity::class.java).apply {
action = Intent.ACTION_SEND action = Intent.ACTION_SEND
type = "text/plain" type = "text/plain"
putExtra(NotificationHelper.ACCOUNT_ID, account.id) putExtra(ShortcutManagerCompat.EXTRA_SHORTCUT_ID, account.id.toString())
} }
val shortcutInfo = ShortcutInfoCompat.Builder(context, account.id.toString()) val shortcutInfo = ShortcutInfoCompat.Builder(context, account.id.toString())

View File

@ -29,22 +29,14 @@
app:layout_scrollFlags="scroll|enterAlways" app:layout_scrollFlags="scroll|enterAlways"
app:navigationContentDescription="@string/action_open_drawer" /> app:navigationContentDescription="@string/action_open_drawer" />
<LinearLayout <androidx.appcompat.widget.Toolbar
android:id="@+id/topNav" android:id="@+id/topNav"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="48dp"
android:orientation="horizontal"> android:orientation="horizontal"
app:contentInsetStart="0dp"
<com.google.android.material.imageview.ShapeableImageView app:contentInsetStartWithNavigation="0dp"
android:id="@+id/topNavAvatar" app:navigationContentDescription="@string/action_open_drawer">
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:contentDescription="@string/action_open_drawer"
app:shapeAppearance="@style/ShapeAppearance.Avatar"
tools:src="@drawable/avatar_default" />
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout" android:id="@+id/tabLayout"
@ -54,8 +46,7 @@
app:tabGravity="fill" app:tabGravity="fill"
app:tabMaxWidth="0dp" app:tabMaxWidth="0dp"
app:tabMode="fixed" /> app:tabMode="fixed" />
</androidx.appcompat.widget.Toolbar>
</LinearLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
@ -73,33 +64,16 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" android:layout_gravity="bottom"
app:contentInsetStart="0dp" app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="0dp"
app:fabAlignmentMode="end"> app:fabAlignmentMode="end">
<LinearLayout <com.google.android.material.tabs.TabLayout
android:id="@+id/bottomTabLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="?attr/actionBarSize"
android:orientation="horizontal"> app:tabGravity="fill"
app:tabIndicatorGravity="top"
<com.google.android.material.imageview.ShapeableImageView app:tabMode="fixed" />
android:id="@+id/bottomNavAvatar"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:contentDescription="@string/action_open_drawer"
app:shapeAppearance="@style/ShapeAppearance.Avatar"
tools:src="@drawable/avatar_default" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/bottomTabLayout"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:tabGravity="fill"
app:tabIndicator="@null"
app:tabMode="fixed" />
</LinearLayout>
</com.google.android.material.bottomappbar.BottomAppBar> </com.google.android.material.bottomappbar.BottomAppBar>
@ -132,4 +106,3 @@
android:fitsSystemWindows="true" /> android:fitsSystemWindows="true" />
</androidx.drawerlayout.widget.DrawerLayout> </androidx.drawerlayout.widget.DrawerLayout>

View File

@ -18,53 +18,10 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?android:attr/colorBackground"> android:background="?android:attr/colorBackground">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarOptions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
app:elevation="0dp">
<LinearLayout
android:id="@+id/topButtonsLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/buttonClear"
style="@style/TuskyButton.TextButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/notifications_clear"
android:textSize="?attr/status_text_medium" />
<Button
android:id="@+id/buttonFilter"
style="@style/TuskyButton.TextButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/notifications_apply_filter"
android:textSize="?attr/status_text_medium" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom"
android:background="?android:attr/listDivider"
app:layout_scrollFlags="scroll|enterAlways" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout" android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -27,4 +27,14 @@
android:id="@+id/load_newest" android:id="@+id/load_newest"
android:title="@string/load_newest_notifications" android:title="@string/load_newest_notifications"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/action_edit_notification_filter"
android:title="@string/notifications_apply_filter"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_clear_notifications"
android:title="@string/notifications_clear"
app:showAsAction="never" />
</menu> </menu>

View File

@ -450,7 +450,6 @@
<string name="report_remote_instance">أعد تحويله إلى %s</string> <string name="report_remote_instance">أعد تحويله إلى %s</string>
<string name="failed_report">فشل الابلاغ</string> <string name="failed_report">فشل الابلاغ</string>
<string name="failed_fetch_posts">فشلت عملية جلب المنشورات</string> <string name="failed_fetch_posts">فشلت عملية جلب المنشورات</string>
<string name="pref_title_show_notifications_filter">اعرض مصفاة الإشعارات</string>
<string name="filter_dialog_whole_word">الكلمة كاملة</string> <string name="filter_dialog_whole_word">الكلمة كاملة</string>
<string name="description_poll">استطلاع رأي بالخيارات: %1$s, %2$s, %3$s, %4$s; %5$s</string> <string name="description_poll">استطلاع رأي بالخيارات: %1$s, %2$s, %3$s, %4$s; %5$s</string>
<string name="mute_domain_warning">هل أنت متأكد من أنك تريد حجب كافة %s؟ سوف لن يكون باستطاعتك رؤية أي محتوى قادم من هذا النطاق بعد الآن ، لا في الخيوط الزمنية العامة ولا في إخطاراتك. سيتم إزالة متابِعيك الذين هم على هذا النطاق.</string> <string name="mute_domain_warning">هل أنت متأكد من أنك تريد حجب كافة %s؟ سوف لن يكون باستطاعتك رؤية أي محتوى قادم من هذا النطاق بعد الآن ، لا في الخيوط الزمنية العامة ولا في إخطاراتك. سيتم إزالة متابِعيك الذين هم على هذا النطاق.</string>

View File

@ -483,7 +483,6 @@
<string name="hint_additional_info">Дадатковыя каментары</string> <string name="hint_additional_info">Дадатковыя каментары</string>
<string name="title_accounts">Уліковыя запісы</string> <string name="title_accounts">Уліковыя запісы</string>
<string name="failed_search">Пошук не атрымаўся</string> <string name="failed_search">Пошук не атрымаўся</string>
<string name="pref_title_show_notifications_filter">Паказаць фільтр апавяшчэнняў</string>
<string name="create_poll_title">Апытанне</string> <string name="create_poll_title">Апытанне</string>
<string name="duration_1_day">1 дзень</string> <string name="duration_1_day">1 дзень</string>
<string name="duration_3_days">3 дні</string> <string name="duration_3_days">3 дні</string>

View File

@ -9,7 +9,6 @@
<string name="label_duration">Продължителност</string> <string name="label_duration">Продължителност</string>
<string name="create_poll_title">Анкета</string> <string name="create_poll_title">Анкета</string>
<string name="pref_title_enable_swipe_for_tabs">Активиране на плъзгащия жест за превключване между раздели</string> <string name="pref_title_enable_swipe_for_tabs">Активиране на плъзгащия жест за превключване между раздели</string>
<string name="pref_title_show_notifications_filter">Показване на филтър за известия</string>
<string name="failed_search">Търсенето бе неуспешно</string> <string name="failed_search">Търсенето бе неуспешно</string>
<string name="title_accounts">Акаунти</string> <string name="title_accounts">Акаунти</string>
<string name="report_description_remote_instance">Акаунтът е от друг сървър. Да изпратите ли и там анонимно копие на доклада\?</string> <string name="report_description_remote_instance">Акаунтът е от друг сървър. Да изпратите ли и там анонимно копие на доклада\?</string>

View File

@ -362,7 +362,6 @@
<string name="title_accounts">অ্যাকাউন্টগুলো</string> <string name="title_accounts">অ্যাকাউন্টগুলো</string>
<string name="filter_dialog_whole_word_description">যখন শব্দ বা বাক্যাংশটি শুধুমাত্র আলফানিউমেরিক হয় তখন এটি শুধুমাত্র তখনই প্রয়োগ করা হবে যদি এটি সম্পূর্ণ শব্দটির সাথে মেলে</string> <string name="filter_dialog_whole_word_description">যখন শব্দ বা বাক্যাংশটি শুধুমাত্র আলফানিউমেরিক হয় তখন এটি শুধুমাত্র তখনই প্রয়োগ করা হবে যদি এটি সম্পূর্ণ শব্দটির সাথে মেলে</string>
<string name="filter_dialog_whole_word">সম্পূর্ণ শব্দ</string> <string name="filter_dialog_whole_word">সম্পূর্ণ শব্দ</string>
<string name="pref_title_show_notifications_filter">বিজ্ঞপ্তি ফিল্টার দেখান</string>
<string name="mute_domain_warning_dialog_ok">পুরো ডোমেইন লুকান</string> <string name="mute_domain_warning_dialog_ok">পুরো ডোমেইন লুকান</string>
<string name="mute_domain_warning">আপনি কি সব %s ব্লক করতে চান\? আপনি যে ডোমেন থেকে কোনও পাবলিক টাইমলাইনে বা আপনার বিজ্ঞপ্তিগুলিতে সামগ্রী দেখতে পাবেন না। আপনার অনুসরণকারীদের সরানো হবে।</string> <string name="mute_domain_warning">আপনি কি সব %s ব্লক করতে চান\? আপনি যে ডোমেন থেকে কোনও পাবলিক টাইমলাইনে বা আপনার বিজ্ঞপ্তিগুলিতে সামগ্রী দেখতে পাবেন না। আপনার অনুসরণকারীদের সরানো হবে।</string>
<string name="action_mute_domain">নিঃশব্দ %s</string> <string name="action_mute_domain">নিঃশব্দ %s</string>

View File

@ -389,7 +389,6 @@
<string name="mute_domain_warning_dialog_ok">পুরো ডোমেইন লুকান</string> <string name="mute_domain_warning_dialog_ok">পুরো ডোমেইন লুকান</string>
<string name="filter_dialog_whole_word">সম্পূর্ণ শব্দ</string> <string name="filter_dialog_whole_word">সম্পূর্ণ শব্দ</string>
<string name="filter_dialog_whole_word_description">যখন শব্দ বা বাক্যাংশটি শুধুমাত্র আলফানিউমেরিক হয় তখন এটি শুধুমাত্র তখনই প্রয়োগ করা হবে যদি এটি সম্পূর্ণ শব্দটির সাথে মেলে</string> <string name="filter_dialog_whole_word_description">যখন শব্দ বা বাক্যাংশটি শুধুমাত্র আলফানিউমেরিক হয় তখন এটি শুধুমাত্র তখনই প্রয়োগ করা হবে যদি এটি সম্পূর্ণ শব্দটির সাথে মেলে</string>
<string name="pref_title_show_notifications_filter">বিজ্ঞপ্তি ফিল্টার দেখান</string>
<string name="pref_title_alway_open_spoiler">সর্বদা সামগ্রী সতর্কতা সহ চিহ্নিত টুটগুলি প্রসারিত করুন</string> <string name="pref_title_alway_open_spoiler">সর্বদা সামগ্রী সতর্কতা সহ চিহ্নিত টুটগুলি প্রসারিত করুন</string>
<string name="title_accounts">অক্কোউন্টগুলি</string> <string name="title_accounts">অক্কোউন্টগুলি</string>
<string name="failed_search">অনুসন্ধান করতে ব্যর্থ</string> <string name="failed_search">অনুসন্ধান করতে ব্যর্থ</string>

View File

@ -397,7 +397,6 @@
<string name="failed_fetch_posts">Error obtenint els estats</string> <string name="failed_fetch_posts">Error obtenint els estats</string>
<string name="report_description_1">L\'informe s\'enviarà al moderador del teu servidor. Pots afegir una explicació del motiu d\'aquest informe del compte a sota:</string> <string name="report_description_1">L\'informe s\'enviarà al moderador del teu servidor. Pots afegir una explicació del motiu d\'aquest informe del compte a sota:</string>
<string name="title_accounts">Comptes</string> <string name="title_accounts">Comptes</string>
<string name="pref_title_show_notifications_filter">Mostrar el filtre de les notificacions</string>
<string name="mute_domain_warning">Estàs segur que vols bloquejar tot de %s\? No veuràs cap contingut de domini ni en els fils públics ni a les teves notificacions. Els teus seguidors d\'aquest domini seran eliminats.</string> <string name="mute_domain_warning">Estàs segur que vols bloquejar tot de %s\? No veuràs cap contingut de domini ni en els fils públics ni a les teves notificacions. Els teus seguidors d\'aquest domini seran eliminats.</string>
<string name="filter_dialog_whole_word_description">Quan la paraula o la frase siguin només alfanumèrica , només s\'aplicarà si coincideix amb tota la paraula</string> <string name="filter_dialog_whole_word_description">Quan la paraula o la frase siguin només alfanumèrica , només s\'aplicarà si coincideix amb tota la paraula</string>
<string name="report_sent_success">\@%s reportat satisfactoriament</string> <string name="report_sent_success">\@%s reportat satisfactoriament</string>

View File

@ -261,7 +261,6 @@
<string name="create_poll_title">ڕاپرسی</string> <string name="create_poll_title">ڕاپرسی</string>
<string name="pref_title_enable_swipe_for_tabs">چالاککردنی ئاماژەکردنی لێدانی چالاک بۆ گۆڕین لە نێوان خشتەبەندەکان</string> <string name="pref_title_enable_swipe_for_tabs">چالاککردنی ئاماژەکردنی لێدانی چالاک بۆ گۆڕین لە نێوان خشتەبەندەکان</string>
<string name="license_description">تاسکی کۆد و سەرمایەکانی تێدایە لەم پڕۆژە کراوەی سەرچاوە:</string> <string name="license_description">تاسکی کۆد و سەرمایەکانی تێدایە لەم پڕۆژە کراوەی سەرچاوە:</string>
<string name="pref_title_show_notifications_filter">فلتەری ئاگانامەکان نیشان بدە</string>
<string name="failed_search">گەڕانەکە سەرکەوتوو نەبوو</string> <string name="failed_search">گەڕانەکە سەرکەوتوو نەبوو</string>
<string name="title_accounts">ئەژمێرەکان</string> <string name="title_accounts">ئەژمێرەکان</string>
<string name="report_description_remote_instance">هەژمارەلە ڕاژەیەکی دیکەیە ترە. کۆپیەکی بێ سەروبەر بنێرە بۆ ڕاپۆرتەکە لەوێ؟</string> <string name="report_description_remote_instance">هەژمارەلە ڕاژەیەکی دیکەیە ترە. کۆپیەکی بێ سەروبەر بنێرە بۆ ڕاپۆرتەکە لەوێ؟</string>

View File

@ -423,7 +423,6 @@
<string name="failed_fetch_posts">Stahování příspěvků selhalo</string> <string name="failed_fetch_posts">Stahování příspěvků selhalo</string>
<string name="report_description_1">Nahlášení bude zasláno moderátorovi vašeho serveru. Níže můžete uvést, proč tento účet nahlašujete:</string> <string name="report_description_1">Nahlášení bude zasláno moderátorovi vašeho serveru. Níže můžete uvést, proč tento účet nahlašujete:</string>
<string name="report_description_remote_instance">Tento účet je z jiného serveru. Chcete na něj také poslat anonymizovanou kopii nahlášení\?</string> <string name="report_description_remote_instance">Tento účet je z jiného serveru. Chcete na něj také poslat anonymizovanou kopii nahlášení\?</string>
<string name="pref_title_show_notifications_filter">Zobrazit filtr oznámení</string>
<string name="create_poll_title">Anketa</string> <string name="create_poll_title">Anketa</string>
<string name="duration_5_min">5 minut</string> <string name="duration_5_min">5 minut</string>
<string name="duration_30_min">30 minut</string> <string name="duration_30_min">30 minut</string>

View File

@ -307,7 +307,6 @@
<string name="notification_clear_text">Ydych chi\'n siŵr eich bod chi am glirio\'ch holl hysbysiadau\'n barhaol\?</string> <string name="notification_clear_text">Ydych chi\'n siŵr eich bod chi am glirio\'ch holl hysbysiadau\'n barhaol\?</string>
<string name="error_multimedia_size_limit">Ni all ffeiliau fideo a sain fod yn fwy na %s MB.</string> <string name="error_multimedia_size_limit">Ni all ffeiliau fideo a sain fod yn fwy na %s MB.</string>
<string name="url_domain_notifier">%s (🔗 %s)</string> <string name="url_domain_notifier">%s (🔗 %s)</string>
<string name="pref_title_show_notifications_filter">Dangos yr hidlydd hysbysiadau</string>
<string name="error_following_hashtag_format">Gwall wrth ddilyn #%s</string> <string name="error_following_hashtag_format">Gwall wrth ddilyn #%s</string>
<string name="error_unfollowing_hashtag_format">Gwall wrth ddad-ddilyn #%s</string> <string name="error_unfollowing_hashtag_format">Gwall wrth ddad-ddilyn #%s</string>
<string name="action_unmute_domain">Dad-dewi %s</string> <string name="action_unmute_domain">Dad-dewi %s</string>
@ -732,4 +731,4 @@
<string name="about_copied">Copïwyd fersiwn a gwybodaeth dyfais</string> <string name="about_copied">Copïwyd fersiwn a gwybodaeth dyfais</string>
<string name="list_exclusive_label">Cuddio o\'r ffrwd cartref</string> <string name="list_exclusive_label">Cuddio o\'r ffrwd cartref</string>
<string name="error_media_playback">Methodd chwarae: %s</string> <string name="error_media_playback">Methodd chwarae: %s</string>
</resources> </resources>

View File

@ -395,7 +395,6 @@
<string name="failed_report">Melden fehlgeschlagen</string> <string name="failed_report">Melden fehlgeschlagen</string>
<string name="report_description_1">Die Meldung wird an die Moderator*innen deines Servers geschickt. Du kannst hier eine Erklärung angeben, warum du dieses Konto meldest:</string> <string name="report_description_1">Die Meldung wird an die Moderator*innen deines Servers geschickt. Du kannst hier eine Erklärung angeben, warum du dieses Konto meldest:</string>
<string name="report_description_remote_instance">Dieses Konto ist von einem anderen Server. Soll eine anonymisierte Kopie der Meldung auch dorthin geschickt werden\?</string> <string name="report_description_remote_instance">Dieses Konto ist von einem anderen Server. Soll eine anonymisierte Kopie der Meldung auch dorthin geschickt werden\?</string>
<string name="pref_title_show_notifications_filter">Benachrichtigungsfilter anzeigen</string>
<string name="create_poll_title">Umfrage</string> <string name="create_poll_title">Umfrage</string>
<string name="duration_5_min">5 Minuten</string> <string name="duration_5_min">5 Minuten</string>
<string name="duration_30_min">30 Minuten</string> <string name="duration_30_min">30 Minuten</string>
@ -683,4 +682,4 @@
<string name="about_copy">Version und Geräteinformationen kopieren</string> <string name="about_copy">Version und Geräteinformationen kopieren</string>
<string name="list_exclusive_label">Nicht in der Startseite anzeigen</string> <string name="list_exclusive_label">Nicht in der Startseite anzeigen</string>
<string name="error_media_upload_sending_fmt">Das Hochladen ist fehlgeschlagen: %s</string> <string name="error_media_upload_sending_fmt">Das Hochladen ist fehlgeschlagen: %s</string>
</resources> </resources>

View File

@ -403,7 +403,6 @@
<string name="failed_fetch_posts">Venigo de statusoj malsukcesis</string> <string name="failed_fetch_posts">Venigo de statusoj malsukcesis</string>
<string name="report_description_1">La signalo estos sendita al la kontrolantoj de via servilo. Vi povas doni klarigon pri kial vi signalas ĉi tiun konton sube:</string> <string name="report_description_1">La signalo estos sendita al la kontrolantoj de via servilo. Vi povas doni klarigon pri kial vi signalas ĉi tiun konton sube:</string>
<string name="report_description_remote_instance">La konto estas en alia servilo. Ĉu sendi sennomigitan kopion de la signalo ankaŭ tien\?</string> <string name="report_description_remote_instance">La konto estas en alia servilo. Ĉu sendi sennomigitan kopion de la signalo ankaŭ tien\?</string>
<string name="pref_title_show_notifications_filter">Montri filtrilon de sciigoj</string>
<string name="filter_dialog_whole_word">Tuta vorto</string> <string name="filter_dialog_whole_word">Tuta vorto</string>
<string name="filter_dialog_whole_word_description">Ŝlosilvorto aŭ frazo litercifera aplikiĝos, nur se ĝi kongruas kun la tuta vorto</string> <string name="filter_dialog_whole_word_description">Ŝlosilvorto aŭ frazo litercifera aplikiĝos, nur se ĝi kongruas kun la tuta vorto</string>
<string name="title_accounts">Kontoj</string> <string name="title_accounts">Kontoj</string>

View File

@ -431,7 +431,6 @@
<string name="failed_fetch_posts">Fallo al obtener estados</string> <string name="failed_fetch_posts">Fallo al obtener estados</string>
<string name="report_description_1">El reporte será enviado a un moderador de tu servidor. Puedes añadir una explicación de por qué estás reportando esta cuenta a continuación:</string> <string name="report_description_1">El reporte será enviado a un moderador de tu servidor. Puedes añadir una explicación de por qué estás reportando esta cuenta a continuación:</string>
<string name="report_description_remote_instance">La cuenta es de otro servidor. ¿Enviar una copia anónima del reporte\?</string> <string name="report_description_remote_instance">La cuenta es de otro servidor. ¿Enviar una copia anónima del reporte\?</string>
<string name="pref_title_show_notifications_filter">Mostrar filtro de notificaciones</string>
<string name="pref_title_alway_open_spoiler">Mostrar siempre publicaciones marcadas con avisos de contenido</string> <string name="pref_title_alway_open_spoiler">Mostrar siempre publicaciones marcadas con avisos de contenido</string>
<string name="title_accounts">Cuentas</string> <string name="title_accounts">Cuentas</string>
<string name="failed_search">Error al buscar</string> <string name="failed_search">Error al buscar</string>

View File

@ -417,7 +417,6 @@
<string name="report_description_remote_instance">Kontua beste zerbitzari batekoa da. Bidali txostenaren kopia anonimatua hara ere\?</string> <string name="report_description_remote_instance">Kontua beste zerbitzari batekoa da. Bidali txostenaren kopia anonimatua hara ere\?</string>
<string name="title_accounts">Kontuak</string> <string name="title_accounts">Kontuak</string>
<string name="failed_search">Bilaketa huts egin du</string> <string name="failed_search">Bilaketa huts egin du</string>
<string name="pref_title_show_notifications_filter">Erakutsi jakinarazpenen iragazkia</string>
<string name="create_poll_title">Inkesta</string> <string name="create_poll_title">Inkesta</string>
<string name="duration_5_min">5 minutu</string> <string name="duration_5_min">5 minutu</string>
<string name="duration_30_min">30 minutu</string> <string name="duration_30_min">30 minutu</string>

View File

@ -398,7 +398,6 @@
<string name="failed_fetch_posts">شکست در واکشی فرسته‌ها</string> <string name="failed_fetch_posts">شکست در واکشی فرسته‌ها</string>
<string name="title_accounts">حساب‌ها</string> <string name="title_accounts">حساب‌ها</string>
<string name="failed_search">شکست در جست‌وجو</string> <string name="failed_search">شکست در جست‌وجو</string>
<string name="pref_title_show_notifications_filter">نمایش پالایهٔ آگاهی‌ها</string>
<string name="create_poll_title">نظرسنجی</string> <string name="create_poll_title">نظرسنجی</string>
<string name="duration_5_min">۵ دقیقه</string> <string name="duration_5_min">۵ دقیقه</string>
<string name="duration_30_min">۳۰ دقیقه</string> <string name="duration_30_min">۳۰ دقیقه</string>
@ -684,4 +683,4 @@
<string name="about_copied">اطّلاعات افزاره و نگارش رونوشت شد</string> <string name="about_copied">اطّلاعات افزاره و نگارش رونوشت شد</string>
<string name="list_exclusive_label">نهفتن از خط زمانی خانگی</string> <string name="list_exclusive_label">نهفتن از خط زمانی خانگی</string>
<string name="error_media_playback">پخش شکست خورد: %s</string> <string name="error_media_playback">پخش شکست خورد: %s</string>
</resources> </resources>

View File

@ -422,7 +422,6 @@
<string name="mute_domain_warning">Êtes-vous sûr⋅e de vouloir bloquer %s en entier \? Vous ne verrez plus de contenu provenant de ce domaine, ni dans les fils publics, ni dans vos notifications. Vos abonné·e·s utilisant ce domaine seront retiré·e·s.</string> <string name="mute_domain_warning">Êtes-vous sûr⋅e de vouloir bloquer %s en entier \? Vous ne verrez plus de contenu provenant de ce domaine, ni dans les fils publics, ni dans vos notifications. Vos abonné·e·s utilisant ce domaine seront retiré·e·s.</string>
<string name="button_done">Terminé</string> <string name="button_done">Terminé</string>
<string name="report_description_remote_instance">Le compte provient dun autre serveur. Envoyez également une copie anonyme du rapport\?</string> <string name="report_description_remote_instance">Le compte provient dun autre serveur. Envoyez également une copie anonyme du rapport\?</string>
<string name="pref_title_show_notifications_filter">Montrer le filtre des notifications</string>
<string name="filter_dialog_whole_word">Mot entier</string> <string name="filter_dialog_whole_word">Mot entier</string>
<string name="filter_dialog_whole_word_description">Un mot-clé ou une phrase alphanumérique sera appliqué·e seulement sil ou elle correspond au mot entier</string> <string name="filter_dialog_whole_word_description">Un mot-clé ou une phrase alphanumérique sera appliqué·e seulement sil ou elle correspond au mot entier</string>
<string name="title_accounts">Comptes</string> <string name="title_accounts">Comptes</string>

View File

@ -439,7 +439,6 @@
<string name="report_description_remote_instance">Is ó fhreastalaí eile an cuntas. Seol cóip gan ainm den tuarascáil ansin freisin\?</string> <string name="report_description_remote_instance">Is ó fhreastalaí eile an cuntas. Seol cóip gan ainm den tuarascáil ansin freisin\?</string>
<string name="title_accounts">Cuntais</string> <string name="title_accounts">Cuntais</string>
<string name="failed_search">Theip ar chuardach</string> <string name="failed_search">Theip ar chuardach</string>
<string name="pref_title_show_notifications_filter">Taispeáin scagaire Fógraí</string>
<string name="pref_title_enable_swipe_for_tabs">Cumasaigh gotha swipe aistriú idir cluaisíní</string> <string name="pref_title_enable_swipe_for_tabs">Cumasaigh gotha swipe aistriú idir cluaisíní</string>
<string name="create_poll_title">Vótaíocht</string> <string name="create_poll_title">Vótaíocht</string>
<string name="duration_5_min">5 nóiméid</string> <string name="duration_5_min">5 nóiméid</string>

View File

@ -109,7 +109,6 @@
<string name="add_poll_choice">Cuir roghainn ris</string> <string name="add_poll_choice">Cuir roghainn ris</string>
<string name="create_poll_title">Cunntas-bheachd</string> <string name="create_poll_title">Cunntas-bheachd</string>
<string name="pref_title_enable_swipe_for_tabs">Cuir an comas gluasad grad-shlaighdidh airson leum a ghearradh o thaba gu taba</string> <string name="pref_title_enable_swipe_for_tabs">Cuir an comas gluasad grad-shlaighdidh airson leum a ghearradh o thaba gu taba</string>
<string name="pref_title_show_notifications_filter">Seall criathrag nam brathan</string>
<string name="failed_search">Dhfhàillig leis an lorg</string> <string name="failed_search">Dhfhàillig leis an lorg</string>
<string name="title_accounts">Cunntasan</string> <string name="title_accounts">Cunntasan</string>
<string name="report_description_remote_instance">Chaidh an cunntas a chlàradh air frithealaiche eile. A bheil thu airson lethbhreac dhen ghearan a chur dha-san gun ainm cuideachd\?</string> <string name="report_description_remote_instance">Chaidh an cunntas a chlàradh air frithealaiche eile. A bheil thu airson lethbhreac dhen ghearan a chur dha-san gun ainm cuideachd\?</string>
@ -700,4 +699,4 @@
<string name="about_copied">Chaidh lethbhreac de thionndadh is fiosrachadh an uidheim a dhèanamh</string> <string name="about_copied">Chaidh lethbhreac de thionndadh is fiosrachadh an uidheim a dhèanamh</string>
<string name="list_exclusive_label">Falaich o loidhne-ama na dachaigh</string> <string name="list_exclusive_label">Falaich o loidhne-ama na dachaigh</string>
<string name="error_media_upload_sending_fmt">Dhfhàillig leis an luchdadh suas: %s</string> <string name="error_media_upload_sending_fmt">Dhfhàillig leis an luchdadh suas: %s</string>
</resources> </resources>

View File

@ -128,7 +128,6 @@
<string name="label_duration">Duración</string> <string name="label_duration">Duración</string>
<string name="create_poll_title">Enquisa</string> <string name="create_poll_title">Enquisa</string>
<string name="pref_title_enable_swipe_for_tabs">Activar xestos de desprazamento para moverse entre lapelas</string> <string name="pref_title_enable_swipe_for_tabs">Activar xestos de desprazamento para moverse entre lapelas</string>
<string name="pref_title_show_notifications_filter">Mostrar filtro das notificacións</string>
<string name="failed_search">Fallou a busca</string> <string name="failed_search">Fallou a busca</string>
<string name="title_accounts">Contas</string> <string name="title_accounts">Contas</string>
<string name="report_description_remote_instance">A conta pertence a outro servidor. Queres enviar unha copia anónima da denuncia alí tamén\?</string> <string name="report_description_remote_instance">A conta pertence a outro servidor. Queres enviar unha copia anónima da denuncia alí tamén\?</string>

View File

@ -256,7 +256,6 @@
<string name="no_drafts">आपके पास कोई ड्राफ्ट नहीं है।</string> <string name="no_drafts">आपके पास कोई ड्राफ्ट नहीं है।</string>
<string name="post_lookup_error_format">%s पोस्ट खोजने में त्रुटि</string> <string name="post_lookup_error_format">%s पोस्ट खोजने में त्रुटि</string>
<string name="pref_title_enable_swipe_for_tabs">टैब के बीच स्विच करने के लिए स्वाइप जेस्चर को सक्षम करें</string> <string name="pref_title_enable_swipe_for_tabs">टैब के बीच स्विच करने के लिए स्वाइप जेस्चर को सक्षम करें</string>
<string name="pref_title_show_notifications_filter">सूचना फ़िल्टर दिखाएं</string>
<string name="failed_search">खोज करने में विफल</string> <string name="failed_search">खोज करने में विफल</string>
<string name="report_description_remote_instance">खाता किसी अन्य सर्वर से है। रिपोर्ट की अनाम प्रति वहां भी भेजें\?</string> <string name="report_description_remote_instance">खाता किसी अन्य सर्वर से है। रिपोर्ट की अनाम प्रति वहां भी भेजें\?</string>
<string name="report_description_1">रिपोर्ट आपके सर्वर मॉडरेटर को भेजी जाएगी। आप इस बारे में स्पष्टीकरण दे सकते हैं कि आप इस खाते को रिपोर्ट क्यों कर रहे हैं:</string> <string name="report_description_1">रिपोर्ट आपके सर्वर मॉडरेटर को भेजी जाएगी। आप इस बारे में स्पष्टीकरण दे सकते हैं कि आप इस खाते को रिपोर्ट क्यों कर रहे हैं:</string>

View File

@ -412,7 +412,6 @@
<string name="failed_fetch_posts">Sikertelen a bejegyzések letöltése</string> <string name="failed_fetch_posts">Sikertelen a bejegyzések letöltése</string>
<string name="report_description_1">A bejelentést a szervered moderátorának küldjük el. Alább megadhatsz egy magyarázatot arra, hogy miért jelented be ezt a fiókot:</string> <string name="report_description_1">A bejelentést a szervered moderátorának küldjük el. Alább megadhatsz egy magyarázatot arra, hogy miért jelented be ezt a fiókot:</string>
<string name="report_description_remote_instance">A fiók egy másik szerverről származik. Küldjünk oda is egy anonimizált másolatot a bejelentésről\?</string> <string name="report_description_remote_instance">A fiók egy másik szerverről származik. Küldjünk oda is egy anonimizált másolatot a bejelentésről\?</string>
<string name="pref_title_show_notifications_filter">Értesítések szűrőjének mutatása</string>
<string name="pref_title_alway_open_spoiler">Tartalomfigyelmeztetéssel ellátott bejegyzések kinyitása mindig</string> <string name="pref_title_alway_open_spoiler">Tartalomfigyelmeztetéssel ellátott bejegyzések kinyitása mindig</string>
<string name="title_accounts">Fiókok</string> <string name="title_accounts">Fiókok</string>
<string name="failed_search">Sikertelen keresés</string> <string name="failed_search">Sikertelen keresés</string>

View File

@ -396,7 +396,6 @@
<string name="report_description_remote_instance">Notandaaðgangurinn er af öðrum vefþjóni. Á einnig að senda nafnlaust afrit af kærunni þangað\?</string> <string name="report_description_remote_instance">Notandaaðgangurinn er af öðrum vefþjóni. Á einnig að senda nafnlaust afrit af kærunni þangað\?</string>
<string name="title_accounts">Notandaaðgangar</string> <string name="title_accounts">Notandaaðgangar</string>
<string name="failed_search">Tókst ekki að leita</string> <string name="failed_search">Tókst ekki að leita</string>
<string name="pref_title_show_notifications_filter">Birta tilkynningasíu</string>
<string name="create_poll_title">Athuga</string> <string name="create_poll_title">Athuga</string>
<string name="duration_5_min">5 mínútur</string> <string name="duration_5_min">5 mínútur</string>
<string name="duration_30_min">30 mínútur</string> <string name="duration_30_min">30 mínútur</string>

View File

@ -439,7 +439,6 @@
<string name="report_description_remote_instance">L\'utente è su un altro server. Mandare una copia della segnalazione anche lì\?</string> <string name="report_description_remote_instance">L\'utente è su un altro server. Mandare una copia della segnalazione anche lì\?</string>
<string name="title_accounts">Utenti</string> <string name="title_accounts">Utenti</string>
<string name="failed_search">Errore durante la ricerca</string> <string name="failed_search">Errore durante la ricerca</string>
<string name="pref_title_show_notifications_filter">Mostra il filtro delle notifiche</string>
<string name="create_poll_title">Sondaggio</string> <string name="create_poll_title">Sondaggio</string>
<string name="duration_5_min">5 minuti</string> <string name="duration_5_min">5 minuti</string>
<string name="duration_30_min">30 minuti</string> <string name="duration_30_min">30 minuti</string>

View File

@ -389,7 +389,6 @@
<string name="poll_info_closed">投票終了</string> <string name="poll_info_closed">投票終了</string>
<string name="title_accounts">アカウント</string> <string name="title_accounts">アカウント</string>
<string name="failed_search">検索に失敗しました</string> <string name="failed_search">検索に失敗しました</string>
<string name="pref_title_show_notifications_filter">通知フィルターを表示</string>
<string name="action_reset_schedule">リセット</string> <string name="action_reset_schedule">リセット</string>
<string name="title_bookmarks">ブックマーク</string> <string name="title_bookmarks">ブックマーク</string>
<string name="action_bookmark">ブックマーク</string> <string name="action_bookmark">ブックマーク</string>

View File

@ -402,7 +402,6 @@
<string name="failed_fetch_posts">게시물을 불러오지 못했습니다</string> <string name="failed_fetch_posts">게시물을 불러오지 못했습니다</string>
<string name="report_description_1">인스턴스 관리자에게 신고합니다. 이 계정을 신고하려는 이유를 작성하실 수 있습니다:</string> <string name="report_description_1">인스턴스 관리자에게 신고합니다. 이 계정을 신고하려는 이유를 작성하실 수 있습니다:</string>
<string name="report_description_remote_instance">이 유저는 다른 인스턴스에 속해 있습니다. 그 인스턴스에도 익명으로 신고 내용을 보내시겠습니까\?</string> <string name="report_description_remote_instance">이 유저는 다른 인스턴스에 속해 있습니다. 그 인스턴스에도 익명으로 신고 내용을 보내시겠습니까\?</string>
<string name="pref_title_show_notifications_filter">알림 필터 보이기</string>
<string name="action_open_as">%s(으)로 열기</string> <string name="action_open_as">%s(으)로 열기</string>
<string name="title_accounts">계정</string> <string name="title_accounts">계정</string>
<string name="failed_search">검색하지 못했습니다</string> <string name="failed_search">검색하지 못했습니다</string>

View File

@ -425,7 +425,6 @@
<string name="pref_title_show_self_username">Rādīt lietotājvārdu rīkjoslās</string> <string name="pref_title_show_self_username">Rādīt lietotājvārdu rīkjoslās</string>
<string name="pref_title_confirm_reblogs">Pirms pastiprināšanas rādīt apstiprināšanas dialogu</string> <string name="pref_title_confirm_reblogs">Pirms pastiprināšanas rādīt apstiprināšanas dialogu</string>
<string name="failed_search">Meklēšana neizdevās</string> <string name="failed_search">Meklēšana neizdevās</string>
<string name="pref_title_show_notifications_filter">Rādīt paziņojumu filtru</string>
<string name="pref_title_enable_swipe_for_tabs">Iespējot vilkšanas žestu, lai pārslēgtos starp cilnēm</string> <string name="pref_title_enable_swipe_for_tabs">Iespējot vilkšanas žestu, lai pārslēgtos starp cilnēm</string>
<string name="pref_title_hide_top_toolbar">Paslēpt augšējās rīkjoslas virsrakstu</string> <string name="pref_title_hide_top_toolbar">Paslēpt augšējās rīkjoslas virsrakstu</string>
<string name="pref_title_notification_filter_reports">iesniegts jauns ziņojums</string> <string name="pref_title_notification_filter_reports">iesniegts jauns ziņojums</string>

View File

@ -404,7 +404,6 @@
<string name="confirmation_domain_unmuted">%s er ikke lenger skjult</string> <string name="confirmation_domain_unmuted">%s er ikke lenger skjult</string>
<string name="mute_domain_warning">Er du sikker på at du vil blokkere alt fra %s\? Du kommer ikke til å se innhold fra domenet i noen offentlige tidslinjer, eller i varslene dine. Kontoer som følger deg fra dette domenet vil bli fjernet.</string> <string name="mute_domain_warning">Er du sikker på at du vil blokkere alt fra %s\? Du kommer ikke til å se innhold fra domenet i noen offentlige tidslinjer, eller i varslene dine. Kontoer som følger deg fra dette domenet vil bli fjernet.</string>
<string name="mute_domain_warning_dialog_ok">Skjul hele domenet</string> <string name="mute_domain_warning_dialog_ok">Skjul hele domenet</string>
<string name="pref_title_show_notifications_filter">Vis varselfilter</string>
<string name="filter_dialog_whole_word">Helt ord</string> <string name="filter_dialog_whole_word">Helt ord</string>
<string name="filter_dialog_whole_word_description">Når nøkkelordet eller frasen kun inneholder bokstaver og tall, vil det bare brukes dersom det stemmer overens med hele ordet</string> <string name="filter_dialog_whole_word_description">Når nøkkelordet eller frasen kun inneholder bokstaver og tall, vil det bare brukes dersom det stemmer overens med hele ordet</string>
<string name="title_accounts">Kontoer</string> <string name="title_accounts">Kontoer</string>

View File

@ -411,7 +411,6 @@
<string name="failed_fetch_posts">Het ophalen van berichten is mislukt</string> <string name="failed_fetch_posts">Het ophalen van berichten is mislukt</string>
<string name="report_description_1">Deze rapportage wordt naar jouw servermoderator(en) gestuurd. Je kunt hieronder een uitleg geven over waarom je het account wilt rapporteren:</string> <string name="report_description_1">Deze rapportage wordt naar jouw servermoderator(en) gestuurd. Je kunt hieronder een uitleg geven over waarom je het account wilt rapporteren:</string>
<string name="report_description_remote_instance">Het account is van een andere server. Wil je ook een geanonimiseerde kopie van de rapportage daarnaartoe sturen\?</string> <string name="report_description_remote_instance">Het account is van een andere server. Wil je ook een geanonimiseerde kopie van de rapportage daarnaartoe sturen\?</string>
<string name="pref_title_show_notifications_filter">Meldingenfilter tonen</string>
<string name="filter_dialog_whole_word">Heel woord</string> <string name="filter_dialog_whole_word">Heel woord</string>
<string name="filter_dialog_whole_word_description">Wanneer het trefwoord of zinsdeel alfanumeriek is, wordt het alleen gefilterd wanneer het hele woord overeenkomt</string> <string name="filter_dialog_whole_word_description">Wanneer het trefwoord of zinsdeel alfanumeriek is, wordt het alleen gefilterd wanneer het hele woord overeenkomt</string>
<string name="duration_5_min">5 minuten</string> <string name="duration_5_min">5 minuten</string>
@ -664,4 +663,4 @@
<string name="about_copied">Versie en apparaatinformatie gekopieerd</string> <string name="about_copied">Versie en apparaatinformatie gekopieerd</string>
<string name="error_media_upload_sending_fmt">De upload is mislukt: %s</string> <string name="error_media_upload_sending_fmt">De upload is mislukt: %s</string>
<string name="socket_timeout_exception">Contact zoeken met je server duurde te lang</string> <string name="socket_timeout_exception">Contact zoeken met je server duurde te lang</string>
</resources> </resources>

View File

@ -411,7 +411,6 @@
<string name="confirmation_domain_unmuted">%s es pas mai rescondut</string> <string name="confirmation_domain_unmuted">%s es pas mai rescondut</string>
<string name="mute_domain_warning">Volètz vertadièrament blocar complètament %s\? Veiretz pas mai de contengut venent daqueste domeni, nimai los flux dactualitat o las notificacion. Vòstres seguidors daqueste domeni seràn tirats.</string> <string name="mute_domain_warning">Volètz vertadièrament blocar complètament %s\? Veiretz pas mai de contengut venent daqueste domeni, nimai los flux dactualitat o las notificacion. Vòstres seguidors daqueste domeni seràn tirats.</string>
<string name="mute_domain_warning_dialog_ok">Rescondre tot lo domeni</string> <string name="mute_domain_warning_dialog_ok">Rescondre tot lo domeni</string>
<string name="pref_title_show_notifications_filter">Mostrar lo filtre de las notificacions</string>
<string name="filter_dialog_whole_word">Mot complèt</string> <string name="filter_dialog_whole_word">Mot complèt</string>
<string name="filter_dialog_whole_word_description">Quand un mot clau o una frasa es solament alfanumeric, serà pas quaplicat se correspond al mot complèt</string> <string name="filter_dialog_whole_word_description">Quand un mot clau o una frasa es solament alfanumeric, serà pas quaplicat se correspond al mot complèt</string>
<string name="pref_title_alway_open_spoiler">Totjorn desplegar las publicacions marcadas amb un avertiment de contengut</string> <string name="pref_title_alway_open_spoiler">Totjorn desplegar las publicacions marcadas amb un avertiment de contengut</string>

View File

@ -440,7 +440,6 @@
<string name="report_description_remote_instance">To konto jest na innym serwerze. Czy przesłać anonimizowaną kopię zgłoszenia na ten serwer\?</string> <string name="report_description_remote_instance">To konto jest na innym serwerze. Czy przesłać anonimizowaną kopię zgłoszenia na ten serwer\?</string>
<string name="title_accounts">Konta</string> <string name="title_accounts">Konta</string>
<string name="failed_search">Wyszukiwanie nie powidło się</string> <string name="failed_search">Wyszukiwanie nie powidło się</string>
<string name="pref_title_show_notifications_filter">Pokaż filtr powiadomień</string>
<string name="create_poll_title">Głosowanie</string> <string name="create_poll_title">Głosowanie</string>
<string name="duration_5_min">5 minut</string> <string name="duration_5_min">5 minut</string>
<string name="duration_30_min">30 minut</string> <string name="duration_30_min">30 minut</string>

View File

@ -422,7 +422,6 @@
<string name="confirmation_domain_unmuted">%s desbloqueada</string> <string name="confirmation_domain_unmuted">%s desbloqueada</string>
<string name="mute_domain_warning">Tem certeza de que deseja bloquear tudo de %s\? Você não verá mais o conteúdo desta instância em nenhuma linha do tempo pública ou nas suas notificações. Seus seguidores desta instância serão removidos.</string> <string name="mute_domain_warning">Tem certeza de que deseja bloquear tudo de %s\? Você não verá mais o conteúdo desta instância em nenhuma linha do tempo pública ou nas suas notificações. Seus seguidores desta instância serão removidos.</string>
<string name="mute_domain_warning_dialog_ok">Bloquear instância</string> <string name="mute_domain_warning_dialog_ok">Bloquear instância</string>
<string name="pref_title_show_notifications_filter">Mostrar filtro de notificações</string>
<string name="filter_dialog_whole_word">Toda palavra</string> <string name="filter_dialog_whole_word">Toda palavra</string>
<string name="filter_dialog_whole_word_description">Se for apenas alfanumérico, só se aplicará se combinar com a palavra inteira</string> <string name="filter_dialog_whole_word_description">Se for apenas alfanumérico, só se aplicará se combinar com a palavra inteira</string>
<string name="action_add_poll">Adicionar enquete</string> <string name="action_add_poll">Adicionar enquete</string>

View File

@ -467,7 +467,6 @@
<string name="report_description_remote_instance">A conta está noutra instância. Quer enviar uma cópia anónima da denúncia para lá\?</string> <string name="report_description_remote_instance">A conta está noutra instância. Quer enviar uma cópia anónima da denúncia para lá\?</string>
<string name="title_accounts">Contas</string> <string name="title_accounts">Contas</string>
<string name="failed_search">Erro ao pesquisar</string> <string name="failed_search">Erro ao pesquisar</string>
<string name="pref_title_show_notifications_filter">Mostrar Filtro das Notificações</string>
<string name="pref_title_enable_swipe_for_tabs">Ativar gesto de deslizar para alternar entre separadores</string> <string name="pref_title_enable_swipe_for_tabs">Ativar gesto de deslizar para alternar entre separadores</string>
<string name="create_poll_title">Votação</string> <string name="create_poll_title">Votação</string>
<string name="label_duration">Duração</string> <string name="label_duration">Duração</string>

View File

@ -433,7 +433,6 @@
<string name="failed_fetch_posts">Не удалось получить статусы</string> <string name="failed_fetch_posts">Не удалось получить статусы</string>
<string name="report_description_1">Жалоба будет отправлена модератору вашего узла. Ниже вы можете добавить пояснение о причинах жалобы:</string> <string name="report_description_1">Жалоба будет отправлена модератору вашего узла. Ниже вы можете добавить пояснение о причинах жалобы:</string>
<string name="report_description_remote_instance">Этот аккаунт расположен на другом узле. Отправить анонимную копию жалобы туда\?</string> <string name="report_description_remote_instance">Этот аккаунт расположен на другом узле. Отправить анонимную копию жалобы туда\?</string>
<string name="pref_title_show_notifications_filter">Показать фильтр уведомлений</string>
<string name="action_add_poll">Создать опрос</string> <string name="action_add_poll">Создать опрос</string>
<string name="pref_title_alway_open_spoiler">Всегда разворачивать посты с предупреждением о содержимом</string> <string name="pref_title_alway_open_spoiler">Всегда разворачивать посты с предупреждением о содержимом</string>
<string name="title_accounts">Аккаунты</string> <string name="title_accounts">Аккаунты</string>

View File

@ -378,7 +378,6 @@
<string name="duration_5_min">५ निमेषाः</string> <string name="duration_5_min">५ निमेषाः</string>
<string name="create_poll_title">मतपेटिका</string> <string name="create_poll_title">मतपेटिका</string>
<string name="pref_title_enable_swipe_for_tabs">सारणहावभावस्य संयुतनं पीठिकापरिवर्तनार्थं कार्यम्</string> <string name="pref_title_enable_swipe_for_tabs">सारणहावभावस्य संयुतनं पीठिकापरिवर्तनार्थं कार्यम्</string>
<string name="pref_title_show_notifications_filter">सूचनाशोधकं दृश्यताम्</string>
<string name="failed_search">अन्वेषणे विफलता जाता</string> <string name="failed_search">अन्वेषणे विफलता जाता</string>
<string name="title_accounts">व्यक्तित्वविवरणलेखाः</string> <string name="title_accounts">व्यक्तित्वविवरणलेखाः</string>
<string name="report_description_remote_instance">अन्यजालवितारकादियं व्यक्तित्वविवरणलेखा । आवेदनस्य रक्षितप्रतिलिपिरपि प्रेष्यतां वा \?</string> <string name="report_description_remote_instance">अन्यजालवितारकादियं व्यक्तित्वविवरणलेखा । आवेदनस्य रक्षितप्रतिलिपिरपि प्रेष्यतां वा \?</string>

View File

@ -48,7 +48,6 @@
<string name="hint_display_name">දර්ශන නාමය</string> <string name="hint_display_name">දර්ශන නාමය</string>
<string name="post_text_size_medium">මධ්‍යම</string> <string name="post_text_size_medium">මධ්‍යම</string>
<string name="post_media_audio">ශ්‍රව්‍ය</string> <string name="post_media_audio">ශ්‍රව්‍ය</string>
<string name="pref_title_show_notifications_filter">දැනුම්දීම් පෙරහන පෙන්වන්න</string>
<string name="abbreviated_days_ago">දව. %d</string> <string name="abbreviated_days_ago">දව. %d</string>
<string name="action_logout">නික්මෙන්න</string> <string name="action_logout">නික්මෙන්න</string>
<string name="filter_edit_title">පෙරහන සංස්කරණය</string> <string name="filter_edit_title">පෙරහන සංස්කරණය</string>
@ -268,4 +267,4 @@
<string name="pref_title_browser_settings">අතිරික්සුව</string> <string name="pref_title_browser_settings">අතිරික්සුව</string>
<string name="abbreviated_seconds_ago">තත්. %d</string> <string name="abbreviated_seconds_ago">තත්. %d</string>
<string name="url_domain_notifier">%s (🔗 %s)</string> <string name="url_domain_notifier">%s (🔗 %s)</string>
</resources> </resources>

View File

@ -407,7 +407,6 @@
<string name="confirmation_domain_unmuted">Domena %s odrita</string> <string name="confirmation_domain_unmuted">Domena %s odrita</string>
<string name="mute_domain_warning">Ali ste prepričani, da želite blokirati vse iz domene %s\? Vsebine iz te domene ne boste videli v nobeni javni časovnici ali v obvestilih. Vaši sledilci iz te domene bodo odstranjeni.</string> <string name="mute_domain_warning">Ali ste prepričani, da želite blokirati vse iz domene %s\? Vsebine iz te domene ne boste videli v nobeni javni časovnici ali v obvestilih. Vaši sledilci iz te domene bodo odstranjeni.</string>
<string name="mute_domain_warning_dialog_ok">Skrij celotno domeno</string> <string name="mute_domain_warning_dialog_ok">Skrij celotno domeno</string>
<string name="pref_title_show_notifications_filter">Pokaži filtre obvestil</string>
<string name="filter_dialog_whole_word">Cela beseda</string> <string name="filter_dialog_whole_word">Cela beseda</string>
<string name="filter_dialog_whole_word_description">Če je ključna beseda ali fraza samo alfanumerična, bo uporabljena le, če se ujema s celotno besedo</string> <string name="filter_dialog_whole_word_description">Če je ključna beseda ali fraza samo alfanumerična, bo uporabljena le, če se ujema s celotno besedo</string>
<string name="title_accounts">Računi</string> <string name="title_accounts">Računi</string>

View File

@ -418,7 +418,6 @@
<string name="failed_fetch_posts">Misslyckades att hämta status</string> <string name="failed_fetch_posts">Misslyckades att hämta status</string>
<string name="report_description_1">Anmälan kommer att skickas till din servermoderator. Du kan beskriva varför du anmäler kontot nedan:</string> <string name="report_description_1">Anmälan kommer att skickas till din servermoderator. Du kan beskriva varför du anmäler kontot nedan:</string>
<string name="report_description_remote_instance">Kontot är från en annan server. Skicka en anonym kopia av anmälan dit också\?</string> <string name="report_description_remote_instance">Kontot är från en annan server. Skicka en anonym kopia av anmälan dit också\?</string>
<string name="pref_title_show_notifications_filter">Visa notifikationsfilter</string>
<string name="filter_dialog_whole_word">Helt ord</string> <string name="filter_dialog_whole_word">Helt ord</string>
<string name="filter_dialog_whole_word_description">När nyckelordet eller frasen enbart är alfanumerisk, appliceras den om den matchar hela ordet</string> <string name="filter_dialog_whole_word_description">När nyckelordet eller frasen enbart är alfanumerisk, appliceras den om den matchar hela ordet</string>
<string name="pref_title_alway_open_spoiler">Expandera alltid inlägg med innehållsvarningar</string> <string name="pref_title_alway_open_spoiler">Expandera alltid inlägg med innehållsvarningar</string>

View File

@ -10,7 +10,6 @@
<string name="duration_5_min">5 นาที</string> <string name="duration_5_min">5 นาที</string>
<string name="create_poll_title">โพล</string> <string name="create_poll_title">โพล</string>
<string name="pref_title_enable_swipe_for_tabs">เปิดใช้งานการเลื่อนนิ้วเพื่อสลับระหว่างแท็บ</string> <string name="pref_title_enable_swipe_for_tabs">เปิดใช้งานการเลื่อนนิ้วเพื่อสลับระหว่างแท็บ</string>
<string name="pref_title_show_notifications_filter">แสดงตัวกรองการแจ้งเตือน</string>
<string name="failed_search">ค้นหาล้มเหลว</string> <string name="failed_search">ค้นหาล้มเหลว</string>
<string name="title_accounts">บัญชี</string> <string name="title_accounts">บัญชี</string>
<string name="report_description_remote_instance">บัญชีนี้มาจากเซิร์ฟเวอร์อื่น ส่งสำเนารายงานที่ไม่ระบุชื่อไปที่นั่นด้วยหรือไม่\?</string> <string name="report_description_remote_instance">บัญชีนี้มาจากเซิร์ฟเวอร์อื่น ส่งสำเนารายงานที่ไม่ระบุชื่อไปที่นั่นด้วยหรือไม่\?</string>

View File

@ -395,7 +395,6 @@
<string name="failed_fetch_posts">Yayınlar getirilemedi</string> <string name="failed_fetch_posts">Yayınlar getirilemedi</string>
<string name="report_description_1">Bildirim sunucu yöneticinize gönderilecektir. Bu hesabı neden bildirdiğinizle ilgili açıklama yapabilirsiniz:</string> <string name="report_description_1">Bildirim sunucu yöneticinize gönderilecektir. Bu hesabı neden bildirdiğinizle ilgili açıklama yapabilirsiniz:</string>
<string name="report_description_remote_instance">Hesap başka bir sunucudan. Raporun anonim bir kopyasını da oraya gönderilsin mi\?</string> <string name="report_description_remote_instance">Hesap başka bir sunucudan. Raporun anonim bir kopyasını da oraya gönderilsin mi\?</string>
<string name="pref_title_show_notifications_filter">Bildirim süzgecini göster</string>
<string name="action_mentions">Bahsedenler</string> <string name="action_mentions">Bahsedenler</string>
<string name="action_open_reblogger">Gönderi yazanını</string> <string name="action_open_reblogger">Gönderi yazanını</string>
<string name="action_open_reblogged_by">Yeniden paylaşımları göster</string> <string name="action_open_reblogged_by">Yeniden paylaşımları göster</string>
@ -684,4 +683,4 @@
<string name="about_copied">Kopyalanan sürüm ve cihaz bilgileri</string> <string name="about_copied">Kopyalanan sürüm ve cihaz bilgileri</string>
<string name="list_exclusive_label">Anasayfa ağ akışından gizle</string> <string name="list_exclusive_label">Anasayfa ağ akışından gizle</string>
<string name="error_media_playback">Oynatma başarısız oldu: %s</string> <string name="error_media_playback">Oynatma başarısız oldu: %s</string>
</resources> </resources>

View File

@ -473,7 +473,6 @@
<string name="no_drafts">У вас немає чернеток.</string> <string name="no_drafts">У вас немає чернеток.</string>
<string name="post_lookup_error_format">Помилка пошуку допису %s</string> <string name="post_lookup_error_format">Помилка пошуку допису %s</string>
<string name="pref_title_enable_swipe_for_tabs">Увімкнути перемикання між вкладками жестом проведення пальцем</string> <string name="pref_title_enable_swipe_for_tabs">Увімкнути перемикання між вкладками жестом проведення пальцем</string>
<string name="pref_title_show_notifications_filter">Показати фільтр сповіщень</string>
<string name="failed_search">Не вдалося здійснити пошук</string> <string name="failed_search">Не вдалося здійснити пошук</string>
<string name="report_description_remote_instance">Обліковий запис з іншого сервера. Надіслати анонімізовану копію звіту й туди\?</string> <string name="report_description_remote_instance">Обліковий запис з іншого сервера. Надіслати анонімізовану копію звіту й туди\?</string>
<string name="report_description_1">Скаргу буде надіслано вашому модератору сервера. Ви можете надати пояснення, чому ви повідомляєте про цей обліковий запис знизу:</string> <string name="report_description_1">Скаргу буде надіслано вашому модератору сервера. Ви можете надати пояснення, чому ви повідомляєте про цей обліковий запис знизу:</string>

View File

@ -324,7 +324,6 @@
<string name="duration_5_min">5 phút</string> <string name="duration_5_min">5 phút</string>
<string name="create_poll_title">Bình chọn</string> <string name="create_poll_title">Bình chọn</string>
<string name="pref_title_enable_swipe_for_tabs">Vuốt qua lại giữa các tab</string> <string name="pref_title_enable_swipe_for_tabs">Vuốt qua lại giữa các tab</string>
<string name="pref_title_show_notifications_filter">Hiện bộ lọc thông báo</string>
<string name="failed_search">Không thể tìm thấy</string> <string name="failed_search">Không thể tìm thấy</string>
<string name="title_accounts">Người</string> <string name="title_accounts">Người</string>
<string name="report_description_remote_instance">Người này thuộc máy chủ khác. Gửi luôn cho máy chủ đó\?</string> <string name="report_description_remote_instance">Người này thuộc máy chủ khác. Gửi luôn cho máy chủ đó\?</string>
@ -666,4 +665,4 @@
<string name="about_device_info_title">Thiết bị của bạn</string> <string name="about_device_info_title">Thiết bị của bạn</string>
<string name="list_exclusive_label">Ẩn khỏi bảng tin</string> <string name="list_exclusive_label">Ẩn khỏi bảng tin</string>
<string name="error_media_playback">Không thể phát: %s</string> <string name="error_media_playback">Không thể phát: %s</string>
</resources> </resources>

View File

@ -421,7 +421,6 @@
<string name="report_description_remote_instance">该账户来自其他服务器。向那里发送一份匿名的报告副本?</string> <string name="report_description_remote_instance">该账户来自其他服务器。向那里发送一份匿名的报告副本?</string>
<string name="title_accounts">账户</string> <string name="title_accounts">账户</string>
<string name="failed_search">搜索失败</string> <string name="failed_search">搜索失败</string>
<string name="pref_title_show_notifications_filter">显示通知过滤器</string>
<string name="create_poll_title">投票</string> <string name="create_poll_title">投票</string>
<string name="duration_5_min">5 分钟</string> <string name="duration_5_min">5 分钟</string>
<string name="duration_30_min">30 分钟</string> <string name="duration_30_min">30 分钟</string>
@ -680,4 +679,4 @@
<string name="about_copy">复制版本及设备信息</string> <string name="about_copy">复制版本及设备信息</string>
<string name="list_exclusive_label">不出现在首页时间线中</string> <string name="list_exclusive_label">不出现在首页时间线中</string>
<string name="error_media_playback">播放失败了:%s</string> <string name="error_media_playback">播放失败了:%s</string>
</resources> </resources>

View File

@ -471,7 +471,6 @@
<string name="label_duration">期間</string> <string name="label_duration">期間</string>
<string name="create_poll_title">投票</string> <string name="create_poll_title">投票</string>
<string name="pref_title_enable_swipe_for_tabs">啟用在分頁間切換的滑動手勢</string> <string name="pref_title_enable_swipe_for_tabs">啟用在分頁間切換的滑動手勢</string>
<string name="pref_title_show_notifications_filter">顯示通知過濾器</string>
<string name="failed_search">搜尋失敗</string> <string name="failed_search">搜尋失敗</string>
<string name="title_accounts">帳號</string> <string name="title_accounts">帳號</string>
<string name="failed_fetch_posts">擷取狀態失敗</string> <string name="failed_fetch_posts">擷取狀態失敗</string>

View File

@ -426,7 +426,6 @@
<string name="failed_fetch_posts">無法獲取狀態</string> <string name="failed_fetch_posts">無法獲取狀態</string>
<string name="report_description_1">該報告將發送給您的伺服器管理員。 您可以在下面提供有關回報此帳戶的原因的說明:</string> <string name="report_description_1">該報告將發送給您的伺服器管理員。 您可以在下面提供有關回報此帳戶的原因的說明:</string>
<string name="report_description_remote_instance">該帳戶來自其他伺服器。向那裡發送一份匿名的報告副本?</string> <string name="report_description_remote_instance">該帳戶來自其他伺服器。向那裡發送一份匿名的報告副本?</string>
<string name="pref_title_show_notifications_filter">顯示通知過濾器</string>
<string name="hashtags">話題</string> <string name="hashtags">話題</string>
<string name="notification_follow_request_name">關注請求</string> <string name="notification_follow_request_name">關注請求</string>
<string name="edit_poll">編輯</string> <string name="edit_poll">編輯</string>

View File

@ -610,8 +610,8 @@
<string name="error_list_load">Error loading lists</string> <string name="error_list_load">Error loading lists</string>
<string name="list_exclusive_label">Hide from the home timeline</string> <string name="list_exclusive_label">Hide from the home timeline</string>
<string name="list">List</string> <string name="list">List</string>
<string name="notifications_clear">Clear</string> <string name="notifications_clear">Delete notifications</string>
<string name="notifications_apply_filter">Filter</string> <string name="notifications_apply_filter">Filter notifications</string>
<string name="filter_apply">Apply</string> <string name="filter_apply">Apply</string>
<string name="compose_shortcut_long_label">Compose post</string> <string name="compose_shortcut_long_label">Compose post</string>
@ -670,7 +670,6 @@
<string name="title_accounts">Accounts</string> <string name="title_accounts">Accounts</string>
<string name="failed_search">Failed to search</string> <string name="failed_search">Failed to search</string>
<string name="pref_title_show_notifications_filter">Show Notifications filter</string>
<string name="pref_title_enable_swipe_for_tabs">Enable swipe gesture to switch between tabs</string> <string name="pref_title_enable_swipe_for_tabs">Enable swipe gesture to switch between tabs</string>
<string name="pref_title_show_stat_inline">Show post statistics in timeline</string> <string name="pref_title_show_stat_inline">Show post statistics in timeline</string>

View File

@ -179,9 +179,4 @@
<item name="materialDrawerMaskDrawable">@drawable/materialdrawer_shape_small</item> <item name="materialDrawerMaskDrawable">@drawable/materialdrawer_shape_small</item>
<item name="materialDrawerDrawCircularShadow">false</item> <item name="materialDrawerDrawCircularShadow">false</item>
</style> </style>
<style name="ShapeAppearance.Avatar" parent="ShapeAppearance.MaterialComponents">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">12.5%</item>
</style>
</resources> </resources>

View File

@ -99,7 +99,6 @@ abstract class NotificationsViewModelTestBase {
PrefKeys.CONFIRM_REBLOGS to true, PrefKeys.CONFIRM_REBLOGS to true,
PrefKeys.CONFIRM_FAVOURITES to false, PrefKeys.CONFIRM_FAVOURITES to false,
PrefKeys.WELLBEING_HIDE_STATS_POSTS to false, PrefKeys.WELLBEING_HIDE_STATS_POSTS to false,
PrefKeys.SHOW_NOTIFICATIONS_FILTER to true,
PrefKeys.FAB_HIDE to false PrefKeys.FAB_HIDE to false
) )

View File

@ -35,7 +35,6 @@ class NotificationsViewModelTestUiState : NotificationsViewModelTestBase() {
private val initialUiState = UiState( private val initialUiState = UiState(
activeFilter = setOf(Notification.Type.FOLLOW), activeFilter = setOf(Notification.Type.FOLLOW),
showFilterOptions = true,
showFabWhileScrolling = true showFabWhileScrolling = true
) )
@ -64,23 +63,4 @@ class NotificationsViewModelTestUiState : NotificationsViewModelTestBase() {
assertThat(expectMostRecentItem().showFabWhileScrolling).isFalse() assertThat(expectMostRecentItem().showFabWhileScrolling).isFalse()
} }
} }
@Test
fun `showFilterOptions depends on SHOW_NOTIFICATIONS_FILTER preference`() = runTest {
// Prior
viewModel.uiState.test {
assertThat(expectMostRecentItem().showFilterOptions).isTrue()
}
// Given
sharedPreferencesMap[PrefKeys.SHOW_NOTIFICATIONS_FILTER] = false
// When
eventHub.dispatch(PreferenceChangedEvent(PrefKeys.SHOW_NOTIFICATIONS_FILTER))
// Then
viewModel.uiState.test {
assertThat(expectMostRecentItem().showFilterOptions).isFalse()
}
}
} }