mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-02-07 22:34:21 -05:00
refactor: convert connectionState to StateFlow
This commit is contained in:
@@ -27,6 +27,7 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.geeksville.mesh.android.*
|
||||
import com.geeksville.mesh.concurrent.handledLaunch
|
||||
@@ -541,7 +542,7 @@ class MainActivity : AppCompatActivity(), Logging {
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
model.connectionState.observe(this) { state ->
|
||||
model.connectionState.asLiveData().observe(this) { state ->
|
||||
onMeshConnectionChanged(state)
|
||||
updateConnectionStatusImage(state)
|
||||
}
|
||||
@@ -619,7 +620,7 @@ class MainActivity : AppCompatActivity(), Logging {
|
||||
menuInflater.inflate(R.menu.menu_main, menu)
|
||||
model.actionBarMenu = menu
|
||||
|
||||
updateConnectionStatusImage(model.connectionState.value!!)
|
||||
updateConnectionStatusImage(model.connectionState.value)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -465,7 +465,7 @@ class UIViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
// Connection state to our radio device
|
||||
val connectionState get() = radioConfigRepository.connectionState.asLiveData()
|
||||
val connectionState get() = radioConfigRepository.connectionState
|
||||
fun isConnected() = connectionState.value != MeshService.ConnectionState.DISCONNECTED
|
||||
|
||||
private val _requestChannelUrl = MutableLiveData<Uri?>(null)
|
||||
|
||||
@@ -140,6 +140,7 @@ class MeshService : Service(), Logging {
|
||||
DEVICE_SLEEP, // device is in LS sleep state, it will reconnected to us over bluetooth once it has data
|
||||
;
|
||||
|
||||
fun isConnected() = this == CONNECTED
|
||||
fun isDisconnected() = this == DISCONNECTED
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
@@ -29,11 +30,9 @@ import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.twotone.Check
|
||||
import androidx.compose.material.icons.twotone.Close
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.icons.twotone.ContentCopy
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -63,14 +62,14 @@ import androidx.fragment.app.activityViewModels
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.geeksville.mesh.AppOnlyProtos.ChannelSet
|
||||
import com.geeksville.mesh.analytics.DataPair
|
||||
import com.geeksville.mesh.android.GeeksvilleApplication
|
||||
import com.geeksville.mesh.android.Logging
|
||||
import com.geeksville.mesh.ChannelProtos
|
||||
import com.geeksville.mesh.ConfigProtos
|
||||
import com.geeksville.mesh.R
|
||||
import com.geeksville.mesh.analytics.DataPair
|
||||
import com.geeksville.mesh.android.BuildUtils.debug
|
||||
import com.geeksville.mesh.android.BuildUtils.errormsg
|
||||
import com.geeksville.mesh.android.GeeksvilleApplication
|
||||
import com.geeksville.mesh.android.Logging
|
||||
import com.geeksville.mesh.android.getCameraPermissions
|
||||
import com.geeksville.mesh.android.hasCameraPermission
|
||||
import com.geeksville.mesh.channelSet
|
||||
@@ -129,7 +128,7 @@ fun ChannelScreen(
|
||||
val focusManager = LocalFocusManager.current
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
|
||||
val connectionState by viewModel.connectionState.observeAsState()
|
||||
val connectionState by viewModel.connectionState.collectAsStateWithLifecycle()
|
||||
val enabled = connectionState == MeshService.ConnectionState.CONNECTED && !viewModel.isManaged
|
||||
|
||||
val channels by viewModel.channels.collectAsStateWithLifecycle()
|
||||
|
||||
@@ -161,7 +161,7 @@ class MessagesFragment : Fragment(), Logging {
|
||||
}
|
||||
|
||||
// If connection state _OR_ myID changes we have to fix our ability to edit outgoing messages
|
||||
model.connectionState.observe(viewLifecycleOwner) {
|
||||
model.connectionState.asLiveData().observe(viewLifecycleOwner) {
|
||||
// If we don't know our node ID and we are offline don't let user try to send
|
||||
val isConnected = model.isConnected()
|
||||
binding.textInputLayout.isEnabled = isConnected
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
@file:Suppress(
|
||||
"LongMethod",
|
||||
"MagicNumber",
|
||||
"CyclomaticComplexMethod",
|
||||
)
|
||||
|
||||
package com.geeksville.mesh.ui
|
||||
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
@@ -58,8 +52,6 @@ import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig
|
||||
import com.geeksville.mesh.MeshProtos
|
||||
import com.geeksville.mesh.R
|
||||
import com.geeksville.mesh.database.entity.NodeEntity
|
||||
import com.geeksville.mesh.service.MeshService
|
||||
import com.geeksville.mesh.service.MeshService.ConnectionState
|
||||
import com.geeksville.mesh.ui.components.MenuItemAction
|
||||
import com.geeksville.mesh.ui.components.NodeKeyStatusIcon
|
||||
import com.geeksville.mesh.ui.components.NodeMenu
|
||||
@@ -71,6 +63,7 @@ import com.geeksville.mesh.ui.theme.AppTheme
|
||||
import com.geeksville.mesh.util.metersIn
|
||||
import com.geeksville.mesh.util.toDistanceString
|
||||
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun NodeItem(
|
||||
@@ -84,10 +77,9 @@ fun NodeItem(
|
||||
blinking: Boolean = false,
|
||||
expanded: Boolean = false,
|
||||
currentTimeMillis: Long,
|
||||
connectionState: MeshService.ConnectionState? = ConnectionState.DISCONNECTED,
|
||||
isConnected: Boolean = false,
|
||||
) {
|
||||
val isUnknownUser = thatNode.isUnknownUser
|
||||
val unknownShortName = stringResource(id = R.string.unknown_node_short_name)
|
||||
val isIgnored = ignoreIncomingList.contains(thatNode.num)
|
||||
val longName = thatNode.user.longName.ifEmpty { stringResource(id = R.string.unknown_username) }
|
||||
|
||||
val isThisNode = thisNode?.num == thatNode.num
|
||||
@@ -101,28 +93,23 @@ fun NodeItem(
|
||||
MeshProtos.HardwareModel.UNSET -> MeshProtos.HardwareModel.UNSET.name
|
||||
else -> hwModel.name.replace('_', '-').replace('p', '.').lowercase()
|
||||
}
|
||||
val roleName = if (isUnknownUser) {
|
||||
val roleName = if (thatNode.isUnknownUser) {
|
||||
DeviceConfig.Role.UNRECOGNIZED.name
|
||||
} else {
|
||||
thatNode.user.role.name
|
||||
}
|
||||
val nodeId = thatNode.user.id.ifEmpty { "???" }
|
||||
|
||||
val highlight = Color(0x33FFFFFF)
|
||||
val bgColor by animateColorAsState(
|
||||
targetValue = if (blinking) highlight else Color.Transparent,
|
||||
targetValue = if (blinking) Color(color = 0x33FFFFFF) else Color.Transparent,
|
||||
animationSpec = repeatable(
|
||||
iterations = 6,
|
||||
animation = tween(
|
||||
durationMillis = 250,
|
||||
easing = FastOutSlowInEasing
|
||||
),
|
||||
animation = tween(durationMillis = 250, easing = FastOutSlowInEasing),
|
||||
repeatMode = RepeatMode.Reverse
|
||||
),
|
||||
label = "blinking node"
|
||||
)
|
||||
|
||||
val style = if (isUnknownUser) {
|
||||
val style = if (thatNode.isUnknownUser) {
|
||||
LocalTextStyle.current.copy(fontStyle = FontStyle.Italic)
|
||||
} else {
|
||||
LocalTextStyle.current
|
||||
@@ -179,7 +166,7 @@ fun NodeItem(
|
||||
content = {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = thatNode.user.shortName.ifEmpty { unknownShortName },
|
||||
text = thatNode.user.shortName.ifEmpty { "???" },
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = MaterialTheme.typography.button.fontSize,
|
||||
textDecoration = TextDecoration.LineThrough.takeIf {
|
||||
@@ -196,7 +183,7 @@ fun NodeItem(
|
||||
onMenuItemAction = menuItemActionClicked,
|
||||
expanded = menuExpanded,
|
||||
onDismissRequest = { menuExpanded = false },
|
||||
isConnected = connectionState == ConnectionState.CONNECTED,
|
||||
isConnected = isConnected,
|
||||
)
|
||||
}
|
||||
NodeKeyStatusIcon(
|
||||
@@ -208,11 +195,7 @@ fun NodeItem(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = longName,
|
||||
style = style,
|
||||
textDecoration = TextDecoration.LineThrough.takeIf {
|
||||
ignoreIncomingList.contains(
|
||||
thatNode.num
|
||||
)
|
||||
},
|
||||
textDecoration = TextDecoration.LineThrough.takeIf { isIgnored },
|
||||
softWrap = true,
|
||||
)
|
||||
|
||||
@@ -322,7 +305,7 @@ fun NodeItem(
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = nodeId,
|
||||
text = thatNode.user.id.ifEmpty { "???" },
|
||||
textAlign = TextAlign.End,
|
||||
fontSize = MaterialTheme.typography.button.fontSize,
|
||||
style = style,
|
||||
|
||||
@@ -183,7 +183,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
||||
}
|
||||
|
||||
// Only let user edit their name or set software update while connected to a radio
|
||||
model.connectionState.observe(viewLifecycleOwner) {
|
||||
model.connectionState.asLiveData().observe(viewLifecycleOwner) {
|
||||
updateNodeInfo()
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
@@ -96,7 +95,7 @@ fun NodesScreen(
|
||||
}
|
||||
|
||||
val currentTimeMillis = rememberTimeTickWithLifecycle()
|
||||
val connectionState by model.connectionState.observeAsState()
|
||||
val connectionState by model.connectionState.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
state = listState,
|
||||
@@ -140,7 +139,7 @@ fun NodesScreen(
|
||||
blinking = node == focusedNode,
|
||||
expanded = state.showDetails,
|
||||
currentTimeMillis = currentTimeMillis,
|
||||
connectionState = connectionState,
|
||||
isConnected = connectionState.isConnected(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user