Skip to content

Commit

Permalink
refactor: add custom formatting to LocalStats fields
Browse files Browse the repository at this point in the history
  • Loading branch information
andrekir committed Nov 26, 2024
1 parent 1219d30 commit 6230f13
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 67 deletions.
43 changes: 15 additions & 28 deletions app/src/main/java/com/geeksville/mesh/model/UIState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,24 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import com.geeksville.mesh.*
import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.ChannelProtos
import com.geeksville.mesh.ChannelProtos.ChannelSettings
import com.geeksville.mesh.ConfigProtos.Config
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.IMeshService
import com.geeksville.mesh.LocalOnlyProtos.LocalConfig
import com.geeksville.mesh.LocalOnlyProtos.LocalModuleConfig
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.Portnums
import com.geeksville.mesh.Position
import com.geeksville.mesh.R
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.channel
import com.geeksville.mesh.channelSet
import com.geeksville.mesh.channelSettings
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.QuickChatActionRepository
Expand All @@ -47,6 +59,8 @@ import com.geeksville.mesh.repository.radio.RadioInterfaceService
import com.geeksville.mesh.service.MeshService
import com.geeksville.mesh.service.ServiceAction
import com.geeksville.mesh.ui.map.MAP_STYLE_ID
import com.geeksville.mesh.util.getShortDate
import com.geeksville.mesh.util.getShortDateTime
import com.geeksville.mesh.util.positionToMeter
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
Expand All @@ -67,11 +81,8 @@ import kotlinx.coroutines.withContext
import java.io.BufferedWriter
import java.io.FileNotFoundException
import java.io.FileWriter
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import kotlin.math.roundToInt

Expand Down Expand Up @@ -150,30 +161,6 @@ data class Contact(
val isMuted: Boolean,
)

// return time if within 24 hours, otherwise date
private fun getShortDate(time: Long): String? {
val date = if (time != 0L) Date(time) else return null
val isWithin24Hours = System.currentTimeMillis() - date.time <= TimeUnit.DAYS.toMillis(1)

return if (isWithin24Hours) {
DateFormat.getTimeInstance(DateFormat.SHORT).format(date)
} else {
DateFormat.getDateInstance(DateFormat.SHORT).format(date)
}
}

// return time if within 24 hours, otherwise date/time
private fun getShortDateTime(time: Long): String {
val date = Date(time)
val isWithin24Hours = System.currentTimeMillis() - date.time <= TimeUnit.DAYS.toMillis(1)

return if (isWithin24Hours) {
DateFormat.getTimeInstance(DateFormat.SHORT).format(date)
} else {
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(date)
}
}

@Suppress("LongParameterList")
@HiltViewModel
class UIViewModel @Inject constructor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ import com.geeksville.mesh.TelemetryProtos.LocalStats
import com.geeksville.mesh.android.notificationManager
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.util.PendingIntentCompat
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import com.geeksville.mesh.util.formatUptime

@Suppress("TooManyFunctions")
class MeshServiceNotifications(
Expand Down Expand Up @@ -150,37 +148,29 @@ class MeshServiceNotifications(
}
}

private fun formatStatsString(stats: LocalStats?, currentStatsUpdatedAtMillis: Long?): String {
val updatedAt = "Next update at: ${
currentStatsUpdatedAtMillis?.let {
val date = Date(it + FIFTEEN_MINUTES_IN_MILLIS) // Add 15 minutes in milliseconds
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
dateFormat.format(date)
} ?: "???"
}"
val statsJoined = stats?.allFields?.mapNotNull { (k, v) ->
if (k.name == "num_online_nodes" || k.name == "num_total_nodes") {
return@mapNotNull null
}
"${
private fun LocalStats?.formatToString(): String = this?.allFields?.mapNotNull { (k, v) ->
when (k.name) {
"num_online_nodes", "num_total_nodes" -> return@mapNotNull null
"uptime_seconds" -> "Uptime: ${formatUptime(v as Int)}"
"channel_utilization" -> "ChUtil: %.2f%%".format(v)
"air_util_tx" -> "AirUtilTX: %.2f%%".format(v)
else -> "${
k.name.replace('_', ' ').split(" ")
.joinToString(" ") { it.replaceFirstChar { char -> char.uppercase() } }
}=$v"
}?.joinToString("\n") ?: "No Local Stats"
return "$updatedAt\n$statsJoined"
}
}: $v"
}
}?.joinToString("\n") ?: "No Local Stats"

fun updateServiceStateNotification(
summaryString: String? = null,
localStats: LocalStats? = null,
currentStatsUpdatedAtMillis: Long? = null,
) {
val statsString = formatStatsString(localStats, currentStatsUpdatedAtMillis)
notificationManager.notify(
notifyId,
createServiceStateNotification(
name = summaryString.orEmpty(),
message = statsString,
message = localStats.formatToString(),
nextUpdateAt = currentStatsUpdatedAtMillis?.plus(FIFTEEN_MINUTES_IN_MILLIS)
)
)
Expand Down
18 changes: 1 addition & 17 deletions app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ import com.geeksville.mesh.ui.preview.NodeEntityPreviewParameterProvider
import com.geeksville.mesh.ui.theme.AppTheme
import com.geeksville.mesh.util.DistanceUnit
import com.geeksville.mesh.util.formatAgo
import com.geeksville.mesh.util.formatUptime
import com.geeksville.mesh.util.thenIf
import java.util.concurrent.TimeUnit
import kotlin.math.ln

@Composable
Expand Down Expand Up @@ -349,22 +349,6 @@ private fun InfoCard(
}
}

private fun formatUptime(seconds: Int): String = formatUptime(seconds.toLong())

private fun formatUptime(seconds: Long): String {
val days = TimeUnit.SECONDS.toDays(seconds)
val hours = TimeUnit.SECONDS.toHours(seconds) % TimeUnit.DAYS.toHours(1)
val minutes = TimeUnit.SECONDS.toMinutes(seconds) % TimeUnit.HOURS.toMinutes(1)
val secs = seconds % TimeUnit.MINUTES.toSeconds(1)

return listOfNotNull(
"${days}d".takeIf { days > 0 },
"${hours}h".takeIf { hours > 0 },
"${minutes}m".takeIf { minutes > 0 },
"${secs}s".takeIf { secs > 0 },
).joinToString(" ")
}

@OptIn(ExperimentalLayoutApi::class)
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable
Expand Down
62 changes: 62 additions & 0 deletions app/src/main/java/com/geeksville/mesh/util/DateTimeUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2024 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.geeksville.mesh.util

import java.text.DateFormat
import java.util.Date
import java.util.concurrent.TimeUnit

// return time if within 24 hours, otherwise date
fun getShortDate(time: Long): String? {
val date = if (time != 0L) Date(time) else return null
val isWithin24Hours = System.currentTimeMillis() - date.time <= TimeUnit.DAYS.toMillis(1)

return if (isWithin24Hours) {
DateFormat.getTimeInstance(DateFormat.SHORT).format(date)
} else {
DateFormat.getDateInstance(DateFormat.SHORT).format(date)
}
}

// return time if within 24 hours, otherwise date/time
fun getShortDateTime(time: Long): String {
val date = Date(time)
val isWithin24Hours = System.currentTimeMillis() - date.time <= TimeUnit.DAYS.toMillis(1)

return if (isWithin24Hours) {
DateFormat.getTimeInstance(DateFormat.SHORT).format(date)
} else {
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(date)
}
}

fun formatUptime(seconds: Int): String = formatUptime(seconds.toLong())

private fun formatUptime(seconds: Long): String {
val days = TimeUnit.SECONDS.toDays(seconds)
val hours = TimeUnit.SECONDS.toHours(seconds) % TimeUnit.DAYS.toHours(1)
val minutes = TimeUnit.SECONDS.toMinutes(seconds) % TimeUnit.HOURS.toMinutes(1)
val secs = seconds % TimeUnit.MINUTES.toSeconds(1)

return listOfNotNull(
"${days}d".takeIf { days > 0 },
"${hours}h".takeIf { hours > 0 },
"${minutes}m".takeIf { minutes > 0 },
"${secs}s".takeIf { secs > 0 },
).joinToString(" ")
}

0 comments on commit 6230f13

Please sign in to comment.