diff --git a/app/src/main/java/com/geeksville/mesh/database/MeshLogRepository.kt b/app/src/main/java/com/geeksville/mesh/database/MeshLogRepository.kt index c80a4db8..805b7d68 100644 --- a/app/src/main/java/com/geeksville/mesh/database/MeshLogRepository.kt +++ b/app/src/main/java/com/geeksville/mesh/database/MeshLogRepository.kt @@ -67,6 +67,10 @@ class MeshLogRepository @Inject constructor(private val meshLogDaoLazy: dagger.L meshLogDao.deleteAll() } + suspend fun deleteLog(uuid: String) = withContext(Dispatchers.IO) { + meshLogDao.deleteLog(uuid) + } + companion object { private const val MAX_ITEMS = 500 private const val MAX_MESH_PACKETS = 10000 diff --git a/app/src/main/java/com/geeksville/mesh/database/dao/MeshLogDao.kt b/app/src/main/java/com/geeksville/mesh/database/dao/MeshLogDao.kt index 6a2f70dc..d5a77fa1 100644 --- a/app/src/main/java/com/geeksville/mesh/database/dao/MeshLogDao.kt +++ b/app/src/main/java/com/geeksville/mesh/database/dao/MeshLogDao.kt @@ -33,4 +33,7 @@ interface MeshLogDao { @Query("DELETE FROM log") fun deleteAll() + + @Query("DELETE FROM log WHERE uuid = :uuid") + fun deleteLog(uuid: String) } diff --git a/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt index a2efa993..849bee96 100644 --- a/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt @@ -2,6 +2,7 @@ package com.geeksville.mesh.model import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.geeksville.mesh.CoroutineDispatchers import com.geeksville.mesh.MeshProtos.MeshPacket import com.geeksville.mesh.Portnums.PortNum import com.geeksville.mesh.TelemetryProtos.Telemetry @@ -15,6 +16,7 @@ import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch import javax.inject.Inject data class MetricsState( @@ -45,7 +47,8 @@ data class TracerouteLogState( @HiltViewModel class MetricsViewModel @Inject constructor( - meshLogRepository: MeshLogRepository, + private val dispatchers: CoroutineDispatchers, + private val meshLogRepository: MeshLogRepository, private val radioConfigRepository: RadioConfigRepository, ) : ViewModel() { private val destNum = MutableStateFlow(0) @@ -59,6 +62,10 @@ class MetricsViewModel @Inject constructor( fun getUser(nodeNum: Int) = radioConfigRepository.getUser(nodeNum) + fun deleteLog(uuid: String) = viewModelScope.launch(dispatchers.io) { + meshLogRepository.deleteLog(uuid) + } + @OptIn(ExperimentalCoroutinesApi::class) val tracerouteState = destNum.flatMapLatest { destNum -> combine( diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/TracerouteLog.kt b/app/src/main/java/com/geeksville/mesh/ui/components/TracerouteLog.kt index 555ac0fa..f51542ec 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/TracerouteLog.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/TracerouteLog.kt @@ -1,6 +1,8 @@ package com.geeksville.mesh.ui.components -import androidx.compose.foundation.clickable +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -13,10 +15,13 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material.Card +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Group import androidx.compose.material.icons.filled.Groups import androidx.compose.material.icons.filled.PersonOff @@ -41,6 +46,7 @@ import com.geeksville.mesh.model.getTracerouteResponse import com.geeksville.mesh.ui.theme.AppTheme import java.text.DateFormat +@OptIn(ExperimentalFoundationApi::class) @Composable fun TracerouteLogScreen( viewModel: MetricsViewModel = hiltViewModel(), @@ -83,20 +89,50 @@ fun TracerouteLogScreen( val time = dateFormat.format(log.received_date) val (text, icon) = route.getTextAndIcon() + var expanded by remember { mutableStateOf(false) } - TracerouteItem( - icon = icon, - text = "$time - $text", - modifier = Modifier.clickable(enabled = result != null) { - if (result != null) { - showDialog = result.getTracerouteResponse(::getUsername) + Box { + TracerouteItem( + icon = icon, + text = "$time - $text", + modifier = Modifier.combinedClickable( + onLongClick = { expanded = true }, + ) { + if (result != null) { + showDialog = result.getTracerouteResponse(::getUsername) + } + } + ) + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + ) { + DeleteItem { + viewModel.deleteLog(log.uuid) + expanded = false } } - ) + } } } } +@Composable +private fun DeleteItem(onClick: () -> Unit) { + DropdownMenuItem(onClick = onClick) { + Icon( + imageVector = Icons.Default.Delete, + contentDescription = stringResource(id = R.string.delete), + tint = MaterialTheme.colors.error, + ) + Spacer(modifier = Modifier.width(12.dp)) + Text( + text = stringResource(id = R.string.delete), + color = MaterialTheme.colors.error, + ) + } +} + @Composable private fun TracerouteItem( icon: ImageVector,