mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-10 23:32:30 +00:00
Merge pull request #1205 from bemusementpark/disable-unblock
Disable unblock button
This commit is contained in:
@@ -276,7 +276,7 @@ public class RecipientDatabase extends Database {
|
||||
notifyRecipientListeners();
|
||||
}
|
||||
|
||||
public void setBlocked(@NonNull List<Recipient> recipients, boolean blocked) {
|
||||
public void setBlocked(@NonNull Iterable<Recipient> recipients, boolean blocked) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
db.beginTransaction();
|
||||
try {
|
||||
|
||||
@@ -1010,7 +1010,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
||||
DatabaseComponent.get(context).reactionDatabase().deleteMessageReactions(MessageId(messageId, mms))
|
||||
}
|
||||
|
||||
override fun unblock(toUnblock: List<Recipient>) {
|
||||
override fun unblock(toUnblock: Iterable<Recipient>) {
|
||||
val recipientDb = DatabaseComponent.get(context).recipientDatabase()
|
||||
recipientDb.setBlocked(toUnblock, false)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.preferences
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.view.isVisible
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
@@ -11,58 +10,26 @@ import network.loki.messenger.databinding.ActivityBlockedContactsBinding
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
|
||||
@AndroidEntryPoint
|
||||
class BlockedContactsActivity: PassphraseRequiredActionBarActivity(), View.OnClickListener {
|
||||
class BlockedContactsActivity: PassphraseRequiredActionBarActivity() {
|
||||
|
||||
lateinit var binding: ActivityBlockedContactsBinding
|
||||
|
||||
val viewModel: BlockedContactsViewModel by viewModels()
|
||||
|
||||
val adapter = BlockedContactsAdapter()
|
||||
val adapter: BlockedContactsAdapter by lazy { BlockedContactsAdapter(viewModel) }
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
if (v === binding.unblockButton && adapter.getSelectedItems().isNotEmpty()) {
|
||||
val contactsToUnblock = adapter.getSelectedItems()
|
||||
// show dialog
|
||||
val title = if (contactsToUnblock.size == 1) {
|
||||
getString(R.string.Unblock_dialog__title_single, contactsToUnblock.first().name)
|
||||
} else {
|
||||
getString(R.string.Unblock_dialog__title_multiple)
|
||||
}
|
||||
fun unblock() {
|
||||
// show dialog
|
||||
val title = viewModel.getTitle(this)
|
||||
|
||||
val message = if (contactsToUnblock.size == 1) {
|
||||
getString(R.string.Unblock_dialog__message, contactsToUnblock.first().name)
|
||||
} else {
|
||||
val stringBuilder = StringBuilder()
|
||||
val iterator = contactsToUnblock.iterator()
|
||||
var numberAdded = 0
|
||||
while (iterator.hasNext() && numberAdded < 3) {
|
||||
val nextRecipient = iterator.next()
|
||||
if (numberAdded > 0) stringBuilder.append(", ")
|
||||
|
||||
stringBuilder.append(nextRecipient.name)
|
||||
numberAdded++
|
||||
}
|
||||
val overflow = contactsToUnblock.size - numberAdded
|
||||
if (overflow > 0) {
|
||||
stringBuilder.append(" ")
|
||||
val string = resources.getQuantityString(R.plurals.Unblock_dialog__message_multiple_overflow, overflow)
|
||||
stringBuilder.append(string.format(overflow))
|
||||
}
|
||||
getString(R.string.Unblock_dialog__message, stringBuilder.toString())
|
||||
}
|
||||
val message = viewModel.getMessage(this)
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.continue_2) { d, _ ->
|
||||
viewModel.unblock(contactsToUnblock)
|
||||
d.dismiss()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { d, _ ->
|
||||
d.dismiss()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.continue_2) { _, _ -> viewModel.unblock() }
|
||||
.setNegativeButton(R.string.cancel) { _, _ -> }
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
|
||||
@@ -73,15 +40,15 @@ class BlockedContactsActivity: PassphraseRequiredActionBarActivity(), View.OnCli
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
viewModel.subscribe(this)
|
||||
.observe(this) { newState ->
|
||||
adapter.submitList(newState.blockedContacts)
|
||||
val isEmpty = newState.blockedContacts.isEmpty()
|
||||
binding.emptyStateMessageTextView.isVisible = isEmpty
|
||||
binding.nonEmptyStateGroup.isVisible = !isEmpty
|
||||
.observe(this) { state ->
|
||||
adapter.submitList(state.items)
|
||||
binding.emptyStateMessageTextView.isVisible = state.emptyStateMessageTextViewVisible
|
||||
binding.nonEmptyStateGroup.isVisible = state.nonEmptyStateGroupVisible
|
||||
binding.unblockButton.isEnabled = state.unblockButtonEnabled
|
||||
}
|
||||
|
||||
binding.unblockButton.setOnClickListener(this)
|
||||
binding.unblockButton.setOnClickListener { unblock() }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,38 +10,30 @@ import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.BlockedContactLayoutBinding
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.util.adapter.SelectableItem
|
||||
|
||||
class BlockedContactsAdapter: ListAdapter<Recipient,BlockedContactsAdapter.ViewHolder>(RecipientDiffer()) {
|
||||
typealias SelectableRecipient = SelectableItem<Recipient>
|
||||
|
||||
class RecipientDiffer: DiffUtil.ItemCallback<Recipient>() {
|
||||
override fun areItemsTheSame(oldItem: Recipient, newItem: Recipient) = oldItem === newItem
|
||||
override fun areContentsTheSame(oldItem: Recipient, newItem: Recipient) = oldItem == newItem
|
||||
class BlockedContactsAdapter(val viewModel: BlockedContactsViewModel) : ListAdapter<SelectableRecipient,BlockedContactsAdapter.ViewHolder>(RecipientDiffer()) {
|
||||
|
||||
class RecipientDiffer: DiffUtil.ItemCallback<SelectableRecipient>() {
|
||||
override fun areItemsTheSame(old: SelectableRecipient, new: SelectableRecipient) = old.item.address == new.item.address
|
||||
override fun areContentsTheSame(old: SelectableRecipient, new: SelectableRecipient) = old.isSelected == new.isSelected
|
||||
override fun getChangePayload(old: SelectableRecipient, new: SelectableRecipient) = new.isSelected
|
||||
}
|
||||
|
||||
private val selectedItems = mutableListOf<Recipient>()
|
||||
|
||||
fun getSelectedItems() = selectedItems
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.blocked_contact_layout, parent, false)
|
||||
return ViewHolder(itemView)
|
||||
}
|
||||
|
||||
private fun toggleSelection(recipient: Recipient, isSelected: Boolean, position: Int) {
|
||||
if (isSelected) {
|
||||
selectedItems -= recipient
|
||||
} else {
|
||||
selectedItems += recipient
|
||||
}
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.blocked_contact_layout, parent, false)
|
||||
.let(::ViewHolder)
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val recipient = getItem(position)
|
||||
val isSelected = recipient in selectedItems
|
||||
holder.bind(recipient, isSelected) {
|
||||
toggleSelection(recipient, isSelected, position)
|
||||
}
|
||||
holder.bind(getItem(position), viewModel::toggle)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
if (payloads.isEmpty()) holder.bind(getItem(position), viewModel::toggle)
|
||||
else holder.select(getItem(position).isSelected)
|
||||
}
|
||||
|
||||
override fun onViewRecycled(holder: ViewHolder) {
|
||||
@@ -54,15 +46,18 @@ class BlockedContactsAdapter: ListAdapter<Recipient,BlockedContactsAdapter.ViewH
|
||||
val glide = GlideApp.with(itemView)
|
||||
val binding = BlockedContactLayoutBinding.bind(itemView)
|
||||
|
||||
fun bind(recipient: Recipient, isSelected: Boolean, toggleSelection: () -> Unit) {
|
||||
binding.recipientName.text = recipient.name
|
||||
fun bind(selectable: SelectableRecipient, toggle: (SelectableRecipient) -> Unit) {
|
||||
binding.recipientName.text = selectable.item.name
|
||||
with (binding.profilePictureView.root) {
|
||||
glide = this@ViewHolder.glide
|
||||
update(recipient)
|
||||
update(selectable.item)
|
||||
}
|
||||
binding.root.setOnClickListener { toggleSelection() }
|
||||
binding.root.setOnClickListener { toggle(selectable) }
|
||||
binding.selectButton.isSelected = selectable.isSelected
|
||||
}
|
||||
|
||||
fun select(isSelected: Boolean) {
|
||||
binding.selectButton.isSelected = isSelected
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.plus
|
||||
import kotlinx.coroutines.withContext
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.database.DatabaseContentProviders
|
||||
import org.thoughtcrime.securesms.database.Storage
|
||||
import org.thoughtcrime.securesms.util.adapter.SelectableItem
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -29,7 +31,9 @@ class BlockedContactsViewModel @Inject constructor(private val storage: Storage)
|
||||
|
||||
private val listUpdateChannel = Channel<Unit>(capacity = Channel.CONFLATED)
|
||||
|
||||
private val _contacts = MutableLiveData(BlockedContactsViewState(emptyList()))
|
||||
private val _state = MutableLiveData(BlockedContactsViewState())
|
||||
|
||||
val state get() = _state.value!!
|
||||
|
||||
fun subscribe(context: Context): LiveData<BlockedContactsViewState> {
|
||||
executor.launch(IO) {
|
||||
@@ -45,21 +49,74 @@ class BlockedContactsViewModel @Inject constructor(private val storage: Storage)
|
||||
}
|
||||
executor.launch(IO) {
|
||||
for (update in listUpdateChannel) {
|
||||
val blockedContactState = BlockedContactsViewState(storage.blockedContacts().sortedBy { it.name })
|
||||
val blockedContactState = state.copy(
|
||||
blockedContacts = storage.blockedContacts().sortedBy { it.name }
|
||||
)
|
||||
withContext(Main) {
|
||||
_contacts.value = blockedContactState
|
||||
_state.value = blockedContactState
|
||||
}
|
||||
}
|
||||
}
|
||||
return _contacts
|
||||
return _state
|
||||
}
|
||||
|
||||
fun unblock(toUnblock: List<Recipient>) {
|
||||
storage.unblock(toUnblock)
|
||||
fun unblock() {
|
||||
storage.unblock(state.selectedItems)
|
||||
_state.value = state.copy(selectedItems = emptySet())
|
||||
}
|
||||
|
||||
fun select(selectedItem: Recipient, isSelected: Boolean) {
|
||||
_state.value = state.run {
|
||||
if (isSelected) copy(selectedItems = selectedItems + selectedItem)
|
||||
else copy(selectedItems = selectedItems - selectedItem)
|
||||
}
|
||||
}
|
||||
|
||||
fun getTitle(context: Context): String =
|
||||
if (state.selectedItems.size == 1) {
|
||||
context.getString(R.string.Unblock_dialog__title_single, state.selectedItems.first().name)
|
||||
} else {
|
||||
context.getString(R.string.Unblock_dialog__title_multiple)
|
||||
}
|
||||
|
||||
fun getMessage(context: Context): String {
|
||||
if (state.selectedItems.size == 1) {
|
||||
return context.getString(R.string.Unblock_dialog__message, state.selectedItems.first().name)
|
||||
}
|
||||
val stringBuilder = StringBuilder()
|
||||
val iterator = state.selectedItems.iterator()
|
||||
var numberAdded = 0
|
||||
while (iterator.hasNext() && numberAdded < 3) {
|
||||
val nextRecipient = iterator.next()
|
||||
if (numberAdded > 0) stringBuilder.append(", ")
|
||||
|
||||
stringBuilder.append(nextRecipient.name)
|
||||
numberAdded++
|
||||
}
|
||||
val overflow = state.selectedItems.size - numberAdded
|
||||
if (overflow > 0) {
|
||||
stringBuilder.append(" ")
|
||||
val string = context.resources.getQuantityString(R.plurals.Unblock_dialog__message_multiple_overflow, overflow)
|
||||
stringBuilder.append(string.format(overflow))
|
||||
}
|
||||
return context.getString(R.string.Unblock_dialog__message, stringBuilder.toString())
|
||||
}
|
||||
|
||||
fun toggle(selectable: SelectableItem<Recipient>) {
|
||||
_state.value = state.run {
|
||||
if (selectable.item in selectedItems) copy(selectedItems = selectedItems - selectable.item)
|
||||
else copy(selectedItems = selectedItems + selectable.item)
|
||||
}
|
||||
}
|
||||
|
||||
data class BlockedContactsViewState(
|
||||
val blockedContacts: List<Recipient>
|
||||
)
|
||||
val blockedContacts: List<Recipient> = emptyList(),
|
||||
val selectedItems: Set<Recipient> = emptySet()
|
||||
) {
|
||||
val items = blockedContacts.map { SelectableItem(it, it in selectedItems) }
|
||||
|
||||
}
|
||||
val unblockButtonEnabled get() = selectedItems.isNotEmpty()
|
||||
val emptyStateMessageTextViewVisible get() = blockedContacts.isEmpty()
|
||||
val nonEmptyStateGroupVisible get() = blockedContacts.isNotEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.thoughtcrime.securesms.util.adapter
|
||||
|
||||
data class SelectableItem<T>(val item: T, val isSelected: Boolean)
|
||||
Reference in New Issue
Block a user