refactor: extract NodeMenu from UsersFragment

This commit is contained in:
andrekir
2024-06-23 08:36:40 -03:00
parent db500c5200
commit f75879603e
3 changed files with 99 additions and 57 deletions

View File

@@ -265,6 +265,7 @@ class UIViewModel @Inject constructor(
}
fun requestTraceroute(destNum: Int) {
info("Requesting traceroute for '$destNum'")
try {
val packetId = meshService?.packetId ?: return
meshService?.requestTraceroute(packetId, destNum)
@@ -274,16 +275,18 @@ class UIViewModel @Inject constructor(
}
fun removeNode(nodeNum: Int) = viewModelScope.launch(Dispatchers.IO) {
info("Removing node '$nodeNum'")
try {
val packetId = meshService?.packetId ?: return@launch
meshService?.removeByNodenum(packetId, nodeNum)
nodeDB.deleteNode(nodeNum)
} catch (ex: RemoteException) {
errormsg("Request traceroute error: ${ex.message}")
errormsg("Remove node error: ${ex.message}")
}
}
fun requestPosition(destNum: Int, position: Position = Position(0.0, 0.0, 0)) {
info("Requesting position for '$destNum'")
try {
meshService?.requestPosition(destNum, position)
} catch (ex: RemoteException) {

View File

@@ -0,0 +1,62 @@
package com.geeksville.mesh.ui
import android.view.Gravity
import android.view.MenuItem
import android.view.View
import androidx.appcompat.widget.PopupMenu
import com.geeksville.mesh.NodeInfo
import com.geeksville.mesh.R
import com.google.android.material.dialog.MaterialAlertDialogBuilder
internal fun View.nodeMenu(
node: NodeInfo,
ignoreIncomingList: List<Int>,
isOurNode: Boolean = false,
showAdmin: Boolean = false,
isManaged: Boolean = false,
onMenuItemAction: MenuItem.() -> Unit,
) = PopupMenu(context, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0).apply {
val isIgnored = ignoreIncomingList.contains(node.num)
inflate(R.menu.menu_nodes)
menu.apply {
setGroupVisible(R.id.group_remote, !isOurNode)
setGroupVisible(R.id.group_admin, showAdmin)
setGroupEnabled(R.id.group_admin, !isManaged)
findItem(R.id.ignore).apply {
isEnabled = isIgnored || ignoreIncomingList.size < 3
isChecked = isIgnored
}
}
setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.remove -> {
MaterialAlertDialogBuilder(context)
.setTitle(R.string.remove)
.setMessage(R.string.remove_node_text)
.setNeutralButton(R.string.cancel) { _, _ -> }
.setPositiveButton(R.string.send) { _, _ ->
item.onMenuItemAction()
}
.show()
}
R.id.ignore -> {
val message = if (isIgnored) R.string.ignore_remove else R.string.ignore_add
MaterialAlertDialogBuilder(context)
.setTitle(R.string.ignore)
.setMessage(context.getString(message, node.user?.longName))
.setNeutralButton(R.string.cancel) { _, _ -> }
.setPositiveButton(R.string.send) { _, _ ->
item.onMenuItemAction()
}
.show()
item.isChecked = !item.isChecked
}
else -> item.onMenuItemAction()
}
true
}
show()
}

View File

@@ -1,12 +1,9 @@
package com.geeksville.mesh.ui
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
@@ -34,7 +31,6 @@ import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.components.NodeFilterTextField
import com.geeksville.mesh.ui.theme.AppTheme
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
@@ -43,82 +39,63 @@ class UsersFragment : ScreenFragment("Users"), Logging {
private val model: UIViewModel by activityViewModels()
private fun popup(view: View, node: NodeInfo) {
private fun popup(node: NodeInfo) {
if (!model.isConnected()) return
val user = node.user ?: return
val isOurNode = node.num == model.myNodeNum
val showAdmin = isOurNode || model.hasAdminChannel
val ignoreIncomingList = model.ignoreIncomingList
val isIgnored = ignoreIncomingList.contains(node.num)
val popup =
PopupMenu(view.context, view, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0)
popup.inflate(R.menu.menu_nodes)
popup.menu.setGroupVisible(R.id.group_remote, !isOurNode)
popup.menu.setGroupVisible(R.id.group_admin, showAdmin)
popup.menu.setGroupEnabled(R.id.group_admin, !model.isManaged)
popup.menu.findItem(R.id.ignore).apply {
isEnabled = isIgnored || ignoreIncomingList.size < 3
isChecked = isIgnored
}
popup.setOnMenuItemClickListener { item: MenuItem ->
when (item.itemId) {
requireView().nodeMenu(
node = node,
ignoreIncomingList = ignoreIncomingList,
isOurNode = isOurNode,
showAdmin = isOurNode || model.hasAdminChannel,
isManaged = model.isManaged,
) {
when (itemId) {
R.id.direct_message -> {
val contactKey = "${node.channel}${user.id}"
debug("calling MessagesFragment filter: $contactKey")
parentFragmentManager.navigateToMessages(contactKey, user.longName)
navigateToMessages(node)
}
R.id.request_position -> {
debug("requesting position for '${user.longName}'")
model.requestPosition(node.num)
}
R.id.traceroute -> {
debug("requesting traceroute for '${user.longName}'")
model.requestTraceroute(node.num)
}
R.id.remove -> {
MaterialAlertDialogBuilder(view.context)
.setTitle(R.string.remove)
.setMessage(getString(R.string.remove_node_text))
.setNeutralButton(R.string.cancel) { _, _ -> }
.setPositiveButton(R.string.send) { _, _ ->
debug("removing node '${user.longName}'")
model.removeNode(node.num)
}
.show()
model.removeNode(node.num)
}
R.id.ignore -> {
val message = if (isIgnored) R.string.ignore_remove else R.string.ignore_add
MaterialAlertDialogBuilder(view.context)
.setTitle(R.string.ignore)
.setMessage(getString(message, user.longName))
.setNeutralButton(R.string.cancel) { _, _ -> }
.setPositiveButton(R.string.send) { _, _ ->
model.ignoreIncomingList = ignoreIncomingList.toMutableList().apply {
if (isIgnored) {
debug("removed '${user.longName}' from ignore list")
remove(node.num)
} else {
debug("added '${user.longName}' to ignore list")
add(node.num)
}
}
item.isChecked = !item.isChecked
model.ignoreIncomingList = ignoreIncomingList.toMutableList().apply {
if (contains(node.num)) {
debug("removed '${node.num}' from ignore list")
remove(node.num)
} else {
debug("added '${node.num}' to ignore list")
add(node.num)
}
.show()
}
}
R.id.remote_admin -> {
debug("calling remote admin --> destNum: ${node.num.toUInt()}")
parentFragmentManager.navigateToRadioConfig(node.num)
navigateToRadioConfig(node)
}
}
true
}
popup.show()
}
private fun navigateToMessages(node: NodeInfo) = node.user?.let { user ->
val contactKey = "${node.channel}${user.id}"
info("calling MessagesFragment filter: $contactKey")
parentFragmentManager.navigateToMessages(contactKey, user.longName)
}
private fun navigateToRadioConfig(node: NodeInfo) {
info("calling RadioConfig --> destNum: ${node.num}")
parentFragmentManager.navigateToRadioConfig(node.num)
}
override fun onCreateView(
@@ -130,7 +107,7 @@ class UsersFragment : ScreenFragment("Users"), Logging {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
AppTheme {
NodesScreen(model = model, onClick = { popup(requireView(), it) })
NodesScreen(model = model, onClick = ::popup)
}
}
}