mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor: BLE transport and UI for Kotlin Multiplatform unification (#4911)
Some checks are pending
Dependency Submission / dependency-submission (push) Waiting to run
Main CI (Verify & Build) / validate-and-build (push) Waiting to run
Main Push Changelog / Generate main push changelog (push) Waiting to run
Some checks are pending
Dependency Submission / dependency-submission (push) Waiting to run
Main CI (Verify & Build) / validate-and-build (push) Waiting to run
Main Push Changelog / Generate main push changelog (push) Waiting to run
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
b0e91a390c
commit
6516287c62
42 changed files with 429 additions and 845 deletions
|
|
@ -67,7 +67,6 @@ import org.meshtastic.core.model.ConnectionState
|
|||
import org.meshtastic.core.model.DeviceType
|
||||
import org.meshtastic.core.navigation.ContactsRoutes
|
||||
import org.meshtastic.core.navigation.MeshtasticNavSavedStateConfig
|
||||
import org.meshtastic.core.navigation.NodeDetailRoutes
|
||||
import org.meshtastic.core.navigation.NodesRoutes
|
||||
import org.meshtastic.core.navigation.TopLevelDestination
|
||||
import org.meshtastic.core.navigation.navigateTopLevel
|
||||
|
|
@ -78,8 +77,7 @@ import org.meshtastic.core.resources.connecting
|
|||
import org.meshtastic.core.resources.device_sleeping
|
||||
import org.meshtastic.core.resources.disconnected
|
||||
import org.meshtastic.core.resources.must_update
|
||||
import org.meshtastic.core.ui.component.MeshtasticCommonAppSetup
|
||||
import org.meshtastic.core.ui.component.MeshtasticSnackbarProvider
|
||||
import org.meshtastic.core.ui.component.MeshtasticAppShell
|
||||
import org.meshtastic.core.ui.component.ScrollToTopEvent
|
||||
import org.meshtastic.core.ui.navigation.icon
|
||||
import org.meshtastic.core.ui.viewmodel.UIViewModel
|
||||
|
|
@ -111,13 +109,6 @@ fun MainScreen(uIViewModel: UIViewModel = koinViewModel(), scanModel: ScannerVie
|
|||
val connectionState by uIViewModel.connectionState.collectAsStateWithLifecycle()
|
||||
val unreadMessageCount by uIViewModel.unreadMessageCount.collectAsStateWithLifecycle()
|
||||
|
||||
MeshtasticCommonAppSetup(
|
||||
uiViewModel = uIViewModel,
|
||||
onNavigateToTracerouteMap = { destNum, requestId, logUuid ->
|
||||
backStack.add(NodeDetailRoutes.TracerouteMap(destNum = destNum, requestId = requestId, logUuid = logUuid))
|
||||
},
|
||||
)
|
||||
|
||||
AndroidAppVersionCheck(uIViewModel)
|
||||
val navSuiteType =
|
||||
NavigationSuiteScaffoldDefaults.navigationSuiteType(
|
||||
|
|
@ -129,118 +120,127 @@ fun MainScreen(uIViewModel: UIViewModel = koinViewModel(), scanModel: ScannerVie
|
|||
// State for determining the connection type icon to display
|
||||
val selectedDevice by scanModel.selectedNotNullFlow.collectAsStateWithLifecycle()
|
||||
|
||||
NavigationSuiteScaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
navigationSuiteItems = {
|
||||
TopLevelDestination.entries.forEach { destination ->
|
||||
val isSelected = destination == topLevelDestination
|
||||
val isConnectionsRoute = destination == TopLevelDestination.Connections
|
||||
item(
|
||||
icon = {
|
||||
TooltipBox(
|
||||
positionProvider =
|
||||
TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(
|
||||
if (isConnectionsRoute) {
|
||||
when (connectionState) {
|
||||
ConnectionState.Connected -> stringResource(Res.string.connected)
|
||||
ConnectionState.Connecting -> stringResource(Res.string.connecting)
|
||||
ConnectionState.DeviceSleep ->
|
||||
stringResource(Res.string.device_sleeping)
|
||||
ConnectionState.Disconnected -> stringResource(Res.string.disconnected)
|
||||
}
|
||||
} else {
|
||||
stringResource(destination.label)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
state = rememberTooltipState(),
|
||||
) {
|
||||
if (isConnectionsRoute) {
|
||||
org.meshtastic.feature.connections.ui.components.AnimatedConnectionsNavIcon(
|
||||
connectionState = connectionState,
|
||||
deviceType = DeviceType.fromAddress(selectedDevice),
|
||||
meshActivityFlow = uIViewModel.meshActivity,
|
||||
colorScheme = colorScheme,
|
||||
)
|
||||
} else {
|
||||
BadgedBox(
|
||||
badge = {
|
||||
if (destination == TopLevelDestination.Conversations) {
|
||||
// Keep track of the last non-zero count for display during exit animation
|
||||
var lastNonZeroCount by remember { mutableIntStateOf(unreadMessageCount) }
|
||||
if (unreadMessageCount > 0) {
|
||||
lastNonZeroCount = unreadMessageCount
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = unreadMessageCount > 0,
|
||||
enter = scaleIn() + fadeIn(),
|
||||
exit = scaleOut() + fadeOut(),
|
||||
) {
|
||||
Badge { Text(lastNonZeroCount.toString()) }
|
||||
}
|
||||
}
|
||||
},
|
||||
) {
|
||||
Crossfade(isSelected, label = "BottomBarIcon") { isSelectedState ->
|
||||
Icon(
|
||||
imageVector = destination.icon,
|
||||
contentDescription = stringResource(destination.label),
|
||||
tint =
|
||||
if (isSelectedState) colorScheme.primary else LocalContentColor.current,
|
||||
MeshtasticAppShell(
|
||||
backStack = backStack,
|
||||
uiViewModel = uIViewModel,
|
||||
hostModifier = Modifier.safeDrawingPadding().padding(bottom = 16.dp),
|
||||
) {
|
||||
NavigationSuiteScaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
navigationSuiteItems = {
|
||||
TopLevelDestination.entries.forEach { destination ->
|
||||
val isSelected = destination == topLevelDestination
|
||||
val isConnectionsRoute = destination == TopLevelDestination.Connections
|
||||
item(
|
||||
icon = {
|
||||
TooltipBox(
|
||||
positionProvider =
|
||||
TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(
|
||||
if (isConnectionsRoute) {
|
||||
when (connectionState) {
|
||||
ConnectionState.Connected -> stringResource(Res.string.connected)
|
||||
ConnectionState.Connecting -> stringResource(Res.string.connecting)
|
||||
ConnectionState.DeviceSleep ->
|
||||
stringResource(Res.string.device_sleeping)
|
||||
ConnectionState.Disconnected ->
|
||||
stringResource(Res.string.disconnected)
|
||||
}
|
||||
} else {
|
||||
stringResource(destination.label)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
state = rememberTooltipState(),
|
||||
) {
|
||||
if (isConnectionsRoute) {
|
||||
org.meshtastic.feature.connections.ui.components.AnimatedConnectionsNavIcon(
|
||||
connectionState = connectionState,
|
||||
deviceType = DeviceType.fromAddress(selectedDevice),
|
||||
meshActivityFlow = uIViewModel.meshActivity,
|
||||
colorScheme = colorScheme,
|
||||
)
|
||||
} else {
|
||||
BadgedBox(
|
||||
badge = {
|
||||
if (destination == TopLevelDestination.Conversations) {
|
||||
// Keep track of the last non-zero count for display during exit
|
||||
// animation
|
||||
var lastNonZeroCount by remember {
|
||||
mutableIntStateOf(unreadMessageCount)
|
||||
}
|
||||
if (unreadMessageCount > 0) {
|
||||
lastNonZeroCount = unreadMessageCount
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = unreadMessageCount > 0,
|
||||
enter = scaleIn() + fadeIn(),
|
||||
exit = scaleOut() + fadeOut(),
|
||||
) {
|
||||
Badge { Text(lastNonZeroCount.toString()) }
|
||||
}
|
||||
}
|
||||
},
|
||||
) {
|
||||
Crossfade(isSelected, label = "BottomBarIcon") { isSelectedState ->
|
||||
Icon(
|
||||
imageVector = destination.icon,
|
||||
contentDescription = stringResource(destination.label),
|
||||
tint =
|
||||
if (isSelectedState) {
|
||||
colorScheme.primary
|
||||
} else {
|
||||
LocalContentColor.current
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
selected = isSelected,
|
||||
label = {
|
||||
Text(
|
||||
text = stringResource(destination.label),
|
||||
modifier =
|
||||
if (navSuiteType == NavigationSuiteType.ShortNavigationBarCompact) {
|
||||
Modifier.width(1.dp)
|
||||
.height(1.dp) // hide on phone - min 1x1 or talkback won't see it.
|
||||
},
|
||||
selected = isSelected,
|
||||
label = {
|
||||
Text(
|
||||
text = stringResource(destination.label),
|
||||
modifier =
|
||||
if (navSuiteType == NavigationSuiteType.ShortNavigationBarCompact) {
|
||||
Modifier.width(1.dp)
|
||||
.height(1.dp) // hide on phone - min 1x1 or talkback won't see it.
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
val isRepress = destination == topLevelDestination
|
||||
if (isRepress) {
|
||||
when (destination) {
|
||||
TopLevelDestination.Nodes -> {
|
||||
val onNodesList = currentKey is NodesRoutes.Nodes
|
||||
if (!onNodesList) {
|
||||
backStack.navigateTopLevel(destination.route)
|
||||
}
|
||||
uIViewModel.emitScrollToTopEvent(ScrollToTopEvent.NodesTabPressed)
|
||||
}
|
||||
TopLevelDestination.Conversations -> {
|
||||
val onConversationsList = currentKey is ContactsRoutes.Contacts
|
||||
if (!onConversationsList) {
|
||||
backStack.navigateTopLevel(destination.route)
|
||||
}
|
||||
uIViewModel.emitScrollToTopEvent(ScrollToTopEvent.ConversationsTabPressed)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
val isRepress = destination == topLevelDestination
|
||||
if (isRepress) {
|
||||
when (destination) {
|
||||
TopLevelDestination.Nodes -> {
|
||||
val onNodesList = currentKey is NodesRoutes.Nodes
|
||||
if (!onNodesList) {
|
||||
backStack.navigateTopLevel(destination.route)
|
||||
}
|
||||
uIViewModel.emitScrollToTopEvent(ScrollToTopEvent.NodesTabPressed)
|
||||
}
|
||||
TopLevelDestination.Conversations -> {
|
||||
val onConversationsList = currentKey is ContactsRoutes.Contacts
|
||||
if (!onConversationsList) {
|
||||
backStack.navigateTopLevel(destination.route)
|
||||
}
|
||||
uIViewModel.emitScrollToTopEvent(ScrollToTopEvent.ConversationsTabPressed)
|
||||
}
|
||||
else -> Unit
|
||||
backStack.navigateTopLevel(destination.route)
|
||||
}
|
||||
} else {
|
||||
backStack.navigateTopLevel(destination.route)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
) {
|
||||
MeshtasticSnackbarProvider(
|
||||
snackbarManager = uIViewModel.snackbarManager,
|
||||
hostModifier = Modifier.safeDrawingPadding().padding(bottom = 16.dp),
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
) {
|
||||
val provider =
|
||||
entryProvider<NavKey> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue