Skip to content

Commit

Permalink
Adds 5 Ghz charts for Wi-Fi. Still needs cleanup but I am committing …
Browse files Browse the repository at this point in the history
…what I have before trying a different approach
  • Loading branch information
christianrowlands committed Jan 26, 2024
1 parent e14975a commit 35d44c7
Show file tree
Hide file tree
Showing 4 changed files with 288 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.craxiom.networksurvey.ui.wifi

import com.patrykandpatrick.vico.core.axis.AxisItemPlacer
import com.patrykandpatrick.vico.core.chart.dimensions.HorizontalDimensions
import com.patrykandpatrick.vico.core.chart.draw.ChartDrawContext
import com.patrykandpatrick.vico.core.chart.layout.HorizontalLayout
import com.patrykandpatrick.vico.core.context.MeasureContext

class ChannelAxisItemPlacer(
private val spacing: Int,
private val offset: Int,
private val shiftExtremeTicks: Boolean = false,
private val addExtremeLabelPadding: Boolean = false,
private val customLabelValues: List<Float> // Add your custom label values here
) : AxisItemPlacer.Horizontal {

override fun getShiftExtremeTicks(context: ChartDrawContext): Boolean = shiftExtremeTicks

override fun getAddFirstLabelPadding(context: MeasureContext) =
context.horizontalLayout is HorizontalLayout.FullWidth && addExtremeLabelPadding && offset == 0

override fun getAddLastLabelPadding(context: MeasureContext): Boolean =
with(context) {
context.horizontalLayout is HorizontalLayout.FullWidth && addExtremeLabelPadding
}

override fun getLabelValues(
context: ChartDrawContext,
visibleXRange: ClosedFloatingPointRange<Float>,
fullXRange: ClosedFloatingPointRange<Float>,
): List<Float> {
// Return your custom label values here
return customLabelValues
}

override fun getMeasuredLabelValues(
context: MeasureContext,
horizontalDimensions: HorizontalDimensions,
fullXRange: ClosedFloatingPointRange<Float>
): List<Float> {
return listOf(customLabelValues[0], customLabelValues[customLabelValues.size - 1])
}

override fun getStartHorizontalAxisInset(
context: MeasureContext,
horizontalDimensions: HorizontalDimensions,
tickThickness: Float
): Float {
return 0f
}

override fun getEndHorizontalAxisInset(
context: MeasureContext,
horizontalDimensions: HorizontalDimensions,
tickThickness: Float
): Float {
return 0f
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.patrykandpatrick.vico.core.chart.values.AxisValueOverrider
import com.patrykandpatrick.vico.core.component.shape.Shapes
import com.patrykandpatrick.vico.core.legend.HorizontalLegend
import com.patrykandpatrick.vico.core.legend.LegendItem
import com.patrykandpatrick.vico.core.model.CartesianChartModelProducer

/**
* A chart that shows signal values (e.g. RSSI) over time.
Expand All @@ -43,24 +44,34 @@ import com.patrykandpatrick.vico.core.legend.LegendItem
*/
@Composable
internal fun WifiSpectrumChart(
viewModel: WifiSpectrumChartViewModel
viewModel: WifiSpectrumChartViewModel,
modelProducer: CartesianChartModelProducer,
xSpacing: Int,
xOffset: Int,
customLabelValues: List<Float>
) {
ComposeChart(viewModel)
ComposeChart(viewModel, modelProducer, xSpacing, xOffset, customLabelValues)
}

@Composable
private fun ComposeChart(viewModel: WifiSpectrumChartViewModel) {
private fun ComposeChart(
viewModel: WifiSpectrumChartViewModel,
modelProducer: CartesianChartModelProducer,
xSpacing: Int,
xOffset: Int,
customLabelValues: List<Float>
) {
val wifiList by viewModel.wifiNetworkInfoList.collectAsStateWithLifecycle()


ProvideChartStyle(rememberSpectrumChartStyle(chartColors)) {
//val defaultLines = currentChartStyle.lineLayer.lines
CartesianChartHost(
modifier = Modifier.height(230.dp),
modelProducer = viewModel.modelProducer2Point4,
modifier = Modifier.height(220.dp),
modelProducer = modelProducer,
marker = null,//rememberMarker(""),
runInitialAnimation = false,
chartScrollSpec = rememberChartScrollSpec(isScrollEnabled = false),
getXStep = { 1f },
chart =
rememberCartesianChart(
rememberLineCartesianLayer(
Expand All @@ -77,6 +88,20 @@ private fun ComposeChart(viewModel: WifiSpectrumChartViewModel) {
),
bottomAxis =
rememberBottomAxis(
title = stringResource(R.string.channel),
itemPlacer = remember {
AxisItemPlacer.Horizontal.default(
spacing = xSpacing,
offset = xOffset
)
/*ChannelAxisItemPlacer(
spacing = xSpacing,
offset = xOffset,
shiftExtremeTicks = true,
addExtremeLabelPadding = true,
customLabelValues = customLabelValues
)*/
},
titleComponent =
rememberTextComponent(
background = rememberShapeComponent(Shapes.pillShape, color2),
Expand All @@ -85,7 +110,6 @@ private fun ComposeChart(viewModel: WifiSpectrumChartViewModel) {
margins = bottomAxisTitleMargins,
typeface = Typeface.MONOSPACE,
),
title = stringResource(R.string.channel),
),
//legend = rememberSsidLegend(wifiList),
//fadingEdges = rememberFadingEdges(),
Expand Down Expand Up @@ -154,7 +178,7 @@ private fun rememberLegend() =
textSize = legendItemLabelTextSize,
typeface = Typeface.MONOSPACE,
),
labelText = stringResource(R.string.series_x, index + 1),
labelText = stringResource(R.string.ssid, index + 1),
)
},
iconSize = legendItemIconSize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,31 @@ private const val WEAKER_SIGNAL_OFFSET = 5

const val WIFI_CHART_MIN = WIFI_SPECTRUM_MIN - 10

private val BAND_2_4_GHZ_CHANNELS = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
private val BAND_2_4_GHZ_CHANNELS_CHART_VIEW =
private val CHANNELS_2_4_GHZ = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
private val CHANNELS_2_4_GHZ_CHART_VIEW =
listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)

private val CHANNELS_5_GHZ_GROUP_1 = listOf(36, 40, 44, 48, 52, 56, 60, 64)
private val CHANNELS_5_GHZ_GROUP_1_CHART_VIEW = listOf(32, 36, 40, 44, 48, 52, 56, 60, 64, 68)

private val CHANNELS_5_GHZ_GROUP_2 =
listOf(100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144)
private val CHANNELS_5_GHZ_GROUP_2_CHART_VIEW =
listOf(96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148)

val CHANNELS_5_GHZ_GROUP_3 = listOf(149f, 153f, 157f, 161f, 165f, 169f, 173f, 177f)
private val CHANNELS_5_GHZ_GROUP_3_CHART_VIEW =
listOf(145, 149, 153, 157, 161, 165, 169, 173, 177, 181)

/**
* Abstract base class for the view model for a signal chart.
*/
class WifiSpectrumChartViewModel : ViewModel() {

internal val modelProducer2Point4 = CartesianChartModelProducer.build()
internal val modelProducer2Point4Ghz = CartesianChartModelProducer.build()
internal val modelProducer5GhzGroup1 = CartesianChartModelProducer.build()
internal val modelProducer5GhzGroup2 = CartesianChartModelProducer.build()
internal val modelProducer5GhzGroup3 = CartesianChartModelProducer.build()

private val _scanRateSeconds = MutableStateFlow(-1)
val scanRate = _scanRateSeconds.asStateFlow()
Expand Down Expand Up @@ -64,36 +79,163 @@ class WifiSpectrumChartViewModel : ViewModel() {
return
}

modelProducer2Point4.tryRunTransaction {
modelProducer2Point4Ghz.tryRunTransaction {
add(
create2Point4SeriesModel(wifiNetworkInfoList = wifiNetworkInfoList)
)
}

modelProducer5GhzGroup1.tryRunTransaction {
add(
create5Group1SeriesModel(wifiNetworkInfoList = wifiNetworkInfoList)
)
}

modelProducer5GhzGroup2.tryRunTransaction {
add(
create5Group2SeriesModel(wifiNetworkInfoList = wifiNetworkInfoList)
)
}

modelProducer5GhzGroup3.tryRunTransaction {
add(
create5Group3SeriesModel(wifiNetworkInfoList = wifiNetworkInfoList)
)
}
}

private fun create2Point4SeriesModel(wifiNetworkInfoList: List<WifiNetworkInfo>): LineCartesianLayerModel.Partial {
return LineCartesianLayerModel.partial {
wifiNetworkInfoList
.filter { it.channel in BAND_2_4_GHZ_CHANNELS }
.forEach { wifiNetwork ->
val signalStrengths = BAND_2_4_GHZ_CHANNELS_CHART_VIEW.map { channel ->
when (channel) {
wifiNetwork.channel -> constrictSignalStrength(wifiNetwork.signalStrength.toFloat())
wifiNetwork.channel - 1, wifiNetwork.channel + 1 -> (wifiNetwork.signalStrength - WEAKER_SIGNAL_OFFSET).toFloat()
else -> WIFI_CHART_MIN
val matchedWifiNetworks = wifiNetworkInfoList
.filter { it.channel in CHANNELS_2_4_GHZ }

if (matchedWifiNetworks.isEmpty()) {
series(
CHANNELS_2_4_GHZ_CHART_VIEW,
List(CHANNELS_2_4_GHZ_CHART_VIEW.size) { WIFI_CHART_MIN })
} else {

matchedWifiNetworks
.forEach { wifiNetwork ->
val signalStrengths = CHANNELS_2_4_GHZ_CHART_VIEW.map { channel ->
when (channel) {
wifiNetwork.channel -> constrictSignalStrength(wifiNetwork.signalStrength.toFloat())
wifiNetwork.channel - 1, wifiNetwork.channel + 1 -> (wifiNetwork.signalStrength - WEAKER_SIGNAL_OFFSET).toFloat()
else -> WIFI_CHART_MIN
}
}
series(CHANNELS_2_4_GHZ_CHART_VIEW, signalStrengths)
}
series(BAND_2_4_GHZ_CHANNELS_CHART_VIEW, signalStrengths)
}
}
}
}


// TODO Handle the 5 GHz range
private fun create5Group1SeriesModel(wifiNetworkInfoList: List<WifiNetworkInfo>): LineCartesianLayerModel.Partial {
return LineCartesianLayerModel.partial {
val matchedWifiNetworks = wifiNetworkInfoList
.filter { it.channel in CHANNELS_5_GHZ_GROUP_1 }

if (matchedWifiNetworks.isEmpty()) {
series(CHANNELS_5_GHZ_GROUP_1_CHART_VIEW, List(
CHANNELS_5_GHZ_GROUP_1_CHART_VIEW.size
) { WIFI_CHART_MIN })
} else {
matchedWifiNetworks
.forEach { wifiNetwork ->
val signalStrengths = CHANNELS_5_GHZ_GROUP_1_CHART_VIEW.map { channel ->
when (channel) {
wifiNetwork.channel -> constrictSignalStrength(wifiNetwork.signalStrength.toFloat())
wifiNetwork.channel - 1, wifiNetwork.channel + 1 -> (wifiNetwork.signalStrength - WEAKER_SIGNAL_OFFSET).toFloat()
else -> WIFI_CHART_MIN
}
}
series(CHANNELS_5_GHZ_GROUP_1_CHART_VIEW, signalStrengths)
}
}
}
}

private fun create5Group2SeriesModel(wifiNetworkInfoList: List<WifiNetworkInfo>): LineCartesianLayerModel.Partial {
return LineCartesianLayerModel.partial {
val matchedWifiNetworks = wifiNetworkInfoList
.filter { it.channel in CHANNELS_5_GHZ_GROUP_2 }

if (matchedWifiNetworks.isEmpty()) {
series(CHANNELS_5_GHZ_GROUP_2_CHART_VIEW, List(
CHANNELS_5_GHZ_GROUP_2_CHART_VIEW.size
) { WIFI_CHART_MIN })
} else {
matchedWifiNetworks
.forEach { wifiNetwork ->
val signalStrengths = CHANNELS_5_GHZ_GROUP_2_CHART_VIEW.map { channel ->
when (channel) {
wifiNetwork.channel -> constrictSignalStrength(wifiNetwork.signalStrength.toFloat())
wifiNetwork.channel - 1, wifiNetwork.channel + 1 -> (wifiNetwork.signalStrength - WEAKER_SIGNAL_OFFSET).toFloat()
else -> WIFI_CHART_MIN
}
}
series(CHANNELS_5_GHZ_GROUP_2_CHART_VIEW, signalStrengths)
}
}
}
}

private fun create5Group3SeriesModel(wifiNetworkInfoList: List<WifiNetworkInfo>): LineCartesianLayerModel.Partial {
return LineCartesianLayerModel.partial {
val matchedWifiNetworks = wifiNetworkInfoList
.filter { it.channel.toFloat() in CHANNELS_5_GHZ_GROUP_3 }

if (matchedWifiNetworks.isEmpty()) {
series(CHANNELS_5_GHZ_GROUP_3_CHART_VIEW, List(
CHANNELS_5_GHZ_GROUP_3_CHART_VIEW.size
) { WIFI_CHART_MIN })
} else {
matchedWifiNetworks
.forEach { wifiNetwork ->
val signalStrengths = CHANNELS_5_GHZ_GROUP_3_CHART_VIEW.map { channel ->
when (channel) {
wifiNetwork.channel -> constrictSignalStrength(wifiNetwork.signalStrength.toFloat())
wifiNetwork.channel - 1, wifiNetwork.channel + 1 -> (wifiNetwork.signalStrength - WEAKER_SIGNAL_OFFSET).toFloat()
else -> WIFI_CHART_MIN
}
}
series(CHANNELS_5_GHZ_GROUP_3_CHART_VIEW, signalStrengths)
}
}
}
}

private fun clearCharts() {
modelProducer2Point4.tryRunTransaction {
modelProducer2Point4Ghz.tryRunTransaction {
add(LineCartesianLayerModel.partial {
series(
CHANNELS_2_4_GHZ_CHART_VIEW,
List(CHANNELS_2_4_GHZ_CHART_VIEW.size) { WIFI_CHART_MIN })
})
}

modelProducer5GhzGroup1.tryRunTransaction {
add(LineCartesianLayerModel.partial {
series(CHANNELS_5_GHZ_GROUP_1_CHART_VIEW, List(
CHANNELS_5_GHZ_GROUP_1_CHART_VIEW.size
) { WIFI_CHART_MIN })
})
}

modelProducer5GhzGroup2.tryRunTransaction {
add(LineCartesianLayerModel.partial {
series(CHANNELS_5_GHZ_GROUP_2_CHART_VIEW, List(
CHANNELS_5_GHZ_GROUP_2_CHART_VIEW.size
) { WIFI_CHART_MIN })
})
}

modelProducer5GhzGroup3.tryRunTransaction {
add(LineCartesianLayerModel.partial {
series(BAND_2_4_GHZ_CHANNELS_CHART_VIEW, List(16) { WIFI_CHART_MIN })
series(CHANNELS_5_GHZ_GROUP_3_CHART_VIEW, List(
CHANNELS_5_GHZ_GROUP_3_CHART_VIEW.size
) { WIFI_CHART_MIN })
})
}
}
Expand Down
Loading

0 comments on commit 35d44c7

Please sign in to comment.