From c08c652d97a3c002d4c34376fa8163244999de0f Mon Sep 17 00:00:00 2001 From: Jackson Rosenthal Date: Fri, 28 Jan 2022 21:40:05 -0500 Subject: [PATCH 1/6] Testing click deletion of messages. (Messages still stored after sending new message or connecting to radio) --- .../geeksville/mesh/model/MessagesState.kt | 23 +++++++++++++++++++ .../geeksville/mesh/ui/MessagesFragment.kt | 16 ++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) 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 dd8828804..8a5a78b7e 100644 --- a/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt @@ -46,6 +46,13 @@ class MessagesState(private val ui: UIViewModel) : Logging { messages.value = messagesList } + fun removeMessage(m: DataPacket) { + debug("Removing message from view id=${m.id}") + + messagesList.remove(m) + messages.value = messagesList; + } + fun updateStatus(id: Int, status: MessageStatus) { // Super inefficent but this is rare debug("Handling message status change $id: $status") @@ -80,4 +87,20 @@ class MessagesState(private val ui: UIViewModel) : Logging { // FIXME - why is the first time we are called p is already in the list at this point? addMessage(p) } + + fun deleteMessage(str: String, dest: String = DataPacket.ID_BROADCAST) { + val service = ui.meshService + val p = DataPacket(str, dest) + + if (service != null) { + try { + service.send(p) + } catch (ex: RemoteException) { + p.errorMessage = "Error: ${ex.message}" + } + } else { + p.errorMessage = "Error: No Mesh service" + } + removeMessage(p) + } } 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 28db58802..08c90e798 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt @@ -48,7 +48,7 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { private val binding get() = _binding!! private val model: UIViewModel by activityViewModels() - + // Allows textMultiline with IME_ACTION_SEND fun EditText.onActionSend(func: () -> Unit) { setImeOptions(EditorInfo.IME_ACTION_SEND) @@ -164,6 +164,10 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { // Set cardview offset and color. val marginParams = holder.card.layoutParams as ViewGroup.MarginLayoutParams val messageOffset = resources.getDimensionPixelOffset(R.dimen.message_offset) + holder.card.setOnLongClickListener { + this.onLongCLick(position) + true + } if (isMe) { marginParams.leftMargin = messageOffset marginParams.rightMargin = 0 @@ -232,6 +236,12 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { if (itemCount != 0) binding.messageListView.scrollToPosition(itemCount - 1) } + + fun onLongCLick(position: Int) { + messages = messages.filter { x -> x != messages[position] }.toTypedArray() + onMessagesChanged(messages.toList()) + } + } override fun onCreateView( @@ -282,8 +292,8 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { binding.textInputLayout.isEnabled = model.isConnected.value != MeshService.ConnectionState.DISCONNECTED - // Just being connected is enough to allow sending texts I think - // && model.nodeDB.myId.value != null && model.radioConfig.value != null + // Just being connected is enough to allow sending texts I think + // && model.nodeDB.myId.value != null && model.radioConfig.value != null } model.isConnected.observe(viewLifecycleOwner, Observer { _ -> From e27a76633c0f10ae698621ba519d5778a633e34b Mon Sep 17 00:00:00 2001 From: Jackson Rosenthal Date: Sat, 29 Jan 2022 14:31:08 -0500 Subject: [PATCH 2/6] Delete messages from view by long clicking. Looking into clearing "all messages" & menu for deleting individual messages --- .../aidl/com/geeksville/mesh/IMeshService.aidl | 3 +++ .../com/geeksville/mesh/model/MessagesState.kt | 13 ++++++------- .../com/geeksville/mesh/service/MeshService.kt | 14 ++++++++++---- .../com/geeksville/mesh/ui/MessagesFragment.kt | 8 +------- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl index 46d90f282..56b6090fc 100644 --- a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl +++ b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl @@ -66,6 +66,9 @@ interface IMeshService { */ void send(inout DataPacket packet); + + void delete(int position); + /** Get the IDs of everyone on the mesh. You should also subscribe for NODE_CHANGE broadcasts. */ 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 8a5a78b7e..60c7a5784 100644 --- a/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt @@ -50,7 +50,7 @@ class MessagesState(private val ui: UIViewModel) : Logging { debug("Removing message from view id=${m.id}") messagesList.remove(m) - messages.value = messagesList; + messages.value = messagesList } fun updateStatus(id: Int, status: MessageStatus) { @@ -88,19 +88,18 @@ class MessagesState(private val ui: UIViewModel) : Logging { addMessage(p) } - fun deleteMessage(str: String, dest: String = DataPacket.ID_BROADCAST) { + fun deleteMessage(packet: DataPacket, position: Int) { val service = ui.meshService - val p = DataPacket(str, dest) if (service != null) { try { - service.send(p) + service.delete(position) } catch (ex: RemoteException) { - p.errorMessage = "Error: ${ex.message}" + packet.errorMessage = "Error: ${ex.message}" } } else { - p.errorMessage = "Error: No Mesh service" + packet.errorMessage = "Error: No Mesh service" } - removeMessage(p) + removeMessage(packet) } } 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 a326ca8ec..8790e0d4b 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -1018,10 +1018,10 @@ class MeshService : Service(), Logging { else broadcastSecs * 1000L - if (prefs.locationShare == RadioConfigProtos.LocationSharing.LocDisabled) { - info("GPS location sharing is disabled") - desiredInterval = 0 - } + if (prefs.locationShare == RadioConfigProtos.LocationSharing.LocDisabled) { + info("GPS location sharing is disabled") + desiredInterval = 0 + } // if (prefs.fixedPosition) { // info("Node has fixed position, therefore not overriding position") @@ -1783,6 +1783,12 @@ class MeshService : Service(), Logging { this@MeshService.setOwner(myId, longName, shortName) } + override fun delete(position: Int) { + if (position >= 0) { + recentDataPackets.removeAt(position) + } + } + override fun send(p: DataPacket) { toRemoteExceptions { // Init from and id 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 08c90e798..5c043f01f 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt @@ -165,7 +165,7 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { val marginParams = holder.card.layoutParams as ViewGroup.MarginLayoutParams val messageOffset = resources.getDimensionPixelOffset(R.dimen.message_offset) holder.card.setOnLongClickListener { - this.onLongCLick(position) + model.messagesState.deleteMessage(messages[position], position) true } if (isMe) { @@ -236,12 +236,6 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { if (itemCount != 0) binding.messageListView.scrollToPosition(itemCount - 1) } - - fun onLongCLick(position: Int) { - messages = messages.filter { x -> x != messages[position] }.toTypedArray() - onMessagesChanged(messages.toList()) - } - } override fun onCreateView( From bc0c682eea7acc080cd08e07430f2aafb9f8925b Mon Sep 17 00:00:00 2001 From: Jackson Rosenthal Date: Sat, 29 Jan 2022 18:00:24 -0500 Subject: [PATCH 3/6] Added popup to prompt delete when user long presses --- .../geeksville/mesh/ui/MessagesFragment.kt | 68 ++++++++++++++++++- app/src/main/res/values/strings.xml | 2 + 2 files changed, 69 insertions(+), 1 deletion(-) 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 5c043f01f..5052e9380 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt @@ -1,5 +1,9 @@ package com.geeksville.mesh.ui +import android.app.AlertDialog +import android.app.Dialog +import android.content.Context +import android.content.DialogInterface import android.graphics.Color import android.os.Bundle import android.text.InputType @@ -12,6 +16,7 @@ import android.widget.ImageView import android.widget.TextView import androidx.cardview.widget.CardView import androidx.core.content.ContextCompat +import androidx.fragment.app.DialogFragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager @@ -25,6 +30,7 @@ import com.geeksville.mesh.databinding.MessagesFragmentBinding import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.service.MeshService import com.google.android.material.chip.Chip +import kotlinx.serialization.descriptors.buildSerialDescriptor import java.text.DateFormat import java.util.* @@ -40,6 +46,54 @@ fun EditText.on(actionId: Int, func: () -> Unit) { } } +//class DeleteMessageDialog : DialogFragment() { +// private lateinit var listener: NoticeDialogListener +// +// interface NoticeDialogListener { +// fun onDialogPositiveClick(dialog: DialogFragment) +// fun onDialogNegativeClick(dialog: DialogFragment) +// } +// +// // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener +// override fun onAttach(context: Context) { +// super.onAttach(context) +// // Verify that the host activity implements the callback interface +// try { +// // Instantiate the NoticeDialogListener so we can send events to the host +// listener = context as NoticeDialogListener +// } catch (e: ClassCastException) { +// // The activity doesn't implement the interface, throw exception +// throw ClassCastException( +// (context.toString() + +// " must implement NoticeDialogListener") +// ) +// } +// } +// +// +//} + +class DeleteMessageDialog : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return activity?.let { + + var delete = false; + val builder = AlertDialog.Builder(it) + builder.setMessage(R.string.delete_selected_message) + .setPositiveButton(R.string.delete, + DialogInterface.OnClickListener { dialog, id -> + delete = true + }) + .setNegativeButton(R.string.cancel, + DialogInterface.OnClickListener { dialog, id -> + delete = false + }) + // Create the AlertDialog object and return it + builder.create() + } ?: throw IllegalStateException("Activity cannot be null") + } +} + class MessagesFragment : ScreenFragment("Messages"), Logging { private var _binding: MessagesFragmentBinding? = null @@ -165,7 +219,19 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { val marginParams = holder.card.layoutParams as ViewGroup.MarginLayoutParams val messageOffset = resources.getDimensionPixelOffset(R.dimen.message_offset) holder.card.setOnLongClickListener { - model.messagesState.deleteMessage(messages[position], position) + val deleteMessageDialog = AlertDialog.Builder(context) + // deleteMessageDialog.setTitle(R.string.delete_selected_message) + deleteMessageDialog.setMessage(R.string.delete_selected_message) + deleteMessageDialog.setPositiveButton( + R.string.delete + ) { _, _ -> + model.messagesState.deleteMessage((messages[position]), position) + } + deleteMessageDialog.setNegativeButton(R.string.cancel, + DialogInterface.OnClickListener { _, _ -> + }) + deleteMessageDialog.create() + deleteMessageDialog.show() true } if (isMe) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0c7eefa92..a74d3ec71 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -120,4 +120,6 @@ We must be granted access to the camera to read QR codes. No pictures or videos will be saved. Short Range / Slow Medium Range / Slow + Delete selected message? + Delete \ No newline at end of file From 2785ab49c33c8ccf6d9bf9cd365b99d4cc10c0de Mon Sep 17 00:00:00 2001 From: Jackson Rosenthal Date: Sat, 29 Jan 2022 18:05:40 -0500 Subject: [PATCH 4/6] Deleted commented out code --- .../geeksville/mesh/ui/MessagesFragment.kt | 48 ------------------- 1 file changed, 48 deletions(-) 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 5052e9380..a2f526e3f 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt @@ -46,54 +46,6 @@ fun EditText.on(actionId: Int, func: () -> Unit) { } } -//class DeleteMessageDialog : DialogFragment() { -// private lateinit var listener: NoticeDialogListener -// -// interface NoticeDialogListener { -// fun onDialogPositiveClick(dialog: DialogFragment) -// fun onDialogNegativeClick(dialog: DialogFragment) -// } -// -// // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener -// override fun onAttach(context: Context) { -// super.onAttach(context) -// // Verify that the host activity implements the callback interface -// try { -// // Instantiate the NoticeDialogListener so we can send events to the host -// listener = context as NoticeDialogListener -// } catch (e: ClassCastException) { -// // The activity doesn't implement the interface, throw exception -// throw ClassCastException( -// (context.toString() + -// " must implement NoticeDialogListener") -// ) -// } -// } -// -// -//} - -class DeleteMessageDialog : DialogFragment() { - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - return activity?.let { - - var delete = false; - val builder = AlertDialog.Builder(it) - builder.setMessage(R.string.delete_selected_message) - .setPositiveButton(R.string.delete, - DialogInterface.OnClickListener { dialog, id -> - delete = true - }) - .setNegativeButton(R.string.cancel, - DialogInterface.OnClickListener { dialog, id -> - delete = false - }) - // Create the AlertDialog object and return it - builder.create() - } ?: throw IllegalStateException("Activity cannot be null") - } -} - class MessagesFragment : ScreenFragment("Messages"), Logging { private var _binding: MessagesFragmentBinding? = null From 863426ce6bb543f1849e9eb4534245f4c7da4191 Mon Sep 17 00:00:00 2001 From: Jackson Rosenthal Date: Sat, 29 Jan 2022 18:35:24 -0500 Subject: [PATCH 5/6] Deleted commented out code & unused imports --- .../java/com/geeksville/mesh/ui/MessagesFragment.kt | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) 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 a2f526e3f..52a694c2c 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt @@ -1,9 +1,6 @@ package com.geeksville.mesh.ui import android.app.AlertDialog -import android.app.Dialog -import android.content.Context -import android.content.DialogInterface import android.graphics.Color import android.os.Bundle import android.text.InputType @@ -16,7 +13,6 @@ import android.widget.ImageView import android.widget.TextView import androidx.cardview.widget.CardView import androidx.core.content.ContextCompat -import androidx.fragment.app.DialogFragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager @@ -30,7 +26,6 @@ import com.geeksville.mesh.databinding.MessagesFragmentBinding import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.service.MeshService import com.google.android.material.chip.Chip -import kotlinx.serialization.descriptors.buildSerialDescriptor import java.text.DateFormat import java.util.* @@ -172,16 +167,15 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { val messageOffset = resources.getDimensionPixelOffset(R.dimen.message_offset) holder.card.setOnLongClickListener { val deleteMessageDialog = AlertDialog.Builder(context) - // deleteMessageDialog.setTitle(R.string.delete_selected_message) deleteMessageDialog.setMessage(R.string.delete_selected_message) deleteMessageDialog.setPositiveButton( R.string.delete ) { _, _ -> model.messagesState.deleteMessage((messages[position]), position) } - deleteMessageDialog.setNegativeButton(R.string.cancel, - DialogInterface.OnClickListener { _, _ -> - }) + deleteMessageDialog.setNegativeButton(R.string.cancel + ) { _, _ -> + } deleteMessageDialog.create() deleteMessageDialog.show() true @@ -266,7 +260,6 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.sendButton.setOnClickListener { debug("sendButton click") From 93e81e4639b5830271ade0d922b2c6d18c3bdc00 Mon Sep 17 00:00:00 2001 From: Jackson Rosenthal Date: Mon, 31 Jan 2022 19:11:32 -0500 Subject: [PATCH 6/6] Added delete all messages into the AlertDialog. --- .../com/geeksville/mesh/IMeshService.aidl | 2 ++ .../geeksville/mesh/model/MessagesState.kt | 19 +++++++++++++++++++ .../geeksville/mesh/service/MeshService.kt | 4 ++++ .../geeksville/mesh/ui/MessagesFragment.kt | 8 +++++++- app/src/main/res/values/strings.xml | 1 + 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl index 56b6090fc..8b5010c86 100644 --- a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl +++ b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl @@ -69,6 +69,8 @@ interface IMeshService { void delete(int position); + void deleteAllMessages(); + /** Get the IDs of everyone on the mesh. You should also subscribe for NODE_CHANGE broadcasts. */ 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 60c7a5784..6e98fb5d4 100644 --- a/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt @@ -53,6 +53,13 @@ class MessagesState(private val ui: UIViewModel) : Logging { messages.value = messagesList } + private fun removeAllMessages() { + debug("Removing all messages") + + messagesList.clear() + messages.value = messagesList + } + fun updateStatus(id: Int, status: MessageStatus) { // Super inefficent but this is rare debug("Handling message status change $id: $status") @@ -102,4 +109,16 @@ class MessagesState(private val ui: UIViewModel) : Logging { } removeMessage(packet) } + + fun deleteAllMessages() { + val service = ui.meshService + if (service != null) { + try { + service.deleteAllMessages() + } catch (ex: RemoteException) { + + } + 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 8790e0d4b..1392734cb 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -1789,6 +1789,10 @@ class MeshService : Service(), Logging { } } + override fun deleteAllMessages() { + recentDataPackets.clear() + } + override fun send(p: DataPacket) { toRemoteExceptions { // Init from and id 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 52a694c2c..bd0beefb4 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt @@ -173,9 +173,15 @@ class MessagesFragment : ScreenFragment("Messages"), Logging { ) { _, _ -> model.messagesState.deleteMessage((messages[position]), position) } - deleteMessageDialog.setNegativeButton(R.string.cancel + deleteMessageDialog.setNeutralButton( + R.string.cancel ) { _, _ -> } + deleteMessageDialog.setNegativeButton( + R.string.delete_all_messages + ) { _, _ -> + model.messagesState.deleteAllMessages() + } deleteMessageDialog.create() deleteMessageDialog.show() true diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a74d3ec71..41e99f78e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -122,4 +122,5 @@ Medium Range / Slow Delete selected message? Delete + Delete All Messages \ No newline at end of file