forked from upstream-mirrors/quik
Move blocked messages to their own screen
This commit is contained in:
@@ -19,7 +19,6 @@
|
||||
package com.moez.QKSMS.feature.blocking
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.jakewharton.rxbinding2.view.clicks
|
||||
import com.moez.QKSMS.R
|
||||
@@ -28,6 +27,7 @@ import com.moez.QKSMS.common.base.QkController
|
||||
import com.moez.QKSMS.common.util.Colors
|
||||
import com.moez.QKSMS.common.util.extensions.animateLayoutChanges
|
||||
import com.moez.QKSMS.feature.blocking.manager.BlockingManagerController
|
||||
import com.moez.QKSMS.feature.blocking.messages.BlockedMessagesController
|
||||
import com.moez.QKSMS.injection.appComponent
|
||||
import kotlinx.android.synthetic.main.blocking_controller.*
|
||||
import kotlinx.android.synthetic.main.settings_switch_widget.view.*
|
||||
@@ -36,10 +36,9 @@ import javax.inject.Inject
|
||||
class BlockingController : QkController<BlockingView, BlockingState, BlockingPresenter>(), BlockingView {
|
||||
|
||||
override val blockingManagerIntent by lazy { blockingManager.clicks() }
|
||||
override val blockedMessagesIntent by lazy { blockedNumbers.clicks() }
|
||||
override val dropClickedIntent by lazy { drop.clicks() }
|
||||
override val conversationClicks by lazy { blockingAdapter.clicks }
|
||||
|
||||
@Inject lateinit var blockingAdapter: BlockingAdapter
|
||||
@Inject lateinit var colors: Colors
|
||||
@Inject override lateinit var presenter: BlockingPresenter
|
||||
|
||||
@@ -51,10 +50,6 @@ class BlockingController : QkController<BlockingView, BlockingState, BlockingPre
|
||||
|
||||
override fun onViewCreated() {
|
||||
super.onViewCreated()
|
||||
|
||||
blockingAdapter.emptyView = empty
|
||||
conversations.adapter = blockingAdapter
|
||||
|
||||
parent.postDelayed({ parent?.animateLayoutChanges = true }, 100)
|
||||
}
|
||||
|
||||
@@ -68,8 +63,12 @@ class BlockingController : QkController<BlockingView, BlockingState, BlockingPre
|
||||
override fun render(state: BlockingState) {
|
||||
blockingManager.summary = state.blockingManager
|
||||
drop.checkbox.isChecked = state.dropEnabled
|
||||
blockedLabel.isVisible = state.data?.isNotEmpty() == true
|
||||
blockingAdapter.updateData(state.data)
|
||||
}
|
||||
|
||||
override fun openBlockedMessages() {
|
||||
router.pushController(RouterTransaction.with(BlockedMessagesController())
|
||||
.pushChangeHandler(QkChangeHandler())
|
||||
.popChangeHandler(QkChangeHandler()))
|
||||
}
|
||||
|
||||
override fun openBlockingManager() {
|
||||
|
||||
@@ -20,10 +20,7 @@ package com.moez.QKSMS.feature.blocking
|
||||
|
||||
import android.content.Context
|
||||
import com.moez.QKSMS.R
|
||||
import com.moez.QKSMS.common.Navigator
|
||||
import com.moez.QKSMS.common.base.QkPresenter
|
||||
import com.moez.QKSMS.extensions.asObservable
|
||||
import com.moez.QKSMS.repository.ConversationRepository
|
||||
import com.moez.QKSMS.util.Preferences
|
||||
import com.uber.autodispose.android.lifecycle.scope
|
||||
import com.uber.autodispose.autoDisposable
|
||||
@@ -32,15 +29,10 @@ import javax.inject.Inject
|
||||
|
||||
class BlockingPresenter @Inject constructor(
|
||||
context: Context,
|
||||
conversationRepo: ConversationRepository,
|
||||
private val navigator: Navigator,
|
||||
private val prefs: Preferences
|
||||
) : QkPresenter<BlockingView, BlockingState>(BlockingState()) {
|
||||
|
||||
init {
|
||||
val blockedConversations = conversationRepo.getBlockedConversations()
|
||||
newState { copy(data = blockedConversations) }
|
||||
|
||||
disposables += prefs.blockingManager.asObservable()
|
||||
.map { client ->
|
||||
when (client) {
|
||||
@@ -54,14 +46,6 @@ class BlockingPresenter @Inject constructor(
|
||||
|
||||
disposables += prefs.drop.asObservable()
|
||||
.subscribe { enabled -> newState { copy(dropEnabled = enabled) } }
|
||||
|
||||
// Trigger a refresh if we go between having some/no blocked conversations, otherwise the header won't update
|
||||
disposables += blockedConversations
|
||||
.asObservable()
|
||||
.filter { it.isValid && it.isLoaded }
|
||||
.map { it.isEmpty() }
|
||||
.distinctUntilChanged()
|
||||
.subscribe { newState { copy() } }
|
||||
}
|
||||
|
||||
override fun bindIntents(view: BlockingView) {
|
||||
@@ -71,13 +55,13 @@ class BlockingPresenter @Inject constructor(
|
||||
.autoDisposable(view.scope())
|
||||
.subscribe { view.openBlockingManager() }
|
||||
|
||||
view.blockedMessagesIntent
|
||||
.autoDisposable(view.scope())
|
||||
.subscribe { view.openBlockedMessages() }
|
||||
|
||||
view.dropClickedIntent
|
||||
.autoDisposable(view.scope())
|
||||
.subscribe { prefs.drop.set(!prefs.drop.get()) }
|
||||
|
||||
view.conversationClicks
|
||||
.autoDisposable(view.scope())
|
||||
.subscribe { threadId -> navigator.showConversation(threadId) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,11 +18,7 @@
|
||||
*/
|
||||
package com.moez.QKSMS.feature.blocking
|
||||
|
||||
import com.moez.QKSMS.model.Conversation
|
||||
import io.realm.RealmResults
|
||||
|
||||
data class BlockingState(
|
||||
val blockingManager: String = "",
|
||||
val dropEnabled: Boolean = false,
|
||||
val data: RealmResults<Conversation>? = null
|
||||
)
|
||||
val dropEnabled: Boolean = false
|
||||
)
|
||||
|
||||
@@ -24,8 +24,9 @@ import io.reactivex.Observable
|
||||
interface BlockingView : QkViewContract<BlockingState> {
|
||||
|
||||
val blockingManagerIntent: Observable<*>
|
||||
val blockedMessagesIntent: Observable<*>
|
||||
val dropClickedIntent: Observable<*>
|
||||
val conversationClicks: Observable<Long>
|
||||
|
||||
fun openBlockingManager()
|
||||
fun openBlockedMessages()
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
* Copyright (C) 2019 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
@@ -16,7 +16,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.moez.QKSMS.feature.blocking
|
||||
package com.moez.QKSMS.feature.blocking.messages
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
@@ -28,7 +28,7 @@ import io.reactivex.subjects.PublishSubject
|
||||
import kotlinx.android.synthetic.main.blocked_list_item.view.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class BlockingAdapter @Inject constructor() : QkRealmAdapter<Conversation>() {
|
||||
class BlockedMessagesAdapter @Inject constructor() : QkRealmAdapter<Conversation>() {
|
||||
|
||||
val clicks: PublishSubject<Long> = PublishSubject.create()
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
* QKSMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QKSMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.moez.QKSMS.feature.blocking.messages
|
||||
|
||||
import android.view.View
|
||||
import com.moez.QKSMS.R
|
||||
import com.moez.QKSMS.common.base.QkController
|
||||
import com.moez.QKSMS.common.util.Colors
|
||||
import com.moez.QKSMS.injection.appComponent
|
||||
import kotlinx.android.synthetic.main.blocked_messages_controller.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class BlockedMessagesController : QkController<BlockedMessagesView, BlockedMessagesState, BlockedMessagesPresenter>(),
|
||||
BlockedMessagesView {
|
||||
|
||||
override val conversationClicks by lazy { blockedMessagesAdapter.clicks }
|
||||
|
||||
@Inject lateinit var blockedMessagesAdapter: BlockedMessagesAdapter
|
||||
@Inject lateinit var colors: Colors
|
||||
@Inject override lateinit var presenter: BlockedMessagesPresenter
|
||||
|
||||
init {
|
||||
appComponent.inject(this)
|
||||
retainViewMode = RetainViewMode.RETAIN_DETACH
|
||||
layoutRes = R.layout.blocked_messages_controller
|
||||
}
|
||||
|
||||
override fun onViewCreated() {
|
||||
super.onViewCreated()
|
||||
|
||||
blockedMessagesAdapter.emptyView = empty
|
||||
conversations.adapter = blockedMessagesAdapter
|
||||
}
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
super.onAttach(view)
|
||||
presenter.bindIntents(this)
|
||||
setTitle(R.string.blocked_messages_title)
|
||||
showBackButton(true)
|
||||
}
|
||||
|
||||
override fun render(state: BlockedMessagesState) {
|
||||
blockedMessagesAdapter.updateData(state.data)
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
* QKSMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QKSMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.moez.QKSMS.feature.blocking.messages
|
||||
|
||||
import com.moez.QKSMS.common.Navigator
|
||||
import com.moez.QKSMS.common.base.QkPresenter
|
||||
import com.moez.QKSMS.repository.ConversationRepository
|
||||
import com.uber.autodispose.android.lifecycle.scope
|
||||
import com.uber.autodispose.autoDisposable
|
||||
import javax.inject.Inject
|
||||
|
||||
class BlockedMessagesPresenter @Inject constructor(
|
||||
conversationRepo: ConversationRepository,
|
||||
private val navigator: Navigator
|
||||
) : QkPresenter<BlockedMessagesView, BlockedMessagesState>(BlockedMessagesState(
|
||||
data = conversationRepo.getBlockedConversations()
|
||||
)) {
|
||||
|
||||
override fun bindIntents(view: BlockedMessagesView) {
|
||||
super.bindIntents(view)
|
||||
|
||||
view.conversationClicks
|
||||
.autoDisposable(view.scope())
|
||||
.subscribe { threadId -> navigator.showConversation(threadId) }
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
* QKSMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QKSMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.moez.QKSMS.feature.blocking.messages
|
||||
|
||||
import com.moez.QKSMS.model.Conversation
|
||||
import io.realm.RealmResults
|
||||
|
||||
data class BlockedMessagesState(
|
||||
val data: RealmResults<Conversation>? = null
|
||||
)
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
* QKSMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QKSMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.moez.QKSMS.feature.blocking.messages
|
||||
|
||||
import com.moez.QKSMS.common.base.QkViewContract
|
||||
import io.reactivex.Observable
|
||||
|
||||
interface BlockedMessagesView : QkViewContract<BlockedMessagesState> {
|
||||
val conversationClicks: Observable<Long>
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import com.moez.QKSMS.common.widget.RadioPreferenceView
|
||||
import com.moez.QKSMS.feature.backup.BackupController
|
||||
import com.moez.QKSMS.feature.blocking.BlockingController
|
||||
import com.moez.QKSMS.feature.blocking.manager.BlockingManagerController
|
||||
import com.moez.QKSMS.feature.blocking.messages.BlockedMessagesController
|
||||
import com.moez.QKSMS.feature.blocking.numbers.BlockedNumbersController
|
||||
import com.moez.QKSMS.feature.compose.DetailedChipView
|
||||
import com.moez.QKSMS.feature.conversationinfo.injection.ConversationInfoComponent
|
||||
@@ -63,6 +64,7 @@ interface AppComponent {
|
||||
|
||||
fun inject(controller: AboutController)
|
||||
fun inject(controller: BackupController)
|
||||
fun inject(controller: BlockedMessagesController)
|
||||
fun inject(controller: BlockedNumbersController)
|
||||
fun inject(controller: BlockingController)
|
||||
fun inject(controller: BlockingManagerController)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2019 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
~
|
||||
~ This file is part of QKSMS.
|
||||
~
|
||||
~ QKSMS is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ QKSMS is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:attr/windowBackground">
|
||||
|
||||
<com.moez.QKSMS.common.widget.QkTextView
|
||||
android:id="@+id/empty"
|
||||
style="@style/TextSecondary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:padding="56dp"
|
||||
android:text="@string/blocked_messages_empty" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/conversations"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/blocked_list_item" />
|
||||
|
||||
</FrameLayout>
|
||||
@@ -17,7 +17,7 @@
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
@@ -25,71 +25,35 @@
|
||||
android:background="?android:attr/windowBackground"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<LinearLayout
|
||||
android:id="@+id/parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<com.moez.QKSMS.common.widget.PreferenceView
|
||||
android:id="@+id/blockingManager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintHorizontal_chainStyle="spread"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:title="@string/blocking_manager_title"
|
||||
tools:summary="@string/blocking_manager_qksms_title" />
|
||||
|
||||
<com.moez.QKSMS.common.widget.PreferenceView
|
||||
android:id="@+id/blockedNumbers"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:title="@string/blocked_messages_title" />
|
||||
|
||||
<com.moez.QKSMS.common.widget.PreferenceView
|
||||
android:id="@+id/drop"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@+id/blockingManager"
|
||||
app:summary="@string/blocking_drop_summary"
|
||||
app:title="@string/blocking_drop_title"
|
||||
app:widget="@layout/settings_switch_widget" />
|
||||
|
||||
<View
|
||||
android:id="@+id/conversationsDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="?android:attr/divider"
|
||||
app:layout_constraintTop_toBottomOf="@+id/drop" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.moez.QKSMS.common.widget.QkTextView
|
||||
android:id="@+id/blockedLabel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/blocking_conversations"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintTop_toBottomOf="@+id/conversationsDivider"
|
||||
app:textSize="secondary" />
|
||||
|
||||
<com.moez.QKSMS.common.widget.QkTextView
|
||||
android:id="@+id/empty"
|
||||
style="@style/TextSecondary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="56dp"
|
||||
android:text="@string/blocking_empty"
|
||||
app:layout_constraintTop_toBottomOf="@+id/blockedLabel" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/conversations"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintTop_toBottomOf="@+id/blockedLabel"
|
||||
tools:listitem="@layout/blocked_list_item" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</ScrollView>
|
||||
|
||||
@@ -255,7 +255,6 @@
|
||||
<string name="blocking_drop_title">Drop messages</string>
|
||||
<string name="blocking_drop_summary">Drop incoming messages from blocked senders instead of hiding them</string>
|
||||
<string name="blocking_conversations">Blocked conversations</string>
|
||||
<string name="blocking_empty">Your blocked conversations will appear here</string>
|
||||
|
||||
<string name="blocking_manager_title">Blocking Manager</string>
|
||||
<string name="blocking_manager_qksms_title">QKSMS</string>
|
||||
@@ -274,6 +273,9 @@
|
||||
<string name="blocked_numbers_dialog_hint">Phone number</string>
|
||||
<string name="blocked_numbers_dialog_block">Block</string>
|
||||
|
||||
<string name="blocked_messages_title">Blocked messages</string>
|
||||
<string name="blocked_messages_empty">Your blocked messages will appear here</string>
|
||||
|
||||
<string name="blocking_block_title">Block</string>
|
||||
<string name="blocking_unblock_title">Unblock</string>
|
||||
<plurals name="blocking_block_external">
|
||||
|
||||
Reference in New Issue
Block a user