rename module and classes to domainblocks

This commit is contained in:
Conny Duck 2023-07-04 19:41:36 +02:00
parent 626a8760ae
commit 4670964362
13 changed files with 62 additions and 63 deletions

View File

@ -148,7 +148,7 @@
<activity <activity
android:name=".components.report.ReportActivity" android:name=".components.report.ReportActivity"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize" /> android:windowSoftInputMode="stateAlwaysHidden|adjustResize" />
<activity android:name=".components.instancemute.InstanceListActivity" /> <activity android:name=".components.domainblocks.DomainBlocksActivity" />
<activity android:name=".components.scheduled.ScheduledStatusActivity" /> <activity android:name=".components.scheduled.ScheduledStatusActivity" />
<activity android:name=".components.announcements.AnnouncementsActivity" /> <activity android:name=".components.announcements.AnnouncementsActivity" />
<activity android:name=".components.drafts.DraftsActivity" /> <activity android:name=".components.drafts.DraftsActivity" />

View File

@ -1,15 +1,14 @@
package com.keylesspalace.tusky.components.instancemute package com.keylesspalace.tusky.components.domainblocks
import android.os.Bundle import android.os.Bundle
import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.instancemute.fragment.InstanceListFragment
import com.keylesspalace.tusky.databinding.ActivityAccountListBinding import com.keylesspalace.tusky.databinding.ActivityAccountListBinding
import dagger.android.DispatchingAndroidInjector import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import javax.inject.Inject import javax.inject.Inject
class InstanceListActivity : BaseActivity(), HasAndroidInjector { class DomainBlocksActivity : BaseActivity(), HasAndroidInjector {
@Inject @Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any> lateinit var androidInjector: DispatchingAndroidInjector<Any>
@ -28,7 +27,7 @@ class InstanceListActivity : BaseActivity(), HasAndroidInjector {
supportFragmentManager supportFragmentManager
.beginTransaction() .beginTransaction()
.replace(R.id.fragment_container, InstanceListFragment()) .replace(R.id.fragment_container, DomainBlocksFragment())
.commit() .commit()
} }

View File

@ -1,4 +1,4 @@
package com.keylesspalace.tusky.components.instancemute.adapter package com.keylesspalace.tusky.components.domainblocks
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
@ -7,7 +7,7 @@ import com.keylesspalace.tusky.components.followedtags.FollowedTagsAdapter.Compa
import com.keylesspalace.tusky.databinding.ItemMutedDomainBinding import com.keylesspalace.tusky.databinding.ItemMutedDomainBinding
import com.keylesspalace.tusky.util.BindingHolder import com.keylesspalace.tusky.util.BindingHolder
class DomainMutesAdapter( class DomainBlocksAdapter(
private val onUnmute: (String) -> Unit private val onUnmute: (String) -> Unit
) : PagingDataAdapter<String, BindingHolder<ItemMutedDomainBinding>>(STRING_COMPARATOR) { ) : PagingDataAdapter<String, BindingHolder<ItemMutedDomainBinding>>(STRING_COMPARATOR) {

View File

@ -1,4 +1,4 @@
package com.keylesspalace.tusky.components.instancemute.fragment package com.keylesspalace.tusky.components.domainblocks
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
@ -11,11 +11,7 @@ import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.followedtags.FollowedTagsActivity import com.keylesspalace.tusky.databinding.FragmentDomainBlocksBinding
import com.keylesspalace.tusky.components.instancemute.InstanceMuteEvent
import com.keylesspalace.tusky.components.instancemute.InstanceMuteViewModel
import com.keylesspalace.tusky.components.instancemute.adapter.DomainMutesAdapter
import com.keylesspalace.tusky.databinding.FragmentInstanceListBinding
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.util.hide import com.keylesspalace.tusky.util.hide
@ -26,17 +22,17 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectable { class DomainBlocksFragment : Fragment(R.layout.fragment_domain_blocks), Injectable {
@Inject @Inject
lateinit var viewModelFactory: ViewModelFactory lateinit var viewModelFactory: ViewModelFactory
private val binding by viewBinding(FragmentInstanceListBinding::bind) private val binding by viewBinding(FragmentDomainBlocksBinding::bind)
private val viewModel: InstanceMuteViewModel by viewModels { viewModelFactory } private val viewModel: DomainBlocksViewModel by viewModels { viewModelFactory }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val adapter = DomainMutesAdapter(viewModel::unmute) val adapter = DomainBlocksAdapter(viewModel::unblock)
binding.recyclerView.setHasFixedSize(true) binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL)) binding.recyclerView.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL))
@ -46,9 +42,9 @@ class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectab
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
viewModel.uiEvents.collect { event -> viewModel.uiEvents.collect { event ->
when (event) { when (event) {
is InstanceMuteEvent.UnmuteError -> showUnmuteError(event.domain) is DomainBlockEvent.UnblockError -> showUnmuteError(event.domain)
is InstanceMuteEvent.MuteError -> showMuteError(event.domain) is DomainBlockEvent.BlockError -> showMuteError(event.domain)
is InstanceMuteEvent.UnmuteSuccess -> showUnmuteSuccess(event.domain) is DomainBlockEvent.BlockSuccess -> showUnmuteSuccess(event.domain)
} }
} }
} }
@ -60,14 +56,14 @@ class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectab
} }
adapter.addLoadStateListener { loadState -> adapter.addLoadStateListener { loadState ->
binding.instanceProgressBar.visible(loadState.refresh == LoadState.Loading && adapter.itemCount == 0) binding.progressBar.visible(loadState.refresh == LoadState.Loading && adapter.itemCount == 0)
if (loadState.refresh is LoadState.Error) { if (loadState.refresh is LoadState.Error) {
binding.recyclerView.hide() binding.recyclerView.hide()
binding.messageView.show() binding.messageView.show()
val errorState = loadState.refresh as LoadState.Error val errorState = loadState.refresh as LoadState.Error
binding.messageView.setup(errorState.error) { adapter.retry() } binding.messageView.setup(errorState.error) { adapter.retry() }
Log.w(FollowedTagsActivity.TAG, "error loading followed hashtags", errorState.error) Log.w(TAG, "error loading blocked domains", errorState.error)
} else if (loadState.refresh is LoadState.NotLoading && adapter.itemCount == 0) { } else if (loadState.refresh is LoadState.NotLoading && adapter.itemCount == 0) {
binding.recyclerView.hide() binding.recyclerView.hide()
binding.messageView.show() binding.messageView.show()
@ -81,23 +77,23 @@ class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectab
private fun showUnmuteError(domain: String) { private fun showUnmuteError(domain: String) {
showSnackbar( showSnackbar(
getString(R.string.error_unmuting_domain, domain), getString(R.string.error_unblocking_domain, domain),
R.string.action_retry R.string.action_retry
) { viewModel.unmute(domain) } ) { viewModel.unblock(domain) }
} }
private fun showMuteError(domain: String) { private fun showMuteError(domain: String) {
showSnackbar( showSnackbar(
getString(R.string.error_muting_domain, domain), getString(R.string.error_blocking_domain, domain),
R.string.action_retry R.string.action_retry
) { viewModel.mute(domain) } ) { viewModel.block(domain) }
} }
private fun showUnmuteSuccess(domain: String) { private fun showUnmuteSuccess(domain: String) {
showSnackbar( showSnackbar(
getString(R.string.confirmation_domain_unmuted, domain), getString(R.string.confirmation_domain_unmuted, domain),
R.string.action_undo R.string.action_undo
) { viewModel.mute(domain) } ) { viewModel.block(domain) }
} }
private fun showSnackbar(message: String, actionText: Int, action: (View) -> Unit) { private fun showSnackbar(message: String, actionText: Int, action: (View) -> Unit) {
@ -105,4 +101,8 @@ class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectab
.setAction(actionText, action) .setAction(actionText, action)
.show() .show()
} }
companion object {
private const val TAG = "DomainBlocksFragment"
}
} }

View File

@ -1,9 +1,9 @@
package com.keylesspalace.tusky.components.instancemute package com.keylesspalace.tusky.components.domainblocks
import androidx.paging.PagingSource import androidx.paging.PagingSource
import androidx.paging.PagingState import androidx.paging.PagingState
class InstanceMutePagingSource(private val viewModel: InstanceMuteViewModel) : PagingSource<String, String>() { class DomainBlocksPagingSource(private val viewModel: DomainBlocksViewModel) : PagingSource<String, String>() {
override fun getRefreshKey(state: PagingState<String, String>): String? = null override fun getRefreshKey(state: PagingState<String, String>): String? = null
override suspend fun load(params: LoadParams<String>): LoadResult<String, String> { override suspend fun load(params: LoadParams<String>): LoadResult<String, String> {

View File

@ -1,4 +1,4 @@
package com.keylesspalace.tusky.components.instancemute package com.keylesspalace.tusky.components.domainblocks
import androidx.paging.ExperimentalPagingApi import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType import androidx.paging.LoadType
@ -10,9 +10,9 @@ import retrofit2.HttpException
import retrofit2.Response import retrofit2.Response
@OptIn(ExperimentalPagingApi::class) @OptIn(ExperimentalPagingApi::class)
class InstanceMuteRemoteMediator( class DomainBlocksRemoteMediator(
private val api: MastodonApi, private val api: MastodonApi,
private val viewModel: InstanceMuteViewModel private val viewModel: DomainBlocksViewModel
) : RemoteMediator<String, String>() { ) : RemoteMediator<String, String>() {
override suspend fun load( override suspend fun load(
loadType: LoadType, loadType: LoadType,

View File

@ -1,4 +1,4 @@
package com.keylesspalace.tusky.components.instancemute package com.keylesspalace.tusky.components.domainblocks
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@ -13,20 +13,20 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
class InstanceMuteViewModel @Inject constructor( class DomainBlocksViewModel @Inject constructor(
private val api: MastodonApi private val api: MastodonApi
) : ViewModel() { ) : ViewModel() {
val domains: MutableList<String> = mutableListOf() val domains: MutableList<String> = mutableListOf()
val uiEvents = MutableSharedFlow<InstanceMuteEvent>() val uiEvents = MutableSharedFlow<DomainBlockEvent>()
var nextKey: String? = null var nextKey: String? = null
var currentSource: InstanceMutePagingSource? = null var currentSource: DomainBlocksPagingSource? = null
@OptIn(ExperimentalPagingApi::class) @OptIn(ExperimentalPagingApi::class)
val pager = Pager( val pager = Pager(
config = PagingConfig(pageSize = 20), config = PagingConfig(pageSize = 20),
remoteMediator = InstanceMuteRemoteMediator(api, this), remoteMediator = DomainBlocksRemoteMediator(api, this),
pagingSourceFactory = { pagingSourceFactory = {
InstanceMutePagingSource( DomainBlocksPagingSource(
viewModel = this viewModel = this
).also { source -> ).also { source ->
currentSource = source currentSource = source
@ -34,38 +34,38 @@ class InstanceMuteViewModel @Inject constructor(
} }
).flow.cachedIn(viewModelScope) ).flow.cachedIn(viewModelScope)
fun mute(domain: String) { fun block(domain: String) {
viewModelScope.launch { viewModelScope.launch {
api.blockDomain(domain).fold({ api.blockDomain(domain).fold({
domains.add(domain) domains.add(domain)
currentSource?.invalidate() currentSource?.invalidate()
}, { e -> }, { e ->
Log.w(TAG, "Error muting domain $domain", e) Log.w(TAG, "Error blocking domain $domain", e)
uiEvents.emit(InstanceMuteEvent.MuteError(domain)) uiEvents.emit(DomainBlockEvent.BlockError(domain))
}) })
} }
} }
fun unmute(domain: String) { fun unblock(domain: String) {
viewModelScope.launch { viewModelScope.launch {
api.unblockDomain(domain).fold({ api.unblockDomain(domain).fold({
domains.remove(domain) domains.remove(domain)
currentSource?.invalidate() currentSource?.invalidate()
uiEvents.emit(InstanceMuteEvent.UnmuteSuccess(domain)) uiEvents.emit(DomainBlockEvent.BlockSuccess(domain))
}, { e -> }, { e ->
Log.w(TAG, "Error unmuting domain $domain", e) Log.w(TAG, "Error unblocking domain $domain", e)
uiEvents.emit(InstanceMuteEvent.UnmuteError(domain)) uiEvents.emit(DomainBlockEvent.UnblockError(domain))
}) })
} }
} }
companion object { companion object {
private const val TAG = "InstanceMuteViewModel" private const val TAG = "DomainBlocksViewModel"
} }
} }
sealed class InstanceMuteEvent { sealed class DomainBlockEvent {
data class UnmuteSuccess(val domain: String) : InstanceMuteEvent() data class BlockSuccess(val domain: String) : DomainBlockEvent()
data class UnmuteError(val domain: String) : InstanceMuteEvent() data class UnblockError(val domain: String) : DomainBlockEvent()
data class MuteError(val domain: String) : InstanceMuteEvent() data class BlockError(val domain: String) : DomainBlockEvent()
} }

View File

@ -30,9 +30,9 @@ import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.TabPreferenceActivity import com.keylesspalace.tusky.TabPreferenceActivity
import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.components.accountlist.AccountListActivity import com.keylesspalace.tusky.components.accountlist.AccountListActivity
import com.keylesspalace.tusky.components.domainblocks.DomainBlocksActivity
import com.keylesspalace.tusky.components.filters.FiltersActivity import com.keylesspalace.tusky.components.filters.FiltersActivity
import com.keylesspalace.tusky.components.followedtags.FollowedTagsActivity import com.keylesspalace.tusky.components.followedtags.FollowedTagsActivity
import com.keylesspalace.tusky.components.instancemute.InstanceListActivity
import com.keylesspalace.tusky.components.login.LoginActivity import com.keylesspalace.tusky.components.login.LoginActivity
import com.keylesspalace.tusky.components.notifications.currentAccountNeedsMigration import com.keylesspalace.tusky.components.notifications.currentAccountNeedsMigration
import com.keylesspalace.tusky.db.AccountManager import com.keylesspalace.tusky.db.AccountManager
@ -156,7 +156,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
setTitle(R.string.title_domain_mutes) setTitle(R.string.title_domain_mutes)
setIcon(R.drawable.ic_mute_24dp) setIcon(R.drawable.ic_mute_24dp)
setOnPreferenceClickListener { setOnPreferenceClickListener {
val intent = Intent(context, InstanceListActivity::class.java) val intent = Intent(context, DomainBlocksActivity::class.java)
activity?.startActivity(intent) activity?.startActivity(intent)
activity?.overridePendingTransition( activity?.overridePendingTransition(
R.anim.slide_from_right, R.anim.slide_from_right,

View File

@ -29,11 +29,11 @@ import com.keylesspalace.tusky.components.account.AccountActivity
import com.keylesspalace.tusky.components.accountlist.AccountListActivity import com.keylesspalace.tusky.components.accountlist.AccountListActivity
import com.keylesspalace.tusky.components.announcements.AnnouncementsActivity import com.keylesspalace.tusky.components.announcements.AnnouncementsActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.components.domainblocks.DomainBlocksActivity
import com.keylesspalace.tusky.components.drafts.DraftsActivity import com.keylesspalace.tusky.components.drafts.DraftsActivity
import com.keylesspalace.tusky.components.filters.EditFilterActivity import com.keylesspalace.tusky.components.filters.EditFilterActivity
import com.keylesspalace.tusky.components.filters.FiltersActivity import com.keylesspalace.tusky.components.filters.FiltersActivity
import com.keylesspalace.tusky.components.followedtags.FollowedTagsActivity import com.keylesspalace.tusky.components.followedtags.FollowedTagsActivity
import com.keylesspalace.tusky.components.instancemute.InstanceListActivity
import com.keylesspalace.tusky.components.login.LoginActivity import com.keylesspalace.tusky.components.login.LoginActivity
import com.keylesspalace.tusky.components.login.LoginWebViewActivity import com.keylesspalace.tusky.components.login.LoginWebViewActivity
import com.keylesspalace.tusky.components.preference.PreferencesActivity import com.keylesspalace.tusky.components.preference.PreferencesActivity
@ -113,7 +113,7 @@ abstract class ActivitiesModule {
abstract fun contributesReportActivity(): ReportActivity abstract fun contributesReportActivity(): ReportActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class]) @ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesInstanceListActivity(): InstanceListActivity abstract fun contributesInstanceListActivity(): DomainBlocksActivity
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun contributesScheduledStatusActivity(): ScheduledStatusActivity abstract fun contributesScheduledStatusActivity(): ScheduledStatusActivity

View File

@ -20,7 +20,7 @@ import com.keylesspalace.tusky.components.account.list.ListsForAccountFragment
import com.keylesspalace.tusky.components.account.media.AccountMediaFragment import com.keylesspalace.tusky.components.account.media.AccountMediaFragment
import com.keylesspalace.tusky.components.accountlist.AccountListFragment import com.keylesspalace.tusky.components.accountlist.AccountListFragment
import com.keylesspalace.tusky.components.conversation.ConversationsFragment import com.keylesspalace.tusky.components.conversation.ConversationsFragment
import com.keylesspalace.tusky.components.instancemute.fragment.InstanceListFragment import com.keylesspalace.tusky.components.domainblocks.DomainBlocksFragment
import com.keylesspalace.tusky.components.notifications.NotificationsFragment import com.keylesspalace.tusky.components.notifications.NotificationsFragment
import com.keylesspalace.tusky.components.preference.AccountPreferencesFragment import com.keylesspalace.tusky.components.preference.AccountPreferencesFragment
import com.keylesspalace.tusky.components.preference.NotificationPreferencesFragment import com.keylesspalace.tusky.components.preference.NotificationPreferencesFragment
@ -84,7 +84,7 @@ abstract class FragmentBuildersModule {
abstract fun reportDoneFragment(): ReportDoneFragment abstract fun reportDoneFragment(): ReportDoneFragment
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun instanceListFragment(): InstanceListFragment abstract fun instanceListFragment(): DomainBlocksFragment
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun searchStatusesFragment(): SearchStatusesFragment abstract fun searchStatusesFragment(): SearchStatusesFragment

View File

@ -27,11 +27,11 @@ import com.keylesspalace.tusky.components.account.media.AccountMediaViewModel
import com.keylesspalace.tusky.components.announcements.AnnouncementsViewModel import com.keylesspalace.tusky.components.announcements.AnnouncementsViewModel
import com.keylesspalace.tusky.components.compose.ComposeViewModel import com.keylesspalace.tusky.components.compose.ComposeViewModel
import com.keylesspalace.tusky.components.conversation.ConversationsViewModel import com.keylesspalace.tusky.components.conversation.ConversationsViewModel
import com.keylesspalace.tusky.components.domainblocks.DomainBlocksViewModel
import com.keylesspalace.tusky.components.drafts.DraftsViewModel import com.keylesspalace.tusky.components.drafts.DraftsViewModel
import com.keylesspalace.tusky.components.filters.EditFilterViewModel import com.keylesspalace.tusky.components.filters.EditFilterViewModel
import com.keylesspalace.tusky.components.filters.FiltersViewModel import com.keylesspalace.tusky.components.filters.FiltersViewModel
import com.keylesspalace.tusky.components.followedtags.FollowedTagsViewModel import com.keylesspalace.tusky.components.followedtags.FollowedTagsViewModel
import com.keylesspalace.tusky.components.instancemute.InstanceMuteViewModel
import com.keylesspalace.tusky.components.login.LoginWebViewViewModel import com.keylesspalace.tusky.components.login.LoginWebViewViewModel
import com.keylesspalace.tusky.components.notifications.NotificationsViewModel import com.keylesspalace.tusky.components.notifications.NotificationsViewModel
import com.keylesspalace.tusky.components.report.ReportViewModel import com.keylesspalace.tusky.components.report.ReportViewModel
@ -188,8 +188,8 @@ abstract class ViewModelModule {
@Binds @Binds
@IntoMap @IntoMap
@ViewModelKey(InstanceMuteViewModel::class) @ViewModelKey(DomainBlocksViewModel::class)
internal abstract fun instanceMuteViewModel(viewModel: InstanceMuteViewModel): ViewModel internal abstract fun instanceMuteViewModel(viewModel: DomainBlocksViewModel): ViewModel
// Add more ViewModels here // Add more ViewModels here
} }

View File

@ -5,7 +5,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<ProgressBar <ProgressBar
android:id="@+id/instanceProgressBar" android:id="@+id/progressBar"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" /> android:layout_gravity="center" />
@ -22,4 +22,4 @@
android:layout_gravity="center" android:layout_gravity="center"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible" /> tools:visibility="visible" />
</FrameLayout> </FrameLayout>

View File

@ -44,8 +44,8 @@
<string name="error_following_hashtags_unsupported">This instance does not support following hashtags.</string> <string name="error_following_hashtags_unsupported">This instance does not support following hashtags.</string>
<string name="error_muting_hashtag_format">Error muting #%s</string> <string name="error_muting_hashtag_format">Error muting #%s</string>
<string name="error_unmuting_hashtag_format">Error unmuting #%s</string> <string name="error_unmuting_hashtag_format">Error unmuting #%s</string>
<string name="error_muting_domain">Failed to mute %s</string> <string name="error_blocking_domain">Failed to mute %s</string>
<string name="error_unmuting_domain">Failed to mute %s</string> <string name="error_unblocking_domain">Failed to unmute %s</string>
<string name="error_status_source_load">Failed to load the status source from the server.</string> <string name="error_status_source_load">Failed to load the status source from the server.</string>
<string name="title_login">Login</string> <string name="title_login">Login</string>