refactor: remove `getString()` from `RadioConfigViewModel`

pull/1500/head^2
andrekir 2024-12-17 12:42:09 -03:00 zatwierdzone przez Andre K
rodzic b05768df98
commit 74497488a7
5 zmienionych plików z 90 dodań i 42 usunięć

Wyświetl plik

@ -17,32 +17,34 @@
package com.geeksville.mesh.model
import androidx.annotation.StringRes
import com.geeksville.mesh.MeshProtos.Routing
import com.geeksville.mesh.MessageStatus
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.database.entity.Reaction
val Routing.Error.stringRes: Int
get() = when (this) {
Routing.Error.NONE -> R.string.routing_error_none
Routing.Error.NO_ROUTE -> R.string.routing_error_no_route
Routing.Error.GOT_NAK -> R.string.routing_error_got_nak
Routing.Error.TIMEOUT -> R.string.routing_error_timeout
Routing.Error.NO_INTERFACE -> R.string.routing_error_no_interface
Routing.Error.MAX_RETRANSMIT -> R.string.routing_error_max_retransmit
Routing.Error.NO_CHANNEL -> R.string.routing_error_no_channel
Routing.Error.TOO_LARGE -> R.string.routing_error_too_large
Routing.Error.NO_RESPONSE -> R.string.routing_error_no_response
Routing.Error.DUTY_CYCLE_LIMIT -> R.string.routing_error_duty_cycle_limit
Routing.Error.BAD_REQUEST -> R.string.routing_error_bad_request
Routing.Error.NOT_AUTHORIZED -> R.string.routing_error_not_authorized
Routing.Error.PKI_FAILED -> R.string.routing_error_pki_failed
Routing.Error.PKI_UNKNOWN_PUBKEY -> R.string.routing_error_pki_unknown_pubkey
Routing.Error.ADMIN_BAD_SESSION_KEY -> R.string.routing_error_admin_bad_session_key
Routing.Error.ADMIN_PUBLIC_KEY_UNAUTHORIZED -> R.string.routing_error_admin_public_key_unauthorized
else -> R.string.unrecognized
}
@Suppress("CyclomaticComplexMethod")
@StringRes
fun getStringResFrom(routingError: Int): Int = when (routingError) {
Routing.Error.NONE_VALUE -> R.string.routing_error_none
Routing.Error.NO_ROUTE_VALUE -> R.string.routing_error_no_route
Routing.Error.GOT_NAK_VALUE -> R.string.routing_error_got_nak
Routing.Error.TIMEOUT_VALUE -> R.string.routing_error_timeout
Routing.Error.NO_INTERFACE_VALUE -> R.string.routing_error_no_interface
Routing.Error.MAX_RETRANSMIT_VALUE -> R.string.routing_error_max_retransmit
Routing.Error.NO_CHANNEL_VALUE -> R.string.routing_error_no_channel
Routing.Error.TOO_LARGE_VALUE -> R.string.routing_error_too_large
Routing.Error.NO_RESPONSE_VALUE -> R.string.routing_error_no_response
Routing.Error.DUTY_CYCLE_LIMIT_VALUE -> R.string.routing_error_duty_cycle_limit
Routing.Error.BAD_REQUEST_VALUE -> R.string.routing_error_bad_request
Routing.Error.NOT_AUTHORIZED_VALUE -> R.string.routing_error_not_authorized
Routing.Error.PKI_FAILED_VALUE -> R.string.routing_error_pki_failed
Routing.Error.PKI_UNKNOWN_PUBKEY_VALUE -> R.string.routing_error_pki_unknown_pubkey
Routing.Error.ADMIN_BAD_SESSION_KEY_VALUE -> R.string.routing_error_admin_bad_session_key
Routing.Error.ADMIN_PUBLIC_KEY_UNAUTHORIZED_VALUE -> R.string.routing_error_admin_public_key_unauthorized
else -> R.string.unrecognized
}
data class Message(
val uuid: Long,
@ -56,18 +58,13 @@ data class Message(
val packetId: Int,
val emojis: List<Reaction>,
) {
private fun getStatusStringRes(value: Int): Int {
val error = Routing.Error.forNumber(value) ?: Routing.Error.UNRECOGNIZED
return error.stringRes
}
fun getStatusStringRes(): Pair<Int, Int> {
val title = if (routingError > 0) R.string.error else R.string.message_delivery_status
val text = when (status) {
MessageStatus.RECEIVED -> R.string.delivery_confirmed
MessageStatus.QUEUED -> R.string.message_status_queued
MessageStatus.ENROUTE -> R.string.message_status_enroute
else -> getStatusStringRes(routingError)
else -> getStringResFrom(routingError)
}
return title to text
}

Wyświetl plik

@ -20,6 +20,7 @@ package com.geeksville.mesh.model
import android.app.Application
import android.net.Uri
import android.os.RemoteException
import androidx.annotation.StringRes
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@ -47,6 +48,7 @@ import com.geeksville.mesh.ui.ConfigRoute
import com.geeksville.mesh.ui.ModuleRoute
import com.geeksville.mesh.ui.ResponseState
import com.geeksville.mesh.ui.Route
import com.geeksville.mesh.util.UiText
import com.google.protobuf.MessageLite
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
@ -118,7 +120,7 @@ class RadioConfigViewModel @Inject constructor(
combine(radioConfigRepository.connectionState, radioConfigState) { connState, configState ->
_radioConfigState.update { it.copy(connected = connState == ConnectionState.CONNECTED) }
if (connState.isDisconnected() && configState.responseState.isWaiting()) {
setResponseStateError(app.getString(R.string.disconnected))
sendError(R.string.disconnected)
}
}.launchIn(viewModelScope)
@ -321,7 +323,7 @@ class RadioConfigViewModel @Inject constructor(
AdminRoute.REBOOT.name -> requestReboot(destNum)
AdminRoute.SHUTDOWN.name -> with(radioConfigState.value) {
if (hasMetadata() && !metadata.canShutdown) {
setResponseStateError(app.getString(R.string.cant_shutdown))
sendError(R.string.cant_shutdown)
} else {
requestShutdown(destNum)
}
@ -364,7 +366,7 @@ class RadioConfigViewModel @Inject constructor(
}
} catch (ex: Exception) {
errormsg("Import DeviceProfile error: ${ex.message}")
setResponseStateError(ex.customMessage)
sendError(ex.customMessage)
}
}
@ -382,7 +384,7 @@ class RadioConfigViewModel @Inject constructor(
setResponseStateSuccess()
} catch (ex: Exception) {
errormsg("Can't write file error: ${ex.message}")
setResponseStateError(ex.customMessage)
sendError(ex.customMessage)
}
}
@ -399,11 +401,13 @@ class RadioConfigViewModel @Inject constructor(
setOwner(user)
}
}
if (hasChannelUrl()) try {
setChannels(channelUrl)
} catch (ex: Exception) {
errormsg("DeviceProfile channel import error", ex)
setResponseStateError(ex.customMessage)
if (hasChannelUrl()) {
try {
setChannels(channelUrl)
} catch (ex: Exception) {
errormsg("DeviceProfile channel import error", ex)
sendError(ex.customMessage)
}
}
if (hasConfig()) {
val descriptor = ConfigProtos.Config.getDescriptor()
@ -494,7 +498,9 @@ class RadioConfigViewModel @Inject constructor(
}
private val Exception.customMessage: String get() = "${javaClass.simpleName}: $message"
private fun setResponseStateError(error: String) {
private fun sendError(error: String) = setResponseStateError(UiText.DynamicString(error))
private fun sendError(@StringRes id: Int) = setResponseStateError(UiText.StringResource(id))
private fun setResponseStateError(error: UiText) {
_radioConfigState.update { it.copy(responseState = ResponseState.Error(error)) }
}
@ -521,7 +527,7 @@ class RadioConfigViewModel @Inject constructor(
val parsed = MeshProtos.Routing.parseFrom(data.payload)
debug(debugMsg.format(parsed.errorReason.name))
if (parsed.errorReason != MeshProtos.Routing.Error.NONE) {
setResponseStateError(app.getString(parsed.errorReason.stringRes))
sendError(getStringResFrom(parsed.errorReasonValue))
} else if (packet.from == destNum && route.isEmpty()) {
requestIds.update { it.apply { remove(data.requestId) } }
if (requestIds.value.isEmpty()) {
@ -535,7 +541,7 @@ class RadioConfigViewModel @Inject constructor(
val parsed = AdminProtos.AdminMessage.parseFrom(data.payload)
debug(debugMsg.format(parsed.payloadVariantCase.name))
if (destNum != packet.from) {
setResponseStateError("Unexpected sender: ${packet.from.toUInt()} instead of ${destNum.toUInt()}.")
sendError("Unexpected sender: ${packet.from.toUInt()} instead of ${destNum.toUInt()}.")
return
}
when (parsed.payloadVariantCase) {
@ -572,7 +578,7 @@ class RadioConfigViewModel @Inject constructor(
AdminProtos.AdminMessage.PayloadVariantCase.GET_CONFIG_RESPONSE -> {
val response = parsed.getConfigResponse
if (response.payloadVariantCase.number == 0) { // PAYLOADVARIANT_NOT_SET
setResponseStateError(response.payloadVariantCase.name)
sendError(response.payloadVariantCase.name)
}
_radioConfigState.update { it.copy(radioConfig = response) }
incrementCompleted()
@ -581,7 +587,7 @@ class RadioConfigViewModel @Inject constructor(
AdminProtos.AdminMessage.PayloadVariantCase.GET_MODULE_CONFIG_RESPONSE -> {
val response = parsed.getModuleConfigResponse
if (response.payloadVariantCase.number == 0) { // PAYLOADVARIANT_NOT_SET
setResponseStateError(response.payloadVariantCase.name)
sendError(response.payloadVariantCase.name)
}
_radioConfigState.update { it.copy(moduleConfig = response) }
incrementCompleted()

Wyświetl plik

@ -81,6 +81,7 @@ import com.geeksville.mesh.ui.components.NodeMapScreen
import com.geeksville.mesh.ui.components.PositionLogScreen
import com.geeksville.mesh.ui.components.SignalMetricsScreen
import com.geeksville.mesh.ui.components.TracerouteLogScreen
import com.geeksville.mesh.util.UiText
import com.geeksville.mesh.ui.components.config.AmbientLightingConfigScreen
import com.geeksville.mesh.ui.components.config.AudioConfigScreen
import com.geeksville.mesh.ui.components.config.BluetoothConfigScreen
@ -260,7 +261,7 @@ sealed class ResponseState<out T> {
data object Empty : ResponseState<Nothing>()
data class Loading(var total: Int = 1, var completed: Int = 0) : ResponseState<Nothing>()
data class Success<T>(val result: T) : ResponseState<T>()
data class Error(val error: String) : ResponseState<Nothing>()
data class Error(val error: UiText) : ResponseState<Nothing>()
fun isWaiting() = this !is Empty
}

Wyświetl plik

@ -74,7 +74,7 @@ fun <T> PacketResponseStateDialog(
}
if (state is ResponseState.Error) {
Text(text = stringResource(id = R.string.error), minLines = 2)
Text(text = state.error)
Text(text = state.error.asString())
}
}
},

Wyświetl plik

@ -0,0 +1,44 @@
/*
* 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 android.content.Context
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
@Suppress("SpreadOperator")
sealed class UiText {
data class DynamicString(val value: String) : UiText()
class StringResource(@StringRes val resId: Int, vararg val args: Any) : UiText()
@Composable
fun asString(): String {
return when (this) {
is DynamicString -> value
is StringResource -> stringResource(resId, *args)
}
}
fun asString(context: Context): String {
return when (this) {
is DynamicString -> value
is StringResource -> context.getString(resId, *args)
}
}
}