diff --git a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl index 8b5010c86..8242c67be 100644 --- a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl +++ b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl @@ -66,8 +66,7 @@ interface IMeshService { */ void send(inout DataPacket packet); - - void delete(int position); + void deleteMessage(int packetId); void deleteAllMessages(); diff --git a/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt b/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt index 6e98fb5d4..a678034fc 100644 --- a/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt @@ -95,12 +95,12 @@ class MessagesState(private val ui: UIViewModel) : Logging { addMessage(p) } - fun deleteMessage(packet: DataPacket, position: Int) { + fun deleteMessage(packet: DataPacket) { val service = ui.meshService if (service != null) { try { - service.delete(position) + service.deleteMessage(packet.id) } catch (ex: RemoteException) { packet.errorMessage = "Error: ${ex.message}" } @@ -116,7 +116,7 @@ class MessagesState(private val ui: UIViewModel) : Logging { try { service.deleteAllMessages() } catch (ex: RemoteException) { - + errormsg("Error: ${ex.message}") } removeAllMessages() } diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index ec276708d..ac0737ce8 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -1782,10 +1782,12 @@ class MeshService : Service(), Logging { this@MeshService.setOwner(myId, longName, shortName) } - override fun delete(position: Int) { - if (position >= 0) { - recentDataPackets.removeAt(position) - } + 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 deleteAllMessages() { diff --git a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt index 20c6dbc96..cf8edcf2f 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt @@ -123,6 +123,9 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { return ViewHolder(contactViewBinding) } + var messages = arrayOf() + var selectedList = ArrayList() + /** * Returns the total number of items in the data set held by the adapter. * @@ -212,9 +215,114 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { } else holder.messageStatusIcon.visibility = View.INVISIBLE + + holder.itemView.setOnLongClickListener { + 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 -> { + // if all selected -> unselect all + if (selectedList.size == messages.size) { + selectedList.clear() + mode.finish() + } else { + // else --> select all + selectedList.clear() + selectedList.addAll(messages) + } + 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) + } + true + } + holder.itemView.setOnClickListener { + if (actionMode != null) clickItem(holder) + } + + if (selectedList.contains(msg)) { + holder.itemView.background = GradientDrawable().apply { + shape = GradientDrawable.RECTANGLE + cornerRadius = 32f + setColor(Color.rgb(127, 127, 127)) + } + } else { + holder.itemView.background = GradientDrawable().apply { + shape = GradientDrawable.RECTANGLE + cornerRadius = 32f + setColor(ContextCompat.getColor(holder.itemView.context, R.color.colorAdvancedBackground)) + } + } } - private var messages = arrayOf() + private fun clickItem(holder: ViewHolder) { + val position = holder.bindingAdapterPosition + if (!selectedList.contains(messages[position])) { + selectedList.add(messages[position]) + } else { + selectedList.remove(messages[position]) + } + if (selectedList.isEmpty()) { + // finish action mode when no items selected + actionMode?.finish() + } else { + // show total items selected on action mode title + actionMode?.title = "${selectedList.size}" + } + notifyItemChanged(position) + } /// Called when our node DB changes fun onMessagesChanged(msgIn: Collection) {