kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
refactor: remove `getString()` from `RadioConfigViewModel`
rodzic
b05768df98
commit
74497488a7
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue