diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1bcfa30ed..7c56194b4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -197,6 +197,7 @@ dependencies { implementation(projects.core.strings) implementation(projects.core.ui) implementation(projects.feature.map) + implementation(projects.feature.node) // Bundles implementation(libs.bundles.markdown) diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml index 9ac0d78c3..52110d240 100644 --- a/app/detekt-baseline.xml +++ b/app/detekt-baseline.xml @@ -1,4 +1,4 @@ - + @@ -6,7 +6,7 @@ CommentSpacing:Constants.kt$/// a bool true means we expect this condition to continue until, false means device might come back CommentSpacing:Coroutines.kt$/// Wrap launch with an exception handler, FIXME, move into a utility lib CommentWrapping:SignalMetrics.kt$Metric.SNR$/* Selected 12 as the max to get 4 equal vertical sections. */ - ComposableNaming:NodeDetail.kt$notesSection + ComposableNaming:NodeDetailScreen.kt$notesSection ComposableParamOrder:ChannelSettingsItemList.kt$ChannelSettingsItemList ComposableParamOrder:Debug.kt$DebugMenuActions ComposableParamOrder:Debug.kt$DecodedPayloadBlock @@ -14,15 +14,12 @@ ComposableParamOrder:DebugSearch.kt$DebugSearchStateviewModelDefaults ComposableParamOrder:DeviceMetrics.kt$DeviceMetricsChart ComposableParamOrder:EditBase64Preference.kt$EditBase64Preference - ComposableParamOrder:ElevationInfo.kt$ElevationInfo ComposableParamOrder:EmptyStateContent.kt$EmptyStateContent ComposableParamOrder:EnvironmentCharts.kt$ChartContent ComposableParamOrder:EnvironmentCharts.kt$EnvironmentMetricsChart ComposableParamOrder:EnvironmentCharts.kt$MetricPlottingCanvas ComposableParamOrder:HostMetricsLog.kt$HostMetricsItem ComposableParamOrder:HostMetricsLog.kt$LogLine - ComposableParamOrder:LastHeardInfo.kt$LastHeardInfo - ComposableParamOrder:LinkedCoordinates.kt$LinkedCoordinates ComposableParamOrder:MainAppBar.kt$MainAppBar ComposableParamOrder:MapReportingPreference.kt$MapReportingPreference ComposableParamOrder:Message.kt$MessageScreen @@ -32,24 +29,16 @@ ComposableParamOrder:MessageItem.kt$MessageItem ComposableParamOrder:MessageList.kt$DeliveryInfo ComposableParamOrder:MessageList.kt$MessageList - ComposableParamOrder:NodeChip.kt$NodeChip - ComposableParamOrder:NodeDetail.kt$DeviceActions - ComposableParamOrder:NodeDetail.kt$EnvironmentMetrics - ComposableParamOrder:NodeDetail.kt$NodeActionButton - ComposableParamOrder:NodeDetail.kt$NodeDetailList - ComposableParamOrder:NodeFilterTextField.kt$NodeFilterTextField - ComposableParamOrder:NodeItem.kt$NodeItem - ComposableParamOrder:NodeKeyStatusIcon.kt$NodeKeyStatusIcon + ComposableParamOrder:NodeDetailScreen.kt$DeviceActions + ComposableParamOrder:NodeDetailScreen.kt$EnvironmentMetrics + ComposableParamOrder:NodeDetailScreen.kt$NodeActionButton + ComposableParamOrder:NodeDetailScreen.kt$NodeDetailList ComposableParamOrder:PaxMetrics.kt$PaxMetricsChart ComposableParamOrder:PermissionScreenLayout.kt$PermissionScreenLayout ComposableParamOrder:PowerMetrics.kt$PowerMetricsChart ComposableParamOrder:QuickChat.kt$OutlinedTextFieldWithCounter - ComposableParamOrder:SatelliteCountInfo.kt$SatelliteCountInfo - ComposableParamOrder:SettingsItem.kt$SettingsItem - ComposableParamOrder:SignalInfo.kt$SignalInfo ComposableParamOrder:SignalMetrics.kt$SignalMetricsChart ComposableParamOrder:TopLevelNavIcon.kt$ConnectionsNavIcon - ComposableParamOrder:TracerouteButton.kt$TracerouteButton ComposableParamOrder:WarningDialog.kt$WarningDialog CyclomaticComplexMethod:MeshService.kt$MeshService$private fun handleReceivedData(packet: MeshPacket) CyclomaticComplexMethod:NetworkConfigItemList.kt$@Composable fun NetworkConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) @@ -57,7 +46,7 @@ CyclomaticComplexMethod:RadioConfigViewModel.kt$RadioConfigViewModel$private fun processPacketResponse(packet: MeshProtos.MeshPacket) EmptyClassBlock:DebugLogFile.kt$BinaryLogFile${ } EmptyFunctionBlock:NopInterface.kt$NopInterface${ } - EmptyFunctionBlock:NsdManager.kt$<no name provided>${ } + EmptyFunctionBlock:NsdManager.kt$<no name provided>${ } EmptyFunctionBlock:TrustAllX509TrustManager.kt$TrustAllX509TrustManager${} FinalNewline:BLEException.kt$com.geeksville.mesh.service.BLEException.kt FinalNewline:BluetoothInterfaceFactory.kt$com.geeksville.mesh.repository.radio.BluetoothInterfaceFactory.kt @@ -84,8 +73,8 @@ LambdaParameterEventTrailing:Message.kt$onClick LambdaParameterEventTrailing:Message.kt$onSendMessage LambdaParameterEventTrailing:MessageList.kt$onReply - LambdaParameterEventTrailing:NodeDetail.kt$onClick - LambdaParameterEventTrailing:NodeDetail.kt$onSaveNotes + LambdaParameterEventTrailing:NodeDetailScreen.kt$onClick + LambdaParameterEventTrailing:NodeDetailScreen.kt$onSaveNotes LambdaParameterInRestartableEffect:Channel.kt$onConfirm LambdaParameterInRestartableEffect:MessageList.kt$onUnreadChanged LargeClass:MeshService.kt$MeshService : Service @@ -145,7 +134,7 @@ MagicNumber:SafeBluetooth.kt$SafeBluetooth$100 MagicNumber:SafeBluetooth.kt$SafeBluetooth$1000 MagicNumber:SafeBluetooth.kt$SafeBluetooth$2500 - MagicNumber:SafeBluetooth.kt$SafeBluetooth.<no name provided>$2500 + MagicNumber:SafeBluetooth.kt$SafeBluetooth.<no name provided>$2500 MagicNumber:SerialConnectionImpl.kt$SerialConnectionImpl$115200 MagicNumber:SerialConnectionImpl.kt$SerialConnectionImpl$200 MagicNumber:ServiceClient.kt$ServiceClient$500 @@ -158,7 +147,7 @@ MagicNumber:TCPInterface.kt$TCPInterface$500 MagicNumber:UIState.kt$4 MatchingDeclarationName:MeshServiceStarter.kt$ServiceStarter : Worker - MaxLineLength:BluetoothInterface.kt$/* Info for the esp32 device side code. See that source for the 'gold' standard docs on this interface. MeshBluetoothService UUID 6ba1b218-15a8-461f-9fa8-5dcae273eafd FIXME - notify vs indication for fromradio output. Using notify for now, not sure if that is best FIXME - in the esp32 mesh management code, occasionally mirror the current net db to flash, so that if we reboot we still have a good guess of users who are out there. FIXME - make sure this protocol is guaranteed robust and won't drop packets "According to the BLE specification the notification length can be max ATT_MTU - 3. The 3 bytes subtracted is the 3-byte header(OP-code (operation, 1 byte) and the attribute handle (2 bytes)). In BLE 4.1 the ATT_MTU is 23 bytes (20 bytes for payload), but in BLE 4.2 the ATT_MTU can be negotiated up to 247 bytes." MAXPACKET is 256? look into what the lora lib uses. FIXME Characteristics: UUID properties description 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 read fromradio - contains a newly received packet destined towards the phone (up to MAXPACKET bytes? per packet). After reading the esp32 will put the next packet in this mailbox. If the FIFO is empty it will put an empty packet in this mailbox. f75c76d2-129e-4dad-a1dd-7866124401e7 write toradio - write ToRadio protobufs to this charstic to send them (up to MAXPACKET len) ed9da18c-a800-4f66-a670-aa7547e34453 read|notify|write fromnum - the current packet # in the message waiting inside fromradio, if the phone sees this notify it should read messages until it catches up with this number. The phone can write to this register to go backwards up to FIXME packets, to handle the rare case of a fromradio packet was dropped after the esp32 callback was called, but before it arrives at the phone. If the phone writes to this register the esp32 will discard older packets and put the next packet >= fromnum in fromradio. When the esp32 advances fromnum, it will delay doing the notify by 100ms, in the hopes that the notify will never actally need to be sent if the phone is already pulling from fromradio. Note: that if the phone ever sees this number decrease, it means the esp32 has rebooted. Re: queue management Not all messages are kept in the fromradio queue (filtered based on SubPacket): * only the most recent Position and User messages for a particular node are kept * all Data SubPackets are kept * No WantNodeNum / DenyNodeNum messages are kept A variable keepAllPackets, if set to true will suppress this behavior and instead keep everything for forwarding to the phone (for debugging) */ + MaxLineLength:BluetoothInterface.kt$/* Info for the esp32 device side code. See that source for the 'gold' standard docs on this interface. MeshBluetoothService UUID 6ba1b218-15a8-461f-9fa8-5dcae273eafd FIXME - notify vs indication for fromradio output. Using notify for now, not sure if that is best FIXME - in the esp32 mesh management code, occasionally mirror the current net db to flash, so that if we reboot we still have a good guess of users who are out there. FIXME - make sure this protocol is guaranteed robust and won't drop packets "According to the BLE specification the notification length can be max ATT_MTU - 3. The 3 bytes subtracted is the 3-byte header(OP-code (operation, 1 byte) and the attribute handle (2 bytes)). In BLE 4.1 the ATT_MTU is 23 bytes (20 bytes for payload), but in BLE 4.2 the ATT_MTU can be negotiated up to 247 bytes." MAXPACKET is 256? look into what the lora lib uses. FIXME Characteristics: UUID properties description 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 read fromradio - contains a newly received packet destined towards the phone (up to MAXPACKET bytes? per packet). After reading the esp32 will put the next packet in this mailbox. If the FIFO is empty it will put an empty packet in this mailbox. f75c76d2-129e-4dad-a1dd-7866124401e7 write toradio - write ToRadio protobufs to this charstic to send them (up to MAXPACKET len) ed9da18c-a800-4f66-a670-aa7547e34453 read|notify|write fromnum - the current packet # in the message waiting inside fromradio, if the phone sees this notify it should read messages until it catches up with this number. The phone can write to this register to go backwards up to FIXME packets, to handle the rare case of a fromradio packet was dropped after the esp32 callback was called, but before it arrives at the phone. If the phone writes to this register the esp32 will discard older packets and put the next packet >= fromnum in fromradio. When the esp32 advances fromnum, it will delay doing the notify by 100ms, in the hopes that the notify will never actally need to be sent if the phone is already pulling from fromradio. Note: that if the phone ever sees this number decrease, it means the esp32 has rebooted. Re: queue management Not all messages are kept in the fromradio queue (filtered based on SubPacket): * only the most recent Position and User messages for a particular node are kept * all Data SubPackets are kept * No WantNodeNum / DenyNodeNum messages are kept A variable keepAllPackets, if set to true will suppress this behavior and instead keep everything for forwarding to the phone (for debugging) */ ModifierClickableOrder:Channel.kt$clickable(onClick = onClick) ModifierMissing:BLEDevices.kt$BLEDevices ModifierMissing:Channel.kt$ChannelScreen @@ -185,8 +174,7 @@ ModifierMissing:MessageActions.kt$ReplyButton ModifierMissing:NetworkConfigItemList.kt$NetworkConfigScreen ModifierMissing:NetworkDevices.kt$NetworkDevices - ModifierMissing:NodeScreen.kt$NodeScreen - ModifierMissing:NodeStatusIcons.kt$NodeStatusIcons + ModifierMissing:NodeListScreen.kt$NodeListScreen ModifierMissing:PaxMetrics.kt$PaxMetricsItem ModifierMissing:PaxMetrics.kt$PaxMetricsScreen ModifierMissing:PositionConfigItemList.kt$PositionConfigScreen @@ -199,9 +187,6 @@ ModifierMissing:Reaction.kt$ReactionDialog ModifierMissing:SecurityConfigItemList.kt$SecurityConfigScreen ModifierMissing:SecurityIcon.kt$SecurityIcon - ModifierMissing:SettingsItem.kt$SettingsItem - ModifierMissing:SettingsItem.kt$SettingsItemDetail - ModifierMissing:SettingsItem.kt$SettingsItemSwitch ModifierMissing:SettingsScreen.kt$SettingsScreen ModifierMissing:Share.kt$ShareScreen ModifierMissing:SignalMetrics.kt$SignalMetricsScreen @@ -217,11 +202,10 @@ ModifierNotUsedAtRoot:PowerMetrics.kt$modifier = modifier.weight(weight = Y_AXIS_WEIGHT) ModifierNotUsedAtRoot:PowerMetrics.kt$modifier = modifier.width(dp) ModifierNotUsedAtRoot:PowerMetrics.kt$modifier.width(dp) - ModifierNotUsedAtRoot:SignalInfo.kt$modifier = modifier ModifierNotUsedAtRoot:SignalMetrics.kt$modifier = modifier.weight(weight = Y_AXIS_WEIGHT) ModifierNotUsedAtRoot:SignalMetrics.kt$modifier = modifier.width(dp) ModifierNotUsedAtRoot:SignalMetrics.kt$modifier.width(dp) - ModifierReused:DeviceMetrics.kt$Canvas(modifier = modifier.width(dp)) { val height = size.height val width = size.width for (i in telemetries.indices) { val telemetry = telemetries[i] /* x-value time */ val xRatio = (telemetry.time - oldest.time).toFloat() / timeDiff val x = xRatio * width /* Channel Utilization */ plotPoint( drawContext = drawContext, color = Device.CH_UTIL.color, x = x, value = telemetry.deviceMetrics.channelUtilization, divisor = MAX_PERCENT_VALUE, ) /* Air Utilization Transmit */ plotPoint( drawContext = drawContext, color = Device.AIR_UTIL.color, x = x, value = telemetry.deviceMetrics.airUtilTx, divisor = MAX_PERCENT_VALUE, ) } /* Battery Line */ var index = 0 while (index < telemetries.size) { val path = Path() index = createPath( telemetries = telemetries, index = index, path = path, oldestTime = oldest.time, timeRange = timeDiff, width = width, timeThreshold = selectedTime.timeThreshold(), ) { i -> val telemetry = telemetries.getOrNull(i) ?: telemetries.last() val ratio = telemetry.deviceMetrics.batteryLevel / MAX_PERCENT_VALUE val y = height - (ratio * height) return@createPath y } drawPath( path = path, color = Device.BATTERY.color, style = Stroke(width = GraphUtil.RADIUS, cap = StrokeCap.Round), ) } } + ModifierReused:DeviceMetrics.kt$Canvas(modifier = modifier.width(dp)) { val height = size.height val width = size.width for (i in telemetries.indices) { val telemetry = telemetries[i] /* x-value time */ val xRatio = (telemetry.time - oldest.time).toFloat() / timeDiff val x = xRatio * width /* Channel Utilization */ plotPoint( drawContext = drawContext, color = Device.CH_UTIL.color, x = x, value = telemetry.deviceMetrics.channelUtilization, divisor = MAX_PERCENT_VALUE, ) /* Air Utilization Transmit */ plotPoint( drawContext = drawContext, color = Device.AIR_UTIL.color, x = x, value = telemetry.deviceMetrics.airUtilTx, divisor = MAX_PERCENT_VALUE, ) } /* Battery Line */ var index = 0 while (index < telemetries.size) { val path = Path() index = createPath( telemetries = telemetries, index = index, path = path, oldestTime = oldest.time, timeRange = timeDiff, width = width, timeThreshold = selectedTime.timeThreshold(), ) { i -> val telemetry = telemetries.getOrNull(i) ?: telemetries.last() val ratio = telemetry.deviceMetrics.batteryLevel / MAX_PERCENT_VALUE val y = height - (ratio * height) return@createPath y } drawPath( path = path, color = Device.BATTERY.color, style = Stroke(width = GraphUtil.RADIUS, cap = StrokeCap.Round), ) } } ModifierReused:DeviceMetrics.kt$HorizontalLinesOverlay( modifier.width(dp), lineColors = listOf(graphColor, Color.Yellow, Color.Red, graphColor, graphColor), ) ModifierReused:DeviceMetrics.kt$TimeAxisOverlay(modifier.width(dp), oldest = oldest.time, newest = newest.time, selectedTime.lineInterval()) ModifierReused:EnvironmentCharts.kt$Box( contentAlignment = Alignment.TopStart, modifier = modifier.horizontalScroll(state = scrollState, reverseScrolling = true), ) { HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { graphColor }) TimeAxisOverlay(modifier = modifier.width(dp), oldest = oldest, newest = newest, selectedTime.lineInterval()) MetricPlottingCanvas( modifier = modifier.width(dp), telemetries = telemetries, graphData = graphData, selectedTime = selectedTime, oldest = oldest, timeDiff = timeDiff, rightMin = rightMin, rightMax = rightMax, ) } @@ -229,9 +213,9 @@ ModifierReused:EnvironmentCharts.kt$MetricPlottingCanvas( modifier = modifier.width(dp), telemetries = telemetries, graphData = graphData, selectedTime = selectedTime, oldest = oldest, timeDiff = timeDiff, rightMin = rightMin, rightMax = rightMax, ) ModifierReused:EnvironmentCharts.kt$TimeAxisOverlay(modifier = modifier.width(dp), oldest = oldest, newest = newest, selectedTime.lineInterval()) ModifierReused:PaxMetrics.kt$HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { Color.LightGray }) - ModifierReused:PaxMetrics.kt$Row(modifier = modifier.fillMaxWidth().fillMaxHeight(fraction = 0.33f)) { YAxisLabels( modifier = Modifier.weight(Y_AXIS_WEIGHT).fillMaxHeight().padding(start = 8.dp), labelColor = MaterialTheme.colorScheme.onSurface, minValue = minValue, maxValue = maxValue, ) Box( contentAlignment = Alignment.TopStart, modifier = Modifier.horizontalScroll(state = scrollState, reverseScrolling = true).weight(CHART_WEIGHT), ) { HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { Color.LightGray }) TimeAxisOverlay(modifier.width(dp), oldest = minTime, newest = maxTime, timeFrame.lineInterval()) Canvas(modifier = Modifier.width(dp).fillMaxHeight()) { val width = size.width val height = size.height fun xForTime(t: Int): Float = if (maxTime == minTime) width / 2 else (t - minTime).toFloat() / (maxTime - minTime) * width fun yForValue(v: Int): Float = height - (v - minValue) / (maxValue - minValue) * height fun drawLine(series: List<Pair<Int, Int>>, color: Color) { for (i in 1 until series.size) { drawLine( color = color, start = Offset(xForTime(series[i - 1].first), yForValue(series[i - 1].second)), end = Offset(xForTime(series[i].first), yForValue(series[i].second)), strokeWidth = 2.dp.toPx(), ) } } drawLine(bleSeries, PaxSeries.BLE.color) drawLine(wifiSeries, PaxSeries.WIFI.color) drawLine(totalSeries, PaxSeries.PAX.color) } } YAxisLabels( modifier = Modifier.weight(Y_AXIS_WEIGHT).fillMaxHeight().padding(end = 8.dp), labelColor = MaterialTheme.colorScheme.onSurface, minValue = minValue, maxValue = maxValue, ) } + ModifierReused:PaxMetrics.kt$Row(modifier = modifier.fillMaxWidth().fillMaxHeight(fraction = 0.33f)) { YAxisLabels( modifier = Modifier.weight(Y_AXIS_WEIGHT).fillMaxHeight().padding(start = 8.dp), labelColor = MaterialTheme.colorScheme.onSurface, minValue = minValue, maxValue = maxValue, ) Box( contentAlignment = Alignment.TopStart, modifier = Modifier.horizontalScroll(state = scrollState, reverseScrolling = true).weight(CHART_WEIGHT), ) { HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { Color.LightGray }) TimeAxisOverlay(modifier.width(dp), oldest = minTime, newest = maxTime, timeFrame.lineInterval()) Canvas(modifier = Modifier.width(dp).fillMaxHeight()) { val width = size.width val height = size.height fun xForTime(t: Int): Float = if (maxTime == minTime) width / 2 else (t - minTime).toFloat() / (maxTime - minTime) * width fun yForValue(v: Int): Float = height - (v - minValue) / (maxValue - minValue) * height fun drawLine(series: List<Pair<Int, Int>>, color: Color) { for (i in 1 until series.size) { drawLine( color = color, start = Offset(xForTime(series[i - 1].first), yForValue(series[i - 1].second)), end = Offset(xForTime(series[i].first), yForValue(series[i].second)), strokeWidth = 2.dp.toPx(), ) } } drawLine(bleSeries, PaxSeries.BLE.color) drawLine(wifiSeries, PaxSeries.WIFI.color) drawLine(totalSeries, PaxSeries.PAX.color) } } YAxisLabels( modifier = Modifier.weight(Y_AXIS_WEIGHT).fillMaxHeight().padding(end = 8.dp), labelColor = MaterialTheme.colorScheme.onSurface, minValue = minValue, maxValue = maxValue, ) } ModifierReused:PaxMetrics.kt$TimeAxisOverlay(modifier.width(dp), oldest = minTime, newest = maxTime, timeFrame.lineInterval()) - ModifierReused:PowerMetrics.kt$Canvas(modifier = modifier.width(dp)) { val width = size.width val height = size.height /* Voltage */ var index = 0 while (index < telemetries.size) { val path = Path() index = createPath( telemetries = telemetries, index = index, path = path, oldestTime = oldest.time, timeRange = timeDiff, width = width, timeThreshold = selectedTime.timeThreshold(), ) { i -> val telemetry = telemetries.getOrNull(i) ?: telemetries.last() val ratio = (retrieveVoltage(selectedChannel, telemetry) - voltageMin) / voltageDiff val y = height - (ratio * height) return@createPath y } drawPath( path = path, color = VOLTAGE_COLOR, style = Stroke(width = GraphUtil.RADIUS, cap = StrokeCap.Round), ) } /* Current */ index = 0 while (index < telemetries.size) { val path = Path() index = createPath( telemetries = telemetries, index = index, path = path, oldestTime = oldest.time, timeRange = timeDiff, width = width, timeThreshold = selectedTime.timeThreshold(), ) { i -> val telemetry = telemetries.getOrNull(i) ?: telemetries.last() val ratio = (retrieveCurrent(selectedChannel, telemetry) - Power.CURRENT.min) / currentDiff val y = height - (ratio * height) return@createPath y } drawPath( path = path, color = Power.CURRENT.color, style = Stroke(width = GraphUtil.RADIUS, cap = StrokeCap.Round), ) } } + ModifierReused:PowerMetrics.kt$Canvas(modifier = modifier.width(dp)) { val width = size.width val height = size.height /* Voltage */ var index = 0 while (index < telemetries.size) { val path = Path() index = createPath( telemetries = telemetries, index = index, path = path, oldestTime = oldest.time, timeRange = timeDiff, width = width, timeThreshold = selectedTime.timeThreshold(), ) { i -> val telemetry = telemetries.getOrNull(i) ?: telemetries.last() val ratio = (retrieveVoltage(selectedChannel, telemetry) - voltageMin) / voltageDiff val y = height - (ratio * height) return@createPath y } drawPath( path = path, color = VOLTAGE_COLOR, style = Stroke(width = GraphUtil.RADIUS, cap = StrokeCap.Round), ) } /* Current */ index = 0 while (index < telemetries.size) { val path = Path() index = createPath( telemetries = telemetries, index = index, path = path, oldestTime = oldest.time, timeRange = timeDiff, width = width, timeThreshold = selectedTime.timeThreshold(), ) { i -> val telemetry = telemetries.getOrNull(i) ?: telemetries.last() val ratio = (retrieveCurrent(selectedChannel, telemetry) - Power.CURRENT.min) / currentDiff val y = height - (ratio * height) return@createPath y } drawPath( path = path, color = Power.CURRENT.color, style = Stroke(width = GraphUtil.RADIUS, cap = StrokeCap.Round), ) } } ModifierReused:PowerMetrics.kt$HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { graphColor }) ModifierReused:PowerMetrics.kt$TimeAxisOverlay(modifier.width(dp), oldest = oldest.time, newest = newest.time, selectedTime.lineInterval()) ModifierReused:PowerMetrics.kt$YAxisLabels( modifier = modifier.weight(weight = Y_AXIS_WEIGHT), Power.CURRENT.color, minValue = Power.CURRENT.min, maxValue = Power.CURRENT.max, ) @@ -247,8 +231,8 @@ MultipleEmitters:CommonCharts.kt$LegendLabel MultipleEmitters:DeviceMetrics.kt$DeviceMetricsChart MultipleEmitters:EnvironmentCharts.kt$EnvironmentMetricsChart - MultipleEmitters:NodeDetail.kt$EncryptionErrorContent - MultipleEmitters:NodeDetail.kt$MetricsSection + MultipleEmitters:NodeDetailScreen.kt$EncryptionErrorContent + MultipleEmitters:NodeDetailScreen.kt$MetricsSection MultipleEmitters:PaxMetrics.kt$PaxMetricsChart MultipleEmitters:PowerMetrics.kt$PowerMetricsChart MultipleEmitters:RadioConfig.kt$RadioConfigItemList @@ -299,28 +283,15 @@ ParameterNaming:MapReportingPreference.kt$onPublishIntervalSecsChanged ParameterNaming:MapReportingPreference.kt$onShouldReportLocationChanged ParameterNaming:MessageList.kt$onUnreadChanged - ParameterNaming:NodeDetail.kt$onFirmwareSelected - ParameterNaming:NodeFilterTextField.kt$onToggleShowIgnored + ParameterNaming:NodeDetailScreen.kt$onFirmwareSelected ParameterNaming:PositionPrecisionPreference.kt$onValueChanged ParameterNaming:UsbDevices.kt$onDeviceSelected ParameterNaming:WelcomeScreen.kt$onGetStarted - PreviewAnnotationNaming:LargeFontPreview.kt$LargeFontPreview$LargeFontPreview PreviewPublic:Channel.kt$ModemPresetInfoPreview - PreviewPublic:ElevationInfo.kt$ElevationInfoPreview PreviewPublic:EmptyStateContent.kt$EmptyStateContentPreview - PreviewPublic:LastHeardInfo.kt$LastHeardInfoPreview - PreviewPublic:LinkedCoordinates.kt$LinkedCoordinatesPreview PreviewPublic:MapReportingPreference.kt$MapReportingPreview - PreviewPublic:NodeChip.kt$NodeChipPreview - PreviewPublic:NodeItem.kt$NodeInfoPreview - PreviewPublic:NodeItem.kt$NodeInfoSimplePreview - PreviewPublic:NodeStatusIcons.kt$StatusIconsPreview PreviewPublic:Reaction.kt$ReactionItemPreview PreviewPublic:Reaction.kt$ReactionRowPreview - PreviewPublic:SatelliteCountInfo.kt$SatelliteCountInfoPreview - PreviewPublic:SignalInfo.kt$SignalInfoPreview - PreviewPublic:SignalInfo.kt$SignalInfoSelfPreview - PreviewPublic:SignalInfo.kt$SignalInfoSimplePreview RethrowCaughtException:SyncContinuation.kt$Continuation$throw ex ReturnCount:RadioConfigViewModel.kt$RadioConfigViewModel$private fun processPacketResponse(packet: MeshProtos.MeshPacket) SwallowedException:BluetoothInterface.kt$BluetoothInterface$ex: CancellationException @@ -339,7 +310,7 @@ TooGenericExceptionCaught:LocationRepository.kt$LocationRepository$e: Exception TooGenericExceptionCaught:MQTTRepository.kt$MQTTRepository$ex: Exception TooGenericExceptionCaught:MeshService.kt$MeshService$ex: Exception - TooGenericExceptionCaught:MeshService.kt$MeshService.<no name provided>$ex: Exception + TooGenericExceptionCaught:MeshService.kt$MeshService.<no name provided>$ex: Exception TooGenericExceptionCaught:MeshServiceStarter.kt$ServiceStarter$ex: Exception TooGenericExceptionCaught:RadioConfigViewModel.kt$RadioConfigViewModel$ex: Exception TooGenericExceptionCaught:SafeBluetooth.kt$SafeBluetooth$ex: Exception @@ -347,29 +318,28 @@ TooGenericExceptionCaught:SyncContinuation.kt$Continuation$ex: Throwable TooGenericExceptionCaught:TCPInterface.kt$TCPInterface$ex: Throwable TooGenericExceptionThrown:MeshService.kt$MeshService$throw Exception("Can't set user without a NodeInfo") - TooGenericExceptionThrown:MeshService.kt$MeshService.<no name provided>$throw Exception("Port numbers must be non-zero!") + TooGenericExceptionThrown:MeshService.kt$MeshService.<no name provided>$throw Exception("Port numbers must be non-zero!") TooGenericExceptionThrown:ServiceClient.kt$ServiceClient$throw Exception("Haven't called connect") TooGenericExceptionThrown:ServiceClient.kt$ServiceClient$throw Exception("Service not bound") TooGenericExceptionThrown:SyncContinuation.kt$SyncContinuation$throw Exception("SyncContinuation timeout") TooGenericExceptionThrown:SyncContinuation.kt$SyncContinuation$throw Exception("This shouldn't happen") TooManyFunctions:BluetoothInterface.kt$BluetoothInterface : IRadioInterface TooManyFunctions:MeshService.kt$MeshService : Service - TooManyFunctions:MeshService.kt$MeshService$<no name provided> : Stub + TooManyFunctions:MeshService.kt$MeshService$<no name provided> : Stub TooManyFunctions:MessageViewModel.kt$MessageViewModel : ViewModel - TooManyFunctions:NodeDetail.kt$com.geeksville.mesh.ui.node.NodeDetail.kt - TooManyFunctions:NodesViewModel.kt$NodesViewModel : ViewModel + TooManyFunctions:NodeDetailScreen.kt$com.geeksville.mesh.ui.node.NodeDetailScreen.kt TooManyFunctions:RadioConfigViewModel.kt$RadioConfigViewModel : ViewModel TooManyFunctions:RadioInterfaceService.kt$RadioInterfaceService TooManyFunctions:SafeBluetooth.kt$SafeBluetooth : Closeable TooManyFunctions:UIState.kt$UIViewModel : ViewModel TopLevelPropertyNaming:Constants.kt$const val prefix = "com.geeksville.mesh" - UnusedParameter:ChannelSettingsItemList.kt$onBack: () -> Unit + UnusedParameter:ChannelSettingsItemList.kt$onBack: () -> Unit UnusedParameter:ChannelSettingsItemList.kt$title: String UnusedParameter:DropDownPreference.kt$modifier: Modifier = Modifier UtilityClassWithPublicConstructor:NetworkRepositoryModule.kt$NetworkRepositoryModule ViewModelForwarding:Main.kt$ScannedQrCodeDialog(uIViewModel, newChannelSet) ViewModelForwarding:Main.kt$VersionChecks(uIViewModel) ViewModelInjection:DebugSearch.kt$viewModel - Wrapping:Message.kt${ event -> when (event) { is MessageScreenEvent.SendMessage -> { viewModel.sendMessage(event.text, contactKey, event.replyingToPacketId) if (event.replyingToPacketId != null) replyingToPacketId = null messageInputState.clearText() } is MessageScreenEvent.SendReaction -> viewModel.sendReaction(event.emoji, event.messageId, contactKey) is MessageScreenEvent.DeleteMessages -> { viewModel.deleteMessages(event.ids) selectedMessageIds.value = emptySet() showDeleteDialog = false } is MessageScreenEvent.ClearUnreadCount -> viewModel.clearUnreadCount(contactKey, event.lastReadMessageId) is MessageScreenEvent.NodeDetails -> navigateToNodeDetails(event.node.num) is MessageScreenEvent.SetTitle -> viewModel.setTitle(event.title) is MessageScreenEvent.NavigateToMessages -> navigateToMessages(event.contactKey) is MessageScreenEvent.NavigateToNodeDetails -> navigateToNodeDetails(event.nodeNum) MessageScreenEvent.NavigateBack -> onNavigateBack() is MessageScreenEvent.CopyToClipboard -> { clipboardManager.nativeClipboard.setPrimaryClip(ClipData.newPlainText(event.text, event.text)) selectedMessageIds.value = emptySet() } } } + Wrapping:Message.kt${ event -> when (event) { is MessageScreenEvent.SendMessage -> { viewModel.sendMessage(event.text, contactKey, event.replyingToPacketId) if (event.replyingToPacketId != null) replyingToPacketId = null messageInputState.clearText() } is MessageScreenEvent.SendReaction -> viewModel.sendReaction(event.emoji, event.messageId, contactKey) is MessageScreenEvent.DeleteMessages -> { viewModel.deleteMessages(event.ids) selectedMessageIds.value = emptySet() showDeleteDialog = false } is MessageScreenEvent.ClearUnreadCount -> viewModel.clearUnreadCount(contactKey, event.lastReadMessageId) is MessageScreenEvent.NodeDetails -> navigateToNodeDetails(event.node.num) is MessageScreenEvent.SetTitle -> viewModel.setTitle(event.title) is MessageScreenEvent.NavigateToMessages -> navigateToMessages(event.contactKey) is MessageScreenEvent.NavigateToNodeDetails -> navigateToNodeDetails(event.nodeNum) MessageScreenEvent.NavigateBack -> onNavigateBack() is MessageScreenEvent.CopyToClipboard -> { clipboardManager.nativeClipboard.setPrimaryClip(ClipData.newPlainText(event.text, event.text)) selectedMessageIds.value = emptySet() } } } diff --git a/app/src/androidTest/java/com/geeksville/mesh/compose/MessageItemTest.kt b/app/src/androidTest/java/com/geeksville/mesh/compose/MessageItemTest.kt index 1d1a46336..f9938dcd2 100644 --- a/app/src/androidTest/java/com/geeksville/mesh/compose/MessageItemTest.kt +++ b/app/src/androidTest/java/com/geeksville/mesh/compose/MessageItemTest.kt @@ -21,13 +21,13 @@ import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithContentDescription import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider import com.geeksville.mesh.ui.message.components.MessageItem import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.meshtastic.core.database.model.Message import org.meshtastic.core.model.MessageStatus +import org.meshtastic.core.ui.component.preview.NodePreviewParameterProvider @RunWith(AndroidJUnit4::class) class MessageItemTest { diff --git a/app/src/google/java/com/geeksville/mesh/ui/map/MapView.kt b/app/src/google/java/com/geeksville/mesh/ui/map/MapView.kt index d777ef6d6..d8ad936e8 100644 --- a/app/src/google/java/com/geeksville/mesh/ui/map/MapView.kt +++ b/app/src/google/java/com/geeksville/mesh/ui/map/MapView.kt @@ -74,7 +74,6 @@ import com.geeksville.mesh.ui.map.components.WaypointMarkers import com.geeksville.mesh.ui.metrics.HEADING_DEG import com.geeksville.mesh.ui.metrics.formatPositionTime import com.geeksville.mesh.ui.node.DEG_D -import com.geeksville.mesh.ui.node.components.NodeChip import com.geeksville.mesh.waypoint import com.google.android.gms.location.LocationCallback import com.google.android.gms.location.LocationRequest @@ -112,6 +111,7 @@ import org.meshtastic.core.model.util.mpsToKmph import org.meshtastic.core.model.util.mpsToMph import org.meshtastic.core.model.util.toString import org.meshtastic.core.strings.R +import org.meshtastic.core.ui.component.NodeChip import org.meshtastic.feature.map.LastHeardFilter import org.meshtastic.feature.map.LayerType import org.meshtastic.feature.map.LocationPermissionsHandler diff --git a/app/src/google/java/com/geeksville/mesh/ui/map/components/ClusterItemsListDialog.kt b/app/src/google/java/com/geeksville/mesh/ui/map/components/ClusterItemsListDialog.kt index 93b4092d7..6b87b1ed2 100644 --- a/app/src/google/java/com/geeksville/mesh/ui/map/components/ClusterItemsListDialog.kt +++ b/app/src/google/java/com/geeksville/mesh/ui/map/components/ClusterItemsListDialog.kt @@ -32,8 +32,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.geeksville.mesh.ui.map.NodeClusterItem -import com.geeksville.mesh.ui.node.components.NodeChip import org.meshtastic.core.strings.R +import org.meshtastic.core.ui.component.NodeChip @Composable fun ClusterItemsListDialog( diff --git a/app/src/google/java/com/geeksville/mesh/ui/map/components/NodeClusterMarkers.kt b/app/src/google/java/com/geeksville/mesh/ui/map/components/NodeClusterMarkers.kt index 9bca72a27..f9eb7136f 100644 --- a/app/src/google/java/com/geeksville/mesh/ui/map/components/NodeClusterMarkers.kt +++ b/app/src/google/java/com/geeksville/mesh/ui/map/components/NodeClusterMarkers.kt @@ -21,12 +21,12 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.key import androidx.compose.ui.graphics.Color import com.geeksville.mesh.ui.map.NodeClusterItem -import com.geeksville.mesh.ui.node.components.NodeChip import com.google.maps.android.clustering.Cluster import com.google.maps.android.clustering.view.DefaultClusterRenderer import com.google.maps.android.compose.Circle import com.google.maps.android.compose.MapsComposeExperimentalApi import com.google.maps.android.compose.clustering.Clustering +import org.meshtastic.core.ui.component.NodeChip import org.meshtastic.feature.map.BaseMapViewModel @OptIn(MapsComposeExperimentalApi::class) diff --git a/app/src/main/java/com/geeksville/mesh/navigation/NodesNavigation.kt b/app/src/main/java/com/geeksville/mesh/navigation/NodesNavigation.kt index b05be2265..c5a649617 100644 --- a/app/src/main/java/com/geeksville/mesh/navigation/NodesNavigation.kt +++ b/app/src/main/java/com/geeksville/mesh/navigation/NodesNavigation.kt @@ -50,8 +50,8 @@ import com.geeksville.mesh.ui.metrics.PowerMetricsScreen import com.geeksville.mesh.ui.metrics.SignalMetricsScreen import com.geeksville.mesh.ui.metrics.TracerouteLogScreen import com.geeksville.mesh.ui.node.NodeDetailScreen +import com.geeksville.mesh.ui.node.NodeListScreen import com.geeksville.mesh.ui.node.NodeMapScreen -import com.geeksville.mesh.ui.node.NodeScreen import org.meshtastic.core.navigation.ContactsRoutes import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI import org.meshtastic.core.navigation.NodeDetailRoutes @@ -64,7 +64,7 @@ fun NavGraphBuilder.nodesGraph(navController: NavHostController, uiViewModel: UI composable( deepLinks = listOf(navDeepLink(basePath = "$DEEP_LINK_BASE_URI/nodes")), ) { - NodeScreen(navigateToNodeDetails = { navController.navigate(NodesRoutes.NodeDetailGraph(it)) }) + NodeListScreen(navigateToNodeDetails = { navController.navigate(NodesRoutes.NodeDetailGraph(it)) }) } nodeDetailGraph(navController, uiViewModel) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/common/components/MainAppBar.kt b/app/src/main/java/com/geeksville/mesh/ui/common/components/MainAppBar.kt index 5c0a094a6..db01edfeb 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/common/components/MainAppBar.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/common/components/MainAppBar.kt @@ -43,11 +43,11 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavDestination.Companion.hasRoute import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState -import com.geeksville.mesh.ui.node.components.NodeChip import org.meshtastic.core.database.model.Node import org.meshtastic.core.navigation.ContactsRoutes import org.meshtastic.core.navigation.SettingsRoutes import org.meshtastic.core.strings.R +import org.meshtastic.core.ui.component.NodeChip import org.meshtastic.core.ui.theme.AppTheme @Suppress("CyclomaticComplexMethod") diff --git a/app/src/main/java/com/geeksville/mesh/ui/connections/ConnectionsScreen.kt b/app/src/main/java/com/geeksville/mesh/ui/connections/ConnectionsScreen.kt index 6d14e3b2b..28f776736 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/connections/ConnectionsScreen.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/connections/ConnectionsScreen.kt @@ -70,7 +70,6 @@ import com.geeksville.mesh.ui.connections.components.ConnectionsSegmentedBar import com.geeksville.mesh.ui.connections.components.CurrentlyConnectedInfo import com.geeksville.mesh.ui.connections.components.NetworkDevices import com.geeksville.mesh.ui.connections.components.UsbDevices -import com.geeksville.mesh.ui.settings.components.SettingsItem import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel import com.geeksville.mesh.ui.settings.radio.components.PacketResponseStateDialog import com.google.accompanist.permissions.ExperimentalPermissionsApi @@ -79,6 +78,7 @@ import org.meshtastic.core.navigation.Route import org.meshtastic.core.navigation.SettingsRoutes import org.meshtastic.core.service.ConnectionState import org.meshtastic.core.strings.R +import org.meshtastic.core.ui.component.SettingsItem import org.meshtastic.core.ui.component.TitledCard fun String?.isIPAddress(): Boolean = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { diff --git a/app/src/main/java/com/geeksville/mesh/ui/connections/components/CurrentlyConnectedInfo.kt b/app/src/main/java/com/geeksville/mesh/ui/connections/components/CurrentlyConnectedInfo.kt index 7efa867e2..abec83eef 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/connections/components/CurrentlyConnectedInfo.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/connections/components/CurrentlyConnectedInfo.kt @@ -39,11 +39,11 @@ import androidx.compose.ui.unit.dp import com.geeksville.mesh.MeshProtos import com.geeksville.mesh.PaxcountProtos import com.geeksville.mesh.TelemetryProtos -import com.geeksville.mesh.ui.node.components.NodeChip import org.meshtastic.core.database.model.Node import org.meshtastic.core.strings.R import org.meshtastic.core.ui.component.MaterialBatteryInfo import org.meshtastic.core.ui.component.MaterialBluetoothSignalInfo +import org.meshtastic.core.ui.component.NodeChip import org.meshtastic.core.ui.theme.AppTheme import org.meshtastic.core.ui.theme.StatusColors.StatusRed diff --git a/app/src/main/java/com/geeksville/mesh/ui/message/Message.kt b/app/src/main/java/com/geeksville/mesh/ui/message/Message.kt index c7cc300d1..116b36606 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/message/Message.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/message/Message.kt @@ -96,7 +96,6 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.geeksville.mesh.AppOnlyProtos import com.geeksville.mesh.ui.common.components.SecurityIcon -import com.geeksville.mesh.ui.node.components.NodeKeyStatusIcon import com.geeksville.mesh.ui.sharing.SharedContactDialog import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -107,6 +106,7 @@ import org.meshtastic.core.model.DataPacket import org.meshtastic.core.model.util.getChannel import org.meshtastic.core.strings.R import org.meshtastic.core.ui.theme.AppTheme +import org.meshtastic.feature.node.component.NodeKeyStatusIcon import java.nio.charset.StandardCharsets private const val MESSAGE_CHARACTER_LIMIT_BYTES = 200 diff --git a/app/src/main/java/com/geeksville/mesh/ui/message/components/MessageItem.kt b/app/src/main/java/com/geeksville/mesh/ui/message/components/MessageItem.kt index adcd14593..e02b0b463 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/message/components/MessageItem.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/message/components/MessageItem.kt @@ -49,16 +49,16 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp -import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider -import com.geeksville.mesh.ui.node.components.NodeChip import org.meshtastic.core.database.entity.Reaction import org.meshtastic.core.database.model.Message import org.meshtastic.core.database.model.Node import org.meshtastic.core.model.MessageStatus import org.meshtastic.core.strings.R import org.meshtastic.core.ui.component.MDText +import org.meshtastic.core.ui.component.NodeChip import org.meshtastic.core.ui.component.Rssi import org.meshtastic.core.ui.component.Snr +import org.meshtastic.core.ui.component.preview.NodePreviewParameterProvider import org.meshtastic.core.ui.theme.AppTheme import org.meshtastic.core.ui.theme.MessageItemColors diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/NodeDetail.kt b/app/src/main/java/com/geeksville/mesh/ui/node/NodeDetailScreen.kt similarity index 98% rename from app/src/main/java/com/geeksville/mesh/ui/node/NodeDetail.kt rename to app/src/main/java/com/geeksville/mesh/ui/node/NodeDetailScreen.kt index e13fd660d..927c518de 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/NodeDetail.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/node/NodeDetailScreen.kt @@ -134,13 +134,6 @@ import com.geeksville.mesh.MeshProtos import com.geeksville.mesh.model.MetricsState import com.geeksville.mesh.model.MetricsViewModel import com.geeksville.mesh.ui.common.components.MainAppBar -import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider -import com.geeksville.mesh.ui.node.components.NodeActionDialogs -import com.geeksville.mesh.ui.node.components.NodeMenuAction -import com.geeksville.mesh.ui.node.components.TracerouteButton -import com.geeksville.mesh.ui.settings.components.SettingsItem -import com.geeksville.mesh.ui.settings.components.SettingsItemDetail -import com.geeksville.mesh.ui.settings.components.SettingsItemSwitch import com.geeksville.mesh.ui.sharing.SharedContactDialog import com.geeksville.mesh.util.thenIf import com.mikepenz.markdown.m3.Markdown @@ -163,12 +156,20 @@ import org.meshtastic.core.navigation.Route import org.meshtastic.core.navigation.SettingsRoutes import org.meshtastic.core.service.ServiceAction import org.meshtastic.core.strings.R +import org.meshtastic.core.ui.component.SettingsItem +import org.meshtastic.core.ui.component.SettingsItemDetail +import org.meshtastic.core.ui.component.SettingsItemSwitch import org.meshtastic.core.ui.component.TitledCard +import org.meshtastic.core.ui.component.preview.NodePreviewParameterProvider import org.meshtastic.core.ui.theme.AppTheme import org.meshtastic.core.ui.theme.StatusColors.StatusGreen import org.meshtastic.core.ui.theme.StatusColors.StatusOrange import org.meshtastic.core.ui.theme.StatusColors.StatusRed import org.meshtastic.core.ui.theme.StatusColors.StatusYellow +import org.meshtastic.feature.node.component.NodeActionDialogs +import org.meshtastic.feature.node.component.NodeMenuAction +import org.meshtastic.feature.node.component.TracerouteButton +import org.meshtastic.feature.node.detail.NodeDetailViewModel import timber.log.Timber private data class VectorMetricInfo( diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/NodeScreen.kt b/app/src/main/java/com/geeksville/mesh/ui/node/NodeListScreen.kt similarity index 85% rename from app/src/main/java/com/geeksville/mesh/ui/node/NodeScreen.kt rename to app/src/main/java/com/geeksville/mesh/ui/node/NodeListScreen.kt index 7d194b141..f56db1653 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/NodeScreen.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/node/NodeListScreen.kt @@ -59,9 +59,6 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.geeksville.mesh.AdminProtos import com.geeksville.mesh.ui.common.components.MainAppBar -import com.geeksville.mesh.ui.node.components.NodeActionDialogs -import com.geeksville.mesh.ui.node.components.NodeFilterTextField -import com.geeksville.mesh.ui.node.components.NodeItem import com.geeksville.mesh.ui.sharing.AddContactFAB import com.geeksville.mesh.ui.sharing.supportsQrCodeSharing import org.meshtastic.core.database.model.Node @@ -70,24 +67,28 @@ import org.meshtastic.core.service.ConnectionState import org.meshtastic.core.strings.R import org.meshtastic.core.ui.component.rememberTimeTickWithLifecycle import org.meshtastic.core.ui.theme.StatusColors.StatusRed +import org.meshtastic.feature.node.component.NodeActionDialogs +import org.meshtastic.feature.node.component.NodeFilterTextField +import org.meshtastic.feature.node.component.NodeItem +import org.meshtastic.feature.node.list.NodeListViewModel @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Suppress("LongMethod", "CyclomaticComplexMethod") @Composable -fun NodeScreen(nodesViewModel: NodesViewModel = hiltViewModel(), navigateToNodeDetails: (Int) -> Unit) { - val state by nodesViewModel.nodesUiState.collectAsStateWithLifecycle() +fun NodeListScreen(viewModel: NodeListViewModel = hiltViewModel(), navigateToNodeDetails: (Int) -> Unit) { + val state by viewModel.nodesUiState.collectAsStateWithLifecycle() - val nodes by nodesViewModel.nodeList.collectAsStateWithLifecycle() - val ourNode by nodesViewModel.ourNodeInfo.collectAsStateWithLifecycle() - val onlineNodeCount by nodesViewModel.onlineNodeCount.collectAsStateWithLifecycle(0) - val totalNodeCount by nodesViewModel.totalNodeCount.collectAsStateWithLifecycle(0) - val unfilteredNodes by nodesViewModel.unfilteredNodeList.collectAsStateWithLifecycle() + val nodes by viewModel.nodeList.collectAsStateWithLifecycle() + val ourNode by viewModel.ourNodeInfo.collectAsStateWithLifecycle() + val onlineNodeCount by viewModel.onlineNodeCount.collectAsStateWithLifecycle(0) + val totalNodeCount by viewModel.totalNodeCount.collectAsStateWithLifecycle(0) + val unfilteredNodes by viewModel.unfilteredNodeList.collectAsStateWithLifecycle() val ignoredNodeCount = unfilteredNodes.count { it.isIgnored } val listState = rememberLazyListState() val currentTimeMillis = rememberTimeTickWithLifecycle() - val connectionState by nodesViewModel.connectionState.collectAsStateWithLifecycle() + val connectionState by viewModel.connectionState.collectAsStateWithLifecycle() val isScrollInProgress by remember { derivedStateOf { listState.isScrollInProgress && (listState.canScrollForward || listState.canScrollBackward) } @@ -109,7 +110,7 @@ fun NodeScreen(nodesViewModel: NodesViewModel = hiltViewModel(), navigateToNodeD val firmwareVersion = DeviceVersion(ourNode?.metadata?.firmwareVersion ?: "0.0.0") val shareCapable = firmwareVersion.supportsQrCodeSharing() val scannedContact: AdminProtos.SharedContact? by - nodesViewModel.sharedContactRequested.collectAsStateWithLifecycle(null) + viewModel.sharedContactRequested.collectAsStateWithLifecycle(null) AddContactFAB( unfilteredNodes = unfilteredNodes, scannedContact = scannedContact, @@ -118,8 +119,8 @@ fun NodeScreen(nodesViewModel: NodesViewModel = hiltViewModel(), navigateToNodeD visible = !isScrollInProgress && connectionState == ConnectionState.CONNECTED && shareCapable, alignment = Alignment.BottomEnd, ), - onSharedContactImport = { contact -> nodesViewModel.addSharedContact(contact) }, - onSharedContactRequested = { contact -> nodesViewModel.setSharedContactRequested(contact) }, + onSharedContactImport = { contact -> viewModel.addSharedContact(contact) }, + onSharedContactRequested = { contact -> viewModel.setSharedContactRequested(contact) }, ) }, ) { contentPadding -> @@ -135,17 +136,17 @@ fun NodeScreen(nodesViewModel: NodesViewModel = hiltViewModel(), navigateToNodeD .background(MaterialTheme.colorScheme.surfaceDim) .padding(8.dp), filterText = state.filter.filterText, - onTextChange = nodesViewModel::setNodeFilterText, + onTextChange = viewModel::setNodeFilterText, currentSortOption = state.sort, - onSortSelect = nodesViewModel::setSortOption, + onSortSelect = viewModel::setSortOption, includeUnknown = state.filter.includeUnknown, - onToggleIncludeUnknown = nodesViewModel::toggleIncludeUnknown, + onToggleIncludeUnknown = viewModel::toggleIncludeUnknown, onlyOnline = state.filter.onlyOnline, - onToggleOnlyOnline = nodesViewModel::toggleOnlyOnline, + onToggleOnlyOnline = viewModel::toggleOnlyOnline, onlyDirect = state.filter.onlyDirect, - onToggleOnlyDirect = nodesViewModel::toggleOnlyDirect, + onToggleOnlyDirect = viewModel::toggleOnlyDirect, showIgnored = state.filter.showIgnored, - onToggleShowIgnored = nodesViewModel::toggleShowIgnored, + onToggleShowIgnored = viewModel::toggleShowIgnored, ignoredNodeCount = ignoredNodeCount, ) } @@ -165,9 +166,9 @@ fun NodeScreen(nodesViewModel: NodesViewModel = hiltViewModel(), navigateToNodeD displayIgnoreDialog = false displayRemoveDialog = false }, - onConfirmFavorite = nodesViewModel::favoriteNode, - onConfirmIgnore = nodesViewModel::ignoreNode, - onConfirmRemove = { nodesViewModel.removeNode(it.num) }, + onConfirmFavorite = viewModel::favoriteNode, + onConfirmIgnore = viewModel::ignoreNode, + onConfirmRemove = { viewModel.removeNode(it.num) }, ) var expanded by remember { mutableStateOf(false) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/settings/SettingsScreen.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/SettingsScreen.kt index 22316c9b8..b70bf00d7 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/SettingsScreen.kt @@ -60,9 +60,6 @@ import com.geeksville.mesh.ClientOnlyProtos.DeviceProfile import com.geeksville.mesh.android.gpsDisabled import com.geeksville.mesh.navigation.getNavRouteFrom import com.geeksville.mesh.ui.common.components.MainAppBar -import com.geeksville.mesh.ui.settings.components.SettingsItem -import com.geeksville.mesh.ui.settings.components.SettingsItemDetail -import com.geeksville.mesh.ui.settings.components.SettingsItemSwitch import com.geeksville.mesh.ui.settings.radio.RadioConfigItemList import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel import com.geeksville.mesh.ui.settings.radio.components.EditDeviceProfileDialog @@ -75,6 +72,9 @@ import kotlinx.coroutines.delay import org.meshtastic.core.navigation.Route import org.meshtastic.core.strings.R import org.meshtastic.core.ui.component.MultipleChoiceAlertDialog +import org.meshtastic.core.ui.component.SettingsItem +import org.meshtastic.core.ui.component.SettingsItemDetail +import org.meshtastic.core.ui.component.SettingsItemSwitch import org.meshtastic.core.ui.component.TitledCard import org.meshtastic.core.ui.theme.MODE_DYNAMIC import java.text.SimpleDateFormat diff --git a/app/src/main/java/com/geeksville/mesh/ui/settings/radio/CleanNodeDatabaseScreen.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/CleanNodeDatabaseScreen.kt index 64dc57abc..a6423c681 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/settings/radio/CleanNodeDatabaseScreen.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/CleanNodeDatabaseScreen.kt @@ -46,9 +46,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import com.geeksville.mesh.ui.node.components.NodeChip import org.meshtastic.core.database.entity.NodeEntity import org.meshtastic.core.strings.R +import org.meshtastic.core.ui.component.NodeChip /** * Composable screen for cleaning the node database. Allows users to specify criteria for deleting nodes. The list of diff --git a/app/src/main/java/com/geeksville/mesh/ui/settings/radio/RadioConfig.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/RadioConfig.kt index 9f2f88cb8..1a63250c2 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/settings/radio/RadioConfig.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/RadioConfig.kt @@ -44,11 +44,11 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.geeksville.mesh.navigation.ConfigRoute import com.geeksville.mesh.navigation.ModuleRoute -import com.geeksville.mesh.ui.settings.components.SettingsItem import com.geeksville.mesh.ui.settings.radio.components.WarningDialog import org.meshtastic.core.navigation.Route import org.meshtastic.core.navigation.SettingsRoutes import org.meshtastic.core.strings.R +import org.meshtastic.core.ui.component.SettingsItem import org.meshtastic.core.ui.component.TitledCard import org.meshtastic.core.ui.theme.AppTheme import org.meshtastic.core.ui.theme.StatusColors.StatusRed diff --git a/build.gradle.kts b/build.gradle.kts index 0e7c45a87..b41d5377d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -75,4 +75,5 @@ dependencies { kover(projects.core.network) kover(projects.core.prefs) kover(projects.feature.map) + kover(projects.feature.node) } \ No newline at end of file diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index a8c2c92ad..450bdd9e7 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -23,6 +23,9 @@ plugins { android { namespace = "org.meshtastic.core.ui" } dependencies { + implementation(projects.core.database) + implementation(projects.core.model) + implementation(projects.core.proto) implementation(projects.core.strings) implementation(libs.bundles.markdown) } diff --git a/core/ui/detekt-baseline.xml b/core/ui/detekt-baseline.xml index 102a440de..4f2b259f6 100644 --- a/core/ui/detekt-baseline.xml +++ b/core/ui/detekt-baseline.xml @@ -6,6 +6,9 @@ ComposableParamOrder:BatteryInfo.kt$BatteryInfo ComposableParamOrder:EditTextPreference.kt$EditTextPreference ComposableParamOrder:MaterialBatteryInfo.kt$MaterialBatteryInfo + ComposableParamOrder:NodeChip.kt$NodeChip + ComposableParamOrder:SettingsItem.kt$SettingsItem + ComposableParamOrder:SignalInfo.kt$SignalInfo ComposableParamOrder:SwitchPreference.kt$SwitchPreference ContentSlotReused:AdaptiveTwoPane.kt$second LongMethod:EditTextPreference.kt$@Composable fun EditTextPreference( title: String, value: String, enabled: Boolean, isError: Boolean, keyboardOptions: KeyboardOptions, keyboardActions: KeyboardActions, onValueChanged: (String) -> Unit, modifier: Modifier = Modifier, summary: String? = null, maxSize: Int = 0, // max_size - 1 (in bytes) onFocusChanged: (FocusState) -> Unit = {}, trailingIcon: (@Composable () -> Unit)? = null, visualTransformation: VisualTransformation = VisualTransformation.None, ) @@ -30,8 +33,12 @@ ModifierMissing:LoraSignalIndicator.kt$Rssi ModifierMissing:LoraSignalIndicator.kt$Snr ModifierMissing:LoraSignalIndicator.kt$SnrAndRssi + ModifierMissing:SettingsItem.kt$SettingsItem + ModifierMissing:SettingsItem.kt$SettingsItemDetail + ModifierMissing:SettingsItem.kt$SettingsItemSwitch ModifierMissing:SimpleAlertDialog.kt$SimpleAlertDialog ModifierMissing:SlidingSelector.kt$OptionLabel + ModifierNotUsedAtRoot:SignalInfo.kt$modifier = modifier ModifierNotUsedAtRoot:TextDividerPreference.kt$modifier = modifier.fillMaxWidth().padding(all = 16.dp) ModifierNotUsedAtRoot:TextDividerPreference.kt$modifier = modifier.fillMaxWidth().wrapContentWidth(Alignment.End) ModifierReused:PreferenceCategory.kt$Card(modifier = modifier.padding(bottom = 8.dp)) { Column( modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 16.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { ProvideTextStyle(MaterialTheme.typography.bodyLarge) { content() } } } @@ -52,5 +59,8 @@ PreviewPublic:IndoorAirQuality.kt$IAQScalePreview PreviewPublic:LazyColumnDragAndDropDemo.kt$LazyColumnDragAndDropDemo PreviewPublic:MaterialBatteryInfo.kt$MaterialBatteryInfoPreview + PreviewPublic:SignalInfo.kt$SignalInfoPreview + PreviewPublic:SignalInfo.kt$SignalInfoSelfPreview + PreviewPublic:SignalInfo.kt$SignalInfoSimplePreview diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeChip.kt b/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/NodeChip.kt similarity index 98% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/NodeChip.kt rename to core/ui/src/main/kotlin/org/meshtastic/core/ui/component/NodeChip.kt index fa826f3bf..0b530c6e4 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeChip.kt +++ b/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/NodeChip.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.core.ui.component import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.IntrinsicSize @@ -79,7 +79,7 @@ fun NodeChip(modifier: Modifier = Modifier, node: Node, onClick: ((Node) -> Unit @Suppress("MagicNumber") @Preview @Composable -fun NodeChipPreview() { +private fun NodeChipPreview() { val user = MeshProtos.User.newBuilder().setShortName("\uD83E\uDEE0").setLongName("John Doe").build() val node = Node( diff --git a/app/src/main/java/com/geeksville/mesh/ui/settings/components/SettingsItem.kt b/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/SettingsItem.kt similarity index 99% rename from app/src/main/java/com/geeksville/mesh/ui/settings/components/SettingsItem.kt rename to core/ui/src/main/kotlin/org/meshtastic/core/ui/component/SettingsItem.kt index c9f774ea7..e9db8e4ff 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/settings/components/SettingsItem.kt +++ b/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/SettingsItem.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.settings.components +package org.meshtastic.core.ui.component import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope diff --git a/app/src/main/java/com/geeksville/mesh/ui/common/components/SignalInfo.kt b/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/SignalInfo.kt similarity index 94% rename from app/src/main/java/com/geeksville/mesh/ui/common/components/SignalInfo.kt rename to core/ui/src/main/kotlin/org/meshtastic/core/ui/component/SignalInfo.kt index 7f4223a58..abc1ef132 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/common/components/SignalInfo.kt +++ b/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/SignalInfo.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.common.components +package org.meshtastic.core.ui.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -32,12 +32,9 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider import org.meshtastic.core.database.model.Node import org.meshtastic.core.strings.R -import org.meshtastic.core.ui.component.Rssi -import org.meshtastic.core.ui.component.Snr -import org.meshtastic.core.ui.component.determineSignalQuality +import org.meshtastic.core.ui.component.preview.NodePreviewParameterProvider import org.meshtastic.core.ui.theme.AppTheme const val MAX_VALID_SNR = 100F diff --git a/app/src/main/java/com/geeksville/mesh/ui/common/preview/NodePreviewParameterProvider.kt b/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/preview/NodePreviewParameterProvider.kt similarity index 99% rename from app/src/main/java/com/geeksville/mesh/ui/common/preview/NodePreviewParameterProvider.kt rename to core/ui/src/main/kotlin/org/meshtastic/core/ui/component/preview/NodePreviewParameterProvider.kt index 56f2bb882..e8d8a8064 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/common/preview/NodePreviewParameterProvider.kt +++ b/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/preview/NodePreviewParameterProvider.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.common.preview +package org.meshtastic.core.ui.component.preview import androidx.compose.ui.tooling.preview.PreviewParameterProvider import com.geeksville.mesh.ConfigProtos diff --git a/app/src/main/res/drawable/ic_antenna_24.xml b/core/ui/src/main/res/drawable/ic_antenna_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_antenna_24.xml rename to core/ui/src/main/res/drawable/ic_antenna_24.xml diff --git a/app/src/main/res/drawable/ic_lock_open_right_24.xml b/core/ui/src/main/res/drawable/ic_lock_open_right_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_lock_open_right_24.xml rename to core/ui/src/main/res/drawable/ic_lock_open_right_24.xml diff --git a/app/src/main/java/com/geeksville/mesh/ui/common/preview/LargeFontPreview.kt b/feature/node/build.gradle.kts similarity index 52% rename from app/src/main/java/com/geeksville/mesh/ui/common/preview/LargeFontPreview.kt rename to feature/node/build.gradle.kts index 9ebf6db99..0566d62fa 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/common/preview/LargeFontPreview.kt +++ b/feature/node/build.gradle.kts @@ -15,9 +15,24 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.common.preview +plugins { + alias(libs.plugins.kover) + alias(libs.plugins.meshtastic.android.library) + alias(libs.plugins.meshtastic.android.library.compose) + alias(libs.plugins.meshtastic.hilt) +} -import androidx.compose.ui.tooling.preview.Preview +android { namespace = "org.meshtastic.feature.node" } -@Preview(name = "Large Font", fontScale = 2f) -annotation class LargeFontPreview +dependencies { + implementation(projects.core.data) + implementation(projects.core.database) + implementation(projects.core.datastore) + implementation(projects.core.model) + implementation(projects.core.proto) + implementation(projects.core.service) + implementation(projects.core.strings) + implementation(projects.core.ui) + + implementation(libs.timber) +} diff --git a/feature/node/detekt-baseline.xml b/feature/node/detekt-baseline.xml new file mode 100644 index 000000000..ac9bafa3a --- /dev/null +++ b/feature/node/detekt-baseline.xml @@ -0,0 +1,19 @@ + + + + + ComposableParamOrder:ElevationInfo.kt$ElevationInfo + ComposableParamOrder:LastHeardInfo.kt$LastHeardInfo + ComposableParamOrder:LinkedCoordinates.kt$LinkedCoordinates + ComposableParamOrder:NodeFilterTextField.kt$NodeFilterTextField + ComposableParamOrder:NodeItem.kt$NodeItem + ComposableParamOrder:NodeKeyStatusIcon.kt$NodeKeyStatusIcon + ComposableParamOrder:SatelliteCountInfo.kt$SatelliteCountInfo + ComposableParamOrder:TracerouteButton.kt$TracerouteButton + ModifierMissing:NodeStatusIcons.kt$NodeStatusIcons + ParameterNaming:NodeFilterTextField.kt$onToggleShowIgnored + PreviewPublic:NodeItem.kt$NodeInfoPreview + PreviewPublic:NodeItem.kt$NodeInfoSimplePreview + TooManyFunctions:NodeListViewModel.kt$NodeListViewModel : ViewModel + + diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/DistanceInfo.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/DistanceInfo.kt similarity index 96% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/DistanceInfo.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/DistanceInfo.kt index 8ef68fd94..12dee2d8e 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/DistanceInfo.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/DistanceInfo.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.SocialDistance diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/ElevationInfo.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/ElevationInfo.kt similarity index 95% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/ElevationInfo.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/ElevationInfo.kt index acbb58aff..234ff7faa 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/ElevationInfo.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/ElevationInfo.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -46,6 +46,6 @@ fun ElevationInfo( @Composable @Preview -fun ElevationInfoPreview() { +private fun ElevationInfoPreview() { MaterialTheme { ElevationInfo(altitude = 100, system = DisplayUnits.METRIC, suffix = "ASL") } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/IconInfo.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/IconInfo.kt similarity index 97% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/IconInfo.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/IconInfo.kt index 5d97ba9a9..645ea53e3 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/IconInfo.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/IconInfo.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/LastHeardInfo.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/LastHeardInfo.kt similarity index 93% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/LastHeardInfo.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/LastHeardInfo.kt index d055ca2d5..705e4204a 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/LastHeardInfo.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/LastHeardInfo.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -23,8 +23,8 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.PreviewLightDark -import com.geeksville.mesh.R import org.meshtastic.core.model.util.formatAgo +import org.meshtastic.core.ui.R import org.meshtastic.core.ui.theme.AppTheme @Composable @@ -39,7 +39,7 @@ fun LastHeardInfo(modifier: Modifier = Modifier, lastHeard: Int, currentTimeMill @PreviewLightDark @Composable -fun LastHeardInfoPreview() { +private fun LastHeardInfoPreview() { AppTheme { LastHeardInfo( lastHeard = (System.currentTimeMillis() / 1000).toInt() - 8600, diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/LinkedCoordinates.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/LinkedCoordinates.kt similarity index 98% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/LinkedCoordinates.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/LinkedCoordinates.kt index 9daff5a98..7b03af764 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/LinkedCoordinates.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/LinkedCoordinates.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import android.content.ActivityNotFoundException import android.content.ClipData @@ -113,6 +113,6 @@ private fun handleClick(context: Context, annotatedString: AnnotatedString) { @PreviewLightDark @Composable -fun LinkedCoordinatesPreview() { +private fun LinkedCoordinatesPreview() { AppTheme { LinkedCoordinates(latitude = 37.7749, longitude = -122.4194, nodeName = "Test Node Name") } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeFilterTextField.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeFilterTextField.kt similarity index 97% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/NodeFilterTextField.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeFilterTextField.kt index 4d6752411..8b595811f 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeFilterTextField.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeFilterTextField.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -33,7 +33,6 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Sort import androidx.compose.material.icons.filled.Clear -import androidx.compose.material.icons.filled.Done import androidx.compose.material.icons.filled.Search import androidx.compose.material3.Checkbox import androidx.compose.material3.DropdownMenu @@ -59,9 +58,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp -import com.geeksville.mesh.ui.common.preview.LargeFontPreview import org.meshtastic.core.database.model.NodeSortOption import org.meshtastic.core.strings.R import org.meshtastic.core.ui.theme.AppTheme @@ -119,7 +118,7 @@ fun NodeFilterTextField( style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurface, modifier = Modifier.fillMaxWidth(), - textAlign = androidx.compose.ui.text.style.TextAlign.Center, + textAlign = TextAlign.Center, ) } } @@ -278,7 +277,7 @@ private fun DropdownMenuCheck( } @PreviewLightDark -@LargeFontPreview +@Preview(name = "Large Font", fontScale = 2f) @Composable private fun NodeFilterTextFieldPreview() { AppTheme { diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeItem.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeItem.kt similarity index 97% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/NodeItem.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeItem.kt index 26ba2ab17..254d05635 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeItem.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeItem.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import android.content.res.Configuration import androidx.compose.foundation.combinedClickable @@ -37,7 +37,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -49,13 +48,14 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig -import com.geeksville.mesh.ui.common.components.SignalInfo -import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider import org.meshtastic.core.database.model.Node import org.meshtastic.core.database.model.isUnmessageableRole import org.meshtastic.core.model.util.toDistanceString import org.meshtastic.core.strings.R import org.meshtastic.core.ui.component.MaterialBatteryInfo +import org.meshtastic.core.ui.component.NodeChip +import org.meshtastic.core.ui.component.SignalInfo +import org.meshtastic.core.ui.component.preview.NodePreviewParameterProvider import org.meshtastic.core.ui.theme.AppTheme @OptIn(ExperimentalMaterial3ExpressiveApi::class) diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeKeyStatusIcon.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeKeyStatusIcon.kt similarity index 97% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/NodeKeyStatusIcon.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeKeyStatusIcon.kt index 1b52dd669..d73143585 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeKeyStatusIcon.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeKeyStatusIcon.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import android.util.Base64 import androidx.annotation.StringRes @@ -130,7 +130,7 @@ fun NodeKeyStatusIcon( mismatchKey -> Icons.Default.KeyOff to colorScheme.StatusRed hasPKC -> Icons.Default.Lock to colorScheme.StatusGreen else -> - ImageVector.vectorResource(com.geeksville.mesh.R.drawable.ic_lock_open_right_24) to + ImageVector.vectorResource(org.meshtastic.core.ui.R.drawable.ic_lock_open_right_24) to colorScheme.StatusYellow } diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeMenu.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeMenu.kt similarity index 98% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/NodeMenu.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeMenu.kt index 6f9a98389..ce8a578ed 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeMenu.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeMenu.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeStatusIcons.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeStatusIcons.kt similarity index 98% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/NodeStatusIcons.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeStatusIcons.kt index 82273a9be..e61fd0c22 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeStatusIcons.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/NodeStatusIcons.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding @@ -123,6 +123,6 @@ fun NodeStatusIcons(isThisNode: Boolean, isUnmessageable: Boolean, isFavorite: B @Preview @Composable -fun StatusIconsPreview() { +private fun StatusIconsPreview() { NodeStatusIcons(isThisNode = true, isUnmessageable = true, isFavorite = true, isConnected = false) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/SatelliteCountInfo.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/SatelliteCountInfo.kt similarity index 94% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/SatelliteCountInfo.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/SatelliteCountInfo.kt index 581766036..81d5854f6 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/SatelliteCountInfo.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/SatelliteCountInfo.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import androidx.compose.material.icons.Icons import androidx.compose.material.icons.twotone.SatelliteAlt @@ -37,6 +37,6 @@ fun SatelliteCountInfo(modifier: Modifier = Modifier, satCount: Int) { @PreviewLightDark @Composable -fun SatelliteCountInfoPreview() { +private fun SatelliteCountInfoPreview() { AppTheme { SatelliteCountInfo(satCount = 5) } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/TracerouteButton.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/TracerouteButton.kt similarity index 96% rename from app/src/main/java/com/geeksville/mesh/ui/node/components/TracerouteButton.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/component/TracerouteButton.kt index 0fa4cd49c..76efe380b 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/TracerouteButton.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/component/TracerouteButton.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node.components +package org.meshtastic.feature.node.component import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.tween @@ -34,8 +34,8 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.geeksville.mesh.ui.settings.components.SettingsItem import org.meshtastic.core.strings.R +import org.meshtastic.core.ui.component.SettingsItem import org.meshtastic.core.ui.theme.AppTheme private const val COOL_DOWN_TIME_MS = 30000L diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/NodeDetailViewModel.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/detail/NodeDetailViewModel.kt similarity index 97% rename from app/src/main/java/com/geeksville/mesh/ui/node/NodeDetailViewModel.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/detail/NodeDetailViewModel.kt index 26354439d..6a4b5fada 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/NodeDetailViewModel.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/detail/NodeDetailViewModel.kt @@ -15,12 +15,11 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node +package org.meshtastic.feature.node.detail import android.os.RemoteException import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.geeksville.mesh.ui.node.components.NodeMenuAction import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow @@ -32,6 +31,7 @@ import org.meshtastic.core.database.model.Node import org.meshtastic.core.model.Position import org.meshtastic.core.service.ServiceAction import org.meshtastic.core.service.ServiceRepository +import org.meshtastic.feature.node.component.NodeMenuAction import timber.log.Timber import javax.inject.Inject diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/NodesViewModel.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/list/NodeListViewModel.kt similarity index 99% rename from app/src/main/java/com/geeksville/mesh/ui/node/NodesViewModel.kt rename to feature/node/src/main/kotlin/org/meshtastic/feature/node/list/NodeListViewModel.kt index 5e63de80a..b39226912 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/NodesViewModel.kt +++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/list/NodeListViewModel.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.node +package org.meshtastic.feature.node.list import android.os.RemoteException import androidx.lifecycle.ViewModel @@ -44,7 +44,7 @@ import timber.log.Timber import javax.inject.Inject @HiltViewModel -class NodesViewModel +class NodeListViewModel @Inject constructor( private val nodeRepository: NodeRepository, diff --git a/mesh_service_example/detekt-baseline.xml b/mesh_service_example/detekt-baseline.xml index 61cefa793..ecf2e0cce 100644 --- a/mesh_service_example/detekt-baseline.xml +++ b/mesh_service_example/detekt-baseline.xml @@ -1,37 +1,5 @@ - - ImplicitDefaultLocale:NodeInfo.kt$NodeInfo$String.format("%d%%", batteryLevel) - MagicNumber:DataPacket.kt$DataPacket.CREATOR$16 - MagicNumber:Extensions.kt$1000 - MagicNumber:Extensions.kt$1440000 - MagicNumber:Extensions.kt$24 - MagicNumber:Extensions.kt$2880 - MagicNumber:Extensions.kt$60 - MagicNumber:LocationUtils.kt$1e-7 - MagicNumber:NodeInfo.kt$DeviceMetrics.Companion$1000 - MagicNumber:NodeInfo.kt$EnvironmentMetrics.Companion$1000 - MagicNumber:NodeInfo.kt$NodeInfo$0.114 - MagicNumber:NodeInfo.kt$NodeInfo$0.299 - MagicNumber:NodeInfo.kt$NodeInfo$0.587 - MagicNumber:NodeInfo.kt$NodeInfo$0x0000FF - MagicNumber:NodeInfo.kt$NodeInfo$0x00FF00 - MagicNumber:NodeInfo.kt$NodeInfo$0xFF0000 - MagicNumber:NodeInfo.kt$NodeInfo$1000 - MagicNumber:NodeInfo.kt$NodeInfo$1000.0 - MagicNumber:NodeInfo.kt$NodeInfo$16 - MagicNumber:NodeInfo.kt$NodeInfo$1609 - MagicNumber:NodeInfo.kt$NodeInfo$1609.34 - MagicNumber:NodeInfo.kt$NodeInfo$255 - MagicNumber:NodeInfo.kt$NodeInfo$3.281 - MagicNumber:NodeInfo.kt$NodeInfo$8 - MagicNumber:NodeInfo.kt$Position$180 - MagicNumber:NodeInfo.kt$Position$90 - MagicNumber:NodeInfo.kt$Position$90.0 - MagicNumber:NodeInfo.kt$Position.Companion$1000 - MagicNumber:NodeInfo.kt$Position.Companion$1e-7 - MagicNumber:NodeInfo.kt$Position.Companion$1e7 - MatchingDeclarationName:LocationUtils.kt$GPSFormat - + diff --git a/settings.gradle.kts b/settings.gradle.kts index cacdfb536..a0d13eca5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,6 +31,7 @@ include( ":core:strings", ":core:ui", ":feature:map", + ":feature:node", ":mesh_service_example", ) rootProject.name = "MeshtasticAndroid"