Merge pull request #415 from meshtastic/cleanup

clean up contacts & messages fragments
pull/418/head
Andre Kirchhoff 2022-04-19 16:32:56 -03:00 zatwierdzone przez GitHub
commit e17cec93c1
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
6 zmienionych plików z 207 dodań i 347 usunięć

Wyświetl plik

@ -66,7 +66,7 @@ interface IMeshService {
*/
void send(inout DataPacket packet);
void deleteMessage(int packetId);
void deleteMessages(in List<DataPacket> deleteList);
void deleteAllMessages();

Wyświetl plik

@ -607,10 +607,7 @@ class MainActivity : BaseActivity(), Logging,
private fun updateNodesFromDevice() {
model.meshService?.let { service ->
// Update our nodeinfos based on data from the device
val nodes = service.nodes.map {
it.user?.id!! to it
}.toMap()
val nodes = service.nodes.associateBy { it.user?.id!! }
model.nodeDB.nodes.value = nodes
try {

Wyświetl plik

@ -77,10 +77,10 @@ class MessagesState(private val ui: UIViewModel) : Logging {
buildContacts()
}
fun removeMessage(m: DataPacket) {
debug("Removing message from view id=${m.id}")
private fun removeMessages(deleteList: List<DataPacket>) {
debug("Removing ${deleteList.size} messages from view")
messagesList.remove(m)
messagesList.removeAll(deleteList)
messages.value = messagesList
buildContacts()
}
@ -128,19 +128,19 @@ class MessagesState(private val ui: UIViewModel) : Logging {
addMessage(p)
}
fun deleteMessage(packet: DataPacket) {
fun deleteMessages(deleteList: List<DataPacket>) {
val service = ui.meshService
if (service != null) {
try {
service.deleteMessage(packet.id)
service.deleteMessages(deleteList)
} catch (ex: RemoteException) {
packet.errorMessage = "Error: ${ex.message}"
debug("Error: ${ex.message}")
}
} else {
packet.errorMessage = "Error: No Mesh service"
debug("Error: No Mesh service")
}
removeMessage(packet)
removeMessages(deleteList)
}
fun deleteAllMessages() {

Wyświetl plik

@ -1796,15 +1796,13 @@ class MeshService : Service(), Logging {
this@MeshService.setOwner(myId, longName, shortName)
}
override fun deleteMessage(packetId: Int) {
val packet = recentDataPackets.find {it.id == packetId}
if (packet != null) {
recentDataPackets.remove(packet)
debug("Deleting message id=${packet.id}")
} else debug("Nothing to delete, message id=${packetId} not found")
override fun deleteMessages(deleteList: List<DataPacket>) {
debug("Deleting ${deleteList.size} messages")
recentDataPackets.removeAll(deleteList)
}
override fun deleteAllMessages() {
debug("Deleting all messages")
recentDataPackets.clear()
}

Wyświetl plik

@ -4,6 +4,8 @@ import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.view.*
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.fragment.app.activityViewModels
@ -12,7 +14,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.geeksville.android.Logging
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.MainActivity
import com.geeksville.mesh.R
import com.geeksville.mesh.databinding.AdapterContactLayoutBinding
import com.geeksville.mesh.databinding.FragmentContactsBinding
@ -25,6 +26,7 @@ import java.util.*
@AndroidEntryPoint
class ContactsFragment : ScreenFragment("Messages"), Logging {
private val actionModeCallback: ActionModeCallback = ActionModeCallback()
private var actionMode: ActionMode? = null
private var _binding: FragmentContactsBinding? = null
@ -33,19 +35,6 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
private val model: UIViewModel by activityViewModels()
private val dateTimeFormat: DateFormat =
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
private val timeFormat: DateFormat =
DateFormat.getTimeInstance(DateFormat.SHORT)
private fun getShortDateTime(time: Date): String {
// return time if within 24 hours, otherwise date/time
val oneDayMsec = 60 * 60 * 24 * 1000L
return if (System.currentTimeMillis() - time.time > oneDayMsec) {
dateTimeFormat.format(time)
} else timeFormat.format(time)
}
// Provide a direct reference to each of the views within a data item
// Used to cache the views within the item layout for fast access
class ViewHolder(itemView: AdapterContactLayoutBinding) :
@ -58,29 +47,19 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
private val contactsAdapter = object : RecyclerView.Adapter<ViewHolder>() {
/**
* Called when RecyclerView needs a new [ViewHolder] of the given type to represent
* an item.
*
*
* This new ViewHolder should be constructed with a new View that can represent the items
* of the given type. You can either create a new View manually or inflate it from an XML
* layout file.
*
*
* The new ViewHolder will be used to display items of the adapter using
* [.onBindViewHolder]. Since it will be re-used to display
* different items in the data set, it is a good idea to cache references to sub views of
* the View to avoid unnecessary [View.findViewById] calls.
*
* @param parent The ViewGroup into which the new View will be added after it is bound to
* an adapter position.
* @param viewType The view type of the new View.
*
* @return A new ViewHolder that holds a View of the given view type.
* @see .getItemViewType
* @see .onBindViewHolder
*/
private val dateTimeFormat: DateFormat =
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
private val timeFormat: DateFormat =
DateFormat.getTimeInstance(DateFormat.SHORT)
private fun getShortDateTime(time: Date): String {
// return time if within 24 hours, otherwise date/time
val oneDayMsec = 60 * 60 * 24 * 1000L
return if (System.currentTimeMillis() - time.time > oneDayMsec) {
dateTimeFormat.format(time)
} else timeFormat.format(time)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(requireContext())
@ -91,38 +70,11 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
return ViewHolder(contactsView)
}
private var messages = arrayOf<DataPacket>()
private var contacts = arrayOf<DataPacket>()
private var selectedList = ArrayList<String>()
var contacts = arrayOf<DataPacket>()
var selectedList = ArrayList<String>()
/**
* Returns the total number of items in the data set held by the adapter.
*
* @return The total number of items in this adapter.
*/
override fun getItemCount(): Int = contacts.size
/**
* Called by RecyclerView to display the data at the specified position. This method should
* update the contents of the [ViewHolder.itemView] to reflect the item at the given
* position.
*
*
* Note that unlike [android.widget.ListView], RecyclerView will not call this method
* again if the position of the item changes in the data set unless the item itself is
* invalidated or the new position cannot be determined. For this reason, you should only
* use the `position` parameter while acquiring the related data item inside
* this method and should not keep a copy of it. If you need the position of an item later
* on (e.g. in a click listener), use [ViewHolder.getAdapterPosition] which will
* have the updated adapter position.
*
* Override [.onBindViewHolder] instead if Adapter can
* handle efficient partial bind.
*
* @param holder The ViewHolder which should be updated to represent the contents of the
* item at the given position in the data set.
* @param position The position of the item within the adapter's data set.
*/
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val contact = contacts[position]
@ -156,92 +108,10 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
} else holder.lastMessageTime.visibility = View.INVISIBLE
holder.itemView.setOnLongClickListener {
clickItem(holder, contactId)
if (actionMode == null) {
actionMode =
(activity as MainActivity).startActionMode(object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.menu_messages, menu)
mode.title = "1"
return true
}
override fun onPrepareActionMode(
mode: ActionMode,
menu: Menu
): Boolean {
clickItem(holder, contactId)
return true
}
override fun onActionItemClicked(
mode: ActionMode,
item: MenuItem
): Boolean {
when (item.itemId) {
R.id.deleteButton -> {
val messagesByContactId = ArrayList<DataPacket>()
selectedList.forEach { contactId ->
messagesByContactId += messages.filter {
if (contactId == DataPacket.ID_BROADCAST)
it.to == DataPacket.ID_BROADCAST
else
it.from == contactId && it.to != DataPacket.ID_BROADCAST
|| it.from == DataPacket.ID_LOCAL && it.to == contactId
}
}
val deleteMessagesString = resources.getQuantityString(
R.plurals.delete_messages,
messagesByContactId.size,
messagesByContactId.size
)
MaterialAlertDialogBuilder(requireContext())
.setMessage(deleteMessagesString)
.setPositiveButton(getString(R.string.delete)) { _, _ ->
debug("User clicked deleteButton")
// all items selected --> deleteAllMessages()
if (messagesByContactId.size == messages.size) {
model.messagesState.deleteAllMessages()
} else {
messagesByContactId.forEach {
model.messagesState.deleteMessage(it)
}
}
mode.finish()
}
.setNeutralButton(R.string.cancel) { _, _ ->
}
.show()
}
R.id.selectAllButton -> {
// if all selected -> unselect all
if (selectedList.size == contacts.size) {
selectedList.clear()
mode.finish()
} else {
// else --> select all
selectedList.clear()
contacts.forEach {
if (it.from == DataPacket.ID_LOCAL || it.to == DataPacket.ID_BROADCAST)
selectedList.add(it.to!!) else selectedList.add(it.from!!)
}
}
actionMode?.title = selectedList.size.toString()
notifyDataSetChanged()
}
}
return true
}
override fun onDestroyActionMode(mode: ActionMode) {
selectedList.clear()
notifyDataSetChanged()
actionMode = null
}
})
} else {
// when action mode is enabled
clickItem(holder, contactId)
(activity as AppCompatActivity).startSupportActionMode(actionModeCallback)
}
true
}
@ -280,10 +150,7 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
}
}
private fun clickItem(
holder: ViewHolder,
contactId: String? = DataPacket.ID_BROADCAST
) {
private fun clickItem(holder: ViewHolder, contactId: String? = DataPacket.ID_BROADCAST) {
val position = holder.bindingAdapterPosition
if (contactId != null && !selectedList.contains(contactId)) {
selectedList.add(contactId)
@ -306,11 +173,6 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
notifyDataSetChanged() // FIXME, this is super expensive and redraws all nodes
}
/// Called when our message DB changes
fun onMessagesChanged(msgIn: Collection<DataPacket>) {
messages = msgIn.toTypedArray()
}
fun onChannelsChanged() {
val oldBroadcast = contacts.find { it.to == DataPacket.ID_BROADCAST }
if (oldBroadcast != null) {
@ -346,9 +208,80 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
debug("New contacts received: ${it.size}")
contactsAdapter.onContactsChanged(it.values)
}
}
model.messagesState.messages.observe(viewLifecycleOwner) {
contactsAdapter.onMessagesChanged(it)
private inner class ActionModeCallback : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.menu_messages, menu)
menu.findItem(R.id.resendButton).isVisible = false
mode.title = "1"
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
return false
}
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
when (item.itemId) {
R.id.deleteButton -> {
val messagesTotal = model.messagesState.messages.value!!
val selectedList = contactsAdapter.selectedList
val deleteList = ArrayList<DataPacket>()
// find messages for each contactId
selectedList.forEach { contactId ->
deleteList += messagesTotal.filter {
if (contactId == DataPacket.ID_BROADCAST)
it.to == DataPacket.ID_BROADCAST || it.delayed == 1 // MeshPacket.Delayed.DELAYED_BROADCAST_VALUE == 1
else it.from == contactId && it.to != DataPacket.ID_BROADCAST || it.from == DataPacket.ID_LOCAL && it.to == contactId
}
}
val deleteMessagesString = resources.getQuantityString(
R.plurals.delete_messages,
deleteList.size,
deleteList.size
)
MaterialAlertDialogBuilder(requireContext())
.setMessage(deleteMessagesString)
.setPositiveButton(getString(R.string.delete)) { _, _ ->
debug("User clicked deleteButton")
// all items selected --> deleteAllMessages()
if (deleteList.size == messagesTotal.size) {
model.messagesState.deleteAllMessages()
} else {
model.messagesState.deleteMessages(deleteList)
}
mode.finish()
}
.setNeutralButton(R.string.cancel) { _, _ ->
}
.show()
}
R.id.selectAllButton -> {
// if all selected -> unselect all
if (contactsAdapter.selectedList.size == contactsAdapter.contacts.size) {
contactsAdapter.selectedList.clear()
mode.finish()
} else {
// else --> select all
contactsAdapter.selectedList.clear()
contactsAdapter.contacts.forEach {
if (it.from == DataPacket.ID_LOCAL || it.to == DataPacket.ID_BROADCAST)
contactsAdapter.selectedList.add(it.to!!)
else contactsAdapter.selectedList.add(it.from!!)
}
}
actionMode?.title = contactsAdapter.selectedList.size.toString()
contactsAdapter.notifyDataSetChanged()
}
}
return true
}
override fun onDestroyActionMode(mode: ActionMode) {
contactsAdapter.selectedList.clear()
contactsAdapter.notifyDataSetChanged()
actionMode = null
}
}
}

Wyświetl plik

@ -9,6 +9,8 @@ import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.cardview.widget.CardView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
@ -18,7 +20,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.geeksville.android.Logging
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.MainActivity
import com.geeksville.mesh.MessageStatus
import com.geeksville.mesh.R
import com.geeksville.mesh.databinding.AdapterMessageLayoutBinding
@ -45,6 +46,7 @@ fun EditText.on(actionId: Int, func: () -> Unit) {
@AndroidEntryPoint
class MessagesFragment : Fragment(), Logging {
private val actionModeCallback: ActionModeCallback = ActionModeCallback()
private var actionMode: ActionMode? = null
private var _binding: MessagesFragmentBinding? = null
@ -69,19 +71,6 @@ class MessagesFragment : Fragment(), Logging {
}
}
private val dateTimeFormat: DateFormat =
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
private val timeFormat: DateFormat =
DateFormat.getTimeInstance(DateFormat.SHORT)
private fun getShortDateTime(time: Date): String {
// return time if within 24 hours, otherwise date/time
val oneDayMsec = 60 * 60 * 24 * 1000L
return if (System.currentTimeMillis() - time.time > oneDayMsec) {
dateTimeFormat.format(time)
} else timeFormat.format(time)
}
// Provide a direct reference to each of the views within a data item
// Used to cache the views within the item layout for fast access
class ViewHolder(itemView: AdapterMessageLayoutBinding) :
@ -95,29 +84,19 @@ class MessagesFragment : Fragment(), Logging {
private val messagesAdapter = object : RecyclerView.Adapter<ViewHolder>() {
/**
* Called when RecyclerView needs a new [ViewHolder] of the given type to represent
* an item.
*
*
* This new ViewHolder should be constructed with a new View that can represent the items
* of the given type. You can either create a new View manually or inflate it from an XML
* layout file.
*
*
* The new ViewHolder will be used to display items of the adapter using
* [.onBindViewHolder]. Since it will be re-used to display
* different items in the data set, it is a good idea to cache references to sub views of
* the View to avoid unnecessary [View.findViewById] calls.
*
* @param parent The ViewGroup into which the new View will be added after it is bound to
* an adapter position.
* @param viewType The view type of the new View.
*
* @return A new ViewHolder that holds a View of the given view type.
* @see .getItemViewType
* @see .onBindViewHolder
*/
private val dateTimeFormat: DateFormat =
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
private val timeFormat: DateFormat =
DateFormat.getTimeInstance(DateFormat.SHORT)
private fun getShortDateTime(time: Date): String {
// return time if within 24 hours, otherwise date/time
val oneDayMsec = 60 * 60 * 24 * 1000L
return if (System.currentTimeMillis() - time.time > oneDayMsec) {
dateTimeFormat.format(time)
} else timeFormat.format(time)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(requireContext())
@ -131,54 +110,14 @@ class MessagesFragment : Fragment(), Logging {
var messages = arrayOf<DataPacket>()
var selectedList = ArrayList<DataPacket>()
/**
* Returns the total number of items in the data set held by the adapter.
*
* @return The total number of items in this adapter.
*/
override fun getItemCount(): Int = messages.size
/**
* Called by RecyclerView to display the data at the specified position. This method should
* update the contents of the [ViewHolder.itemView] to reflect the item at the given
* position.
*
*
* Note that unlike [android.widget.ListView], RecyclerView will not call this method
* again if the position of the item changes in the data set unless the item itself is
* invalidated or the new position cannot be determined. For this reason, you should only
* use the `position` parameter while acquiring the related data item inside
* this method and should not keep a copy of it. If you need the position of an item later
* on (e.g. in a click listener), use [ViewHolder.getAdapterPosition] which will
* have the updated adapter position.
*
* Override [.onBindViewHolder] instead if Adapter can
* handle efficient partial bind.
*
* @param holder The ViewHolder which should be updated to represent the contents of the
* item at the given position in the data set.
* @param position The position of the item within the adapter's data set.
*/
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val msg = messages[position]
val nodes = model.nodeDB.nodes.value!!
val node = nodes.get(msg.from)
val node = nodes[msg.from]
// Determine if this is my message (originated on this device)
val isLocal = msg.from == DataPacket.ID_LOCAL
val isBroadcast = (msg.to == DataPacket.ID_BROADCAST
|| msg.delayed == 1) // MeshProtos.MeshPacket.Delayed.DELAYED_BROADCAST_VALUE == 1
// Filter messages by contactId
if (contactId == DataPacket.ID_BROADCAST) {
if (isBroadcast) {
holder.card.visibility = View.VISIBLE
} else holder.card.visibility = View.GONE
} else {
if (msg.from == contactId && msg.to != DataPacket.ID_BROADCAST
|| msg.from == DataPacket.ID_LOCAL && msg.to == contactId) {
holder.card.visibility = View.VISIBLE
} else holder.card.visibility = View.GONE
}
// Set cardview offset and color.
val marginParams = holder.card.layoutParams as ViewGroup.MarginLayoutParams
@ -237,98 +176,14 @@ class MessagesFragment : Fragment(), Logging {
if (icon != null) {
holder.messageStatusIcon.setImageResource(icon)
holder.messageStatusIcon.visibility = View.VISIBLE
} else
holder.messageStatusIcon.visibility = View.INVISIBLE
holder.messageStatusIcon.visibility = View.GONE
holder.itemView.setOnLongClickListener {
clickItem(holder)
if (actionMode == null) {
actionMode = (activity as MainActivity).startActionMode(object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.menu_messages, menu)
mode.title = "1"
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
clickItem(holder)
return true
}
override fun onActionItemClicked(
mode: ActionMode,
item: MenuItem
): Boolean {
when (item.itemId) {
R.id.deleteButton -> {
val deleteMessagesString = resources.getQuantityString(
R.plurals.delete_messages,
selectedList.size,
selectedList.size
)
MaterialAlertDialogBuilder(requireContext())
.setMessage(deleteMessagesString)
.setPositiveButton(getString(R.string.delete)) { _, _ ->
debug("User clicked deleteButton")
// all items selected --> deleteAllMessages()
if (selectedList.size == messages.size) {
model.messagesState.deleteAllMessages()
} else {
selectedList.forEach {
model.messagesState.deleteMessage(it)
}
}
mode.finish()
}
.setNeutralButton(R.string.cancel) { _, _ ->
}
.show()
}
R.id.selectAllButton -> {
// filter messages by ContactId
val messagesByContactId = messages.filter {
if (contactId == DataPacket.ID_BROADCAST)
it.to == DataPacket.ID_BROADCAST
else
it.from == contactId && it.to != DataPacket.ID_BROADCAST
|| it.from == DataPacket.ID_LOCAL && it.to == contactId
}
// if all selected -> unselect all
if (selectedList.size == messagesByContactId.size) {
selectedList.clear()
mode.finish()
} else {
// else --> select all
selectedList.clear()
selectedList.addAll(messagesByContactId)
}
actionMode?.title = selectedList.size.toString()
notifyDataSetChanged()
}
R.id.resendButton -> {
debug("User clicked resendButton")
var resendText = ""
selectedList.forEach {
resendText = resendText + it.text + System.lineSeparator()
}
if (resendText!="")
resendText = resendText.substring(0, resendText.length - 1)
binding.messageInputText.setText(resendText)
mode.finish()
}
}
return true
}
override fun onDestroyActionMode(mode: ActionMode) {
selectedList.clear()
notifyDataSetChanged()
actionMode = null
}
})
} else {
// when action mode is enabled
clickItem(holder)
actionMode =
(activity as AppCompatActivity).startSupportActionMode(actionModeCallback)
}
true
}
@ -370,7 +225,11 @@ class MessagesFragment : Fragment(), Logging {
/// Called when our node DB changes
fun onMessagesChanged(msgIn: Collection<DataPacket>) {
messages = msgIn.toTypedArray()
messages = msgIn.filter {
if (contactId == DataPacket.ID_BROADCAST)
it.to == DataPacket.ID_BROADCAST || it.delayed == 1 // MeshPacket.Delayed.DELAYED_BROADCAST_VALUE == 1
else it.from == contactId && it.to != DataPacket.ID_BROADCAST || it.from == DataPacket.ID_LOCAL && it.to == contactId
}.toTypedArray()
notifyDataSetChanged() // FIXME, this is super expensive and redraws all messages
// scroll to the last line
@ -445,4 +304,77 @@ class MessagesFragment : Fragment(), Logging {
// && model.nodeDB.myId.value != null && model.radioConfig.value != null
}
}
private inner class ActionModeCallback : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.menu_messages, menu)
mode.title = "1"
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
return false
}
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
when (item.itemId) {
R.id.deleteButton -> {
val selectedList = messagesAdapter.selectedList
val deleteMessagesString = resources.getQuantityString(
R.plurals.delete_messages,
selectedList.size,
selectedList.size
)
MaterialAlertDialogBuilder(requireContext())
.setMessage(deleteMessagesString)
.setPositiveButton(getString(R.string.delete)) { _, _ ->
debug("User clicked deleteButton")
// all items selected --> deleteAllMessages()
val messagesTotal = model.messagesState.messages.value
if (messagesTotal != null && selectedList.size == messagesTotal.size) {
model.messagesState.deleteAllMessages()
} else {
model.messagesState.deleteMessages(selectedList)
}
mode.finish()
}
.setNeutralButton(R.string.cancel) { _, _ ->
}
.show()
}
R.id.selectAllButton -> {
// if all selected -> unselect all
if (messagesAdapter.selectedList.size == messagesAdapter.messages.size) {
messagesAdapter.selectedList.clear()
mode.finish()
} else {
// else --> select all
messagesAdapter.selectedList.clear()
messagesAdapter.selectedList.addAll(messagesAdapter.messages)
}
actionMode?.title = messagesAdapter.selectedList.size.toString()
messagesAdapter.notifyDataSetChanged()
}
R.id.resendButton -> {
debug("User clicked resendButton")
val selectedList = messagesAdapter.selectedList
var resendText = ""
selectedList.forEach {
resendText = resendText + it.text + System.lineSeparator()
}
if (resendText!="")
resendText = resendText.substring(0, resendText.length - 1)
binding.messageInputText.setText(resendText)
mode.finish()
}
}
return true
}
override fun onDestroyActionMode(mode: ActionMode) {
messagesAdapter.selectedList.clear()
messagesAdapter.notifyDataSetChanged()
actionMode = null
}
}
}