kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
refactor(config): pass `destNum` via `setFragmentResultListener`
rodzic
e6e85d6403
commit
c15c3d8c09
|
@ -646,7 +646,6 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
return true
|
||||
}
|
||||
R.id.radio_config -> {
|
||||
model.setDestNode(null)
|
||||
supportFragmentManager.beginTransaction()
|
||||
.add(R.id.mainActivityLayout, DeviceSettingsFragment())
|
||||
.addToBackStack(null)
|
||||
|
|
|
@ -28,6 +28,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
@ -44,8 +45,8 @@ data class RadioConfigState(
|
|||
val route: String = "",
|
||||
val userConfig: MeshProtos.User = MeshProtos.User.getDefaultInstance(),
|
||||
val channelList: List<ChannelProtos.ChannelSettings> = emptyList(),
|
||||
val radioConfig: ConfigProtos.Config = ConfigProtos.Config.getDefaultInstance(),
|
||||
val moduleConfig: ModuleConfigProtos.ModuleConfig = ModuleConfigProtos.ModuleConfig.getDefaultInstance(),
|
||||
val radioConfig: ConfigProtos.Config = config {},
|
||||
val moduleConfig: ModuleConfigProtos.ModuleConfig = moduleConfig {},
|
||||
val ringtone: String = "",
|
||||
val cannedMessageMessages: String = "",
|
||||
val responseState: ResponseState<Boolean> = ResponseState.Empty,
|
||||
|
@ -57,17 +58,22 @@ class RadioConfigViewModel @Inject constructor(
|
|||
private val radioConfigRepository: RadioConfigRepository,
|
||||
) : ViewModel(), Logging {
|
||||
|
||||
private var destNum: Int = 0
|
||||
private val meshService: IMeshService? get() = radioConfigRepository.meshService
|
||||
|
||||
// Connection state to our radio device
|
||||
val connectionState get() = radioConfigRepository.connectionState
|
||||
|
||||
// A map from nodeNum to NodeInfo
|
||||
val nodes: StateFlow<Map<Int, NodeInfo>> get() = radioConfigRepository.nodeDBbyNum
|
||||
private val _destNum = MutableStateFlow<Int?>(null)
|
||||
private val _destNode = MutableStateFlow<NodeInfo?>(null)
|
||||
val destNode: StateFlow<NodeInfo?> get() = _destNode
|
||||
|
||||
val myNodeInfo: StateFlow<MyNodeInfo?> get() = radioConfigRepository.myNodeInfo
|
||||
val ourNodeInfo: StateFlow<NodeInfo?> get() = radioConfigRepository.ourNodeInfo
|
||||
/**
|
||||
* Sets the destination [NodeInfo] used in Radio Configuration.
|
||||
* @param num Destination nodeNum (or null for our local [NodeInfo]).
|
||||
*/
|
||||
fun setDestNum(num: Int?) {
|
||||
_destNum.value = num
|
||||
}
|
||||
|
||||
private val requestIds = MutableStateFlow(hashSetOf<Int>())
|
||||
private val _radioConfigState = MutableStateFlow(RadioConfigState())
|
||||
|
@ -77,6 +83,10 @@ class RadioConfigViewModel @Inject constructor(
|
|||
val currentDeviceProfile get() = _currentDeviceProfile.value
|
||||
|
||||
init {
|
||||
combine(_destNum, radioConfigRepository.nodeDBbyNum) { destNum, nodes ->
|
||||
nodes[destNum] ?: nodes.values.firstOrNull()
|
||||
}.onEach { _destNode.value = it }.launchIn(viewModelScope)
|
||||
|
||||
radioConfigRepository.deviceProfileFlow.onEach {
|
||||
_currentDeviceProfile.value = it
|
||||
}.launchIn(viewModelScope)
|
||||
|
@ -87,6 +97,7 @@ class RadioConfigViewModel @Inject constructor(
|
|||
debug("RadioConfigViewModel created")
|
||||
}
|
||||
|
||||
private val myNodeInfo: StateFlow<MyNodeInfo?> get() = radioConfigRepository.myNodeInfo
|
||||
val myNodeNum get() = myNodeInfo.value?.myNodeNum
|
||||
val maxChannels get() = myNodeInfo.value?.maxChannels ?: 8
|
||||
|
||||
|
@ -101,7 +112,6 @@ class RadioConfigViewModel @Inject constructor(
|
|||
errorMessage: String,
|
||||
) = viewModelScope.launch {
|
||||
meshService?.let { service ->
|
||||
this@RadioConfigViewModel.destNum = destNum
|
||||
val packetId = service.packetId
|
||||
try {
|
||||
requestAction(service, packetId, destNum)
|
||||
|
@ -313,7 +323,7 @@ class RadioConfigViewModel @Inject constructor(
|
|||
fun installProfile(protobuf: DeviceProfile) = with(protobuf) {
|
||||
_deviceProfile.value = null
|
||||
// meshService?.beginEditSettings()
|
||||
if (hasLongName() || hasShortName()) ourNodeInfo.value?.user?.let {
|
||||
if (hasLongName() || hasShortName()) destNode.value?.user?.let {
|
||||
val user = it.copy(
|
||||
longName = if (hasLongName()) longName else it.longName,
|
||||
shortName = if (hasShortName()) shortName else it.shortName
|
||||
|
@ -409,9 +419,8 @@ class RadioConfigViewModel @Inject constructor(
|
|||
if (data.requestId !in requestIds.value) return
|
||||
val route = radioConfigState.value.route
|
||||
|
||||
// val destNum = destNode.value?.num ?: return
|
||||
val debugMsg =
|
||||
"requestId: ${data.requestId.toUInt()} to: ${destNum.toUInt()} received %s from: ${packet.from.toUInt()}"
|
||||
val destNum = destNode.value?.num ?: return
|
||||
val debugMsg = "requestId: ${data.requestId.toUInt()} to: ${destNum.toUInt()} received %s"
|
||||
|
||||
if (data?.portnumValue == Portnums.PortNum.ROUTING_APP_VALUE) {
|
||||
val parsed = MeshProtos.Routing.parseFrom(data.payload)
|
||||
|
|
|
@ -229,17 +229,6 @@ class UIViewModel @Inject constructor(
|
|||
.filterValues { it.data.waypoint!!.expire > System.currentTimeMillis() / 1000 }
|
||||
}.asLiveData()
|
||||
|
||||
private val _destNode = MutableStateFlow<NodeInfo?>(null)
|
||||
val destNode: StateFlow<NodeInfo?> get() = if (_destNode.value != null) _destNode else ourNodeInfo
|
||||
|
||||
/**
|
||||
* Sets the destination [NodeInfo] used in Radio Configuration.
|
||||
* @param node Destination [NodeInfo] (or null for our local NodeInfo).
|
||||
*/
|
||||
fun setDestNode(node: NodeInfo?) {
|
||||
_destNode.value = node
|
||||
}
|
||||
|
||||
fun generatePacketId(): Int? {
|
||||
return try {
|
||||
meshService?.packetId
|
||||
|
|
|
@ -143,14 +143,13 @@ class RadioConfigRepository @Inject constructor(
|
|||
* Flow representing the combined [DeviceProfile] protobuf.
|
||||
*/
|
||||
val deviceProfileFlow: Flow<DeviceProfile> = combine(
|
||||
myNodeInfoFlow(),
|
||||
nodeDBbyNum,
|
||||
channelSetFlow,
|
||||
localConfigFlow,
|
||||
moduleConfigFlow,
|
||||
) { myInfo, nodes, channels, localConfig, localModuleConfig ->
|
||||
) { nodes, channels, localConfig, localModuleConfig ->
|
||||
deviceProfile {
|
||||
nodes[myInfo?.myNodeNum]?.user?.let {
|
||||
nodes.values.firstOrNull()?.user?.let {
|
||||
longName = it.longName
|
||||
shortName = it.shortName
|
||||
}
|
||||
|
|
|
@ -1904,6 +1904,10 @@ class MeshService : Service(), Logging {
|
|||
removeFixedPosition = true
|
||||
}
|
||||
})
|
||||
|
||||
updateNodeInfo(myNodeNum) {
|
||||
it.position = position.copy(time = currentSecond())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,8 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavHostController
|
||||
|
@ -61,7 +62,6 @@ import com.geeksville.mesh.android.Logging
|
|||
import com.geeksville.mesh.config
|
||||
import com.geeksville.mesh.model.Channel
|
||||
import com.geeksville.mesh.model.RadioConfigViewModel
|
||||
import com.geeksville.mesh.model.UIViewModel
|
||||
import com.geeksville.mesh.moduleConfig
|
||||
import com.geeksville.mesh.service.MeshService.ConnectionState
|
||||
import com.geeksville.mesh.ui.components.PreferenceCategory
|
||||
|
@ -95,18 +95,22 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||
@AndroidEntryPoint
|
||||
class DeviceSettingsFragment : ScreenFragment("Radio Configuration"), Logging {
|
||||
|
||||
private val model: UIViewModel by activityViewModels()
|
||||
private val model: RadioConfigViewModel by viewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
setFragmentResultListener("requestKey") { _, bundle ->
|
||||
val destNum = bundle.getInt("destNum")
|
||||
model.setDestNum(destNum)
|
||||
}
|
||||
|
||||
return ComposeView(requireContext()).apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
setBackgroundColor(ContextCompat.getColor(context, R.color.colorAdvancedBackground))
|
||||
setContent {
|
||||
// TODO change destNode to destNum and pass as navigation argument
|
||||
val node by model.destNode.collectAsStateWithLifecycle()
|
||||
|
||||
AppCompatTheme {
|
||||
|
@ -138,6 +142,7 @@ class DeviceSettingsFragment : ScreenFragment("Radio Configuration"), Logging {
|
|||
) { innerPadding ->
|
||||
RadioConfigNavHost(
|
||||
node = node,
|
||||
viewModel = model,
|
||||
navController = navController,
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
)
|
||||
|
@ -231,12 +236,10 @@ fun RadioConfigNavHost(
|
|||
val connectionState by viewModel.connectionState.collectAsStateWithLifecycle()
|
||||
val connected = connectionState == ConnectionState.CONNECTED && node != null
|
||||
|
||||
val myNodeInfo by viewModel.myNodeInfo.collectAsStateWithLifecycle() // FIXME
|
||||
val destNum = node?.num ?: 0
|
||||
val isLocal = destNum == myNodeInfo?.myNodeNum
|
||||
val isLocal = destNum == viewModel.myNodeNum
|
||||
|
||||
val radioConfigState by viewModel.radioConfigState.collectAsStateWithLifecycle()
|
||||
var location by remember(node) { mutableStateOf(node?.position) } // FIXME
|
||||
|
||||
val deviceProfile by viewModel.deviceProfile.collectAsStateWithLifecycle()
|
||||
val isWaiting = radioConfigState.responseState.isWaiting()
|
||||
|
@ -399,14 +402,13 @@ fun RadioConfigNavHost(
|
|||
composable(ConfigRoute.POSITION.name) {
|
||||
PositionConfigItemList(
|
||||
isLocal = isLocal,
|
||||
location = location,
|
||||
location = node?.position,
|
||||
positionConfig = radioConfigState.radioConfig.position,
|
||||
enabled = connected,
|
||||
onSaveClicked = { locationInput, positionInput ->
|
||||
if (positionInput.fixedPosition) {
|
||||
if (locationInput != null && locationInput != location) {
|
||||
if (locationInput != null && locationInput != node?.position) {
|
||||
viewModel.setFixedPosition(locationInput)
|
||||
location = locationInput
|
||||
}
|
||||
} else {
|
||||
if (radioConfigState.radioConfig.position.fixedPosition) {
|
||||
|
|
|
@ -18,7 +18,9 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
|
@ -171,7 +173,7 @@ class UsersFragment : ScreenFragment("Users"), Logging {
|
|||
}
|
||||
R.id.remote_admin -> {
|
||||
debug("calling remote admin --> destNum: ${node.num.toUInt()}")
|
||||
model.setDestNode(node)
|
||||
setFragmentResult("requestKey", bundleOf("destNum" to node.num))
|
||||
parentFragmentManager.beginTransaction()
|
||||
.replace(R.id.mainActivityLayout, DeviceSettingsFragment())
|
||||
.addToBackStack(null)
|
||||
|
|
|
@ -32,8 +32,8 @@ fun PositionConfigItemList(
|
|||
onSaveClicked: (position: Position?, config: PositionConfig) -> Unit,
|
||||
) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
var locationInput by remember { mutableStateOf(location) }
|
||||
var positionInput by remember { mutableStateOf(positionConfig) }
|
||||
var locationInput by remember(location) { mutableStateOf(location) }
|
||||
var positionInput by remember(positionConfig) { mutableStateOf(positionConfig) }
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
|
@ -182,8 +182,6 @@ fun PositionConfigItemList(
|
|||
enabled = positionInput != positionConfig || locationInput != location,
|
||||
onCancelClicked = {
|
||||
focusManager.clearFocus()
|
||||
locationInput = location
|
||||
positionInput = positionConfig
|
||||
},
|
||||
onSaveClicked = {
|
||||
focusManager.clearFocus()
|
||||
|
|
Ładowanie…
Reference in New Issue