Add :core:ui (#3203)

This commit is contained in:
Phil Oliver 2025-09-25 17:01:53 -04:00 committed by GitHub
parent b139c7edd7
commit c5360086b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
128 changed files with 594 additions and 750 deletions

View file

@ -185,6 +185,7 @@ dependencies {
implementation(projects.core.prefs)
implementation(projects.core.proto)
implementation(projects.core.strings)
implementation(projects.core.ui)
implementation(projects.feature.map)
// Bundles

View file

@ -12,8 +12,6 @@
<ID>CommentSpacing:Exceptions.kt$Exceptions$/// Set in Application.onCreate</ID>
<ID>CommentWrapping:SignalMetrics.kt$Metric.SNR$/* Selected 12 as the max to get 4 equal vertical sections. */</ID>
<ID>ComposableNaming:NodeDetail.kt$notesSection</ID>
<ID>ComposableParamOrder:AlertDialogs.kt$SimpleAlertDialog</ID>
<ID>ComposableParamOrder:BatteryInfo.kt$BatteryInfo</ID>
<ID>ComposableParamOrder:ChannelSettingsItemList.kt$ChannelSettingsItemList</ID>
<ID>ComposableParamOrder:Debug.kt$DebugMenuActions</ID>
<ID>ComposableParamOrder:Debug.kt$DecodedPayloadBlock</ID>
@ -21,7 +19,6 @@
<ID>ComposableParamOrder:DebugSearch.kt$DebugSearchStateviewModelDefaults</ID>
<ID>ComposableParamOrder:DeviceMetrics.kt$DeviceMetricsChart</ID>
<ID>ComposableParamOrder:EditBase64Preference.kt$EditBase64Preference</ID>
<ID>ComposableParamOrder:EditTextPreference.kt$EditTextPreference</ID>
<ID>ComposableParamOrder:ElevationInfo.kt$ElevationInfo</ID>
<ID>ComposableParamOrder:EmptyStateContent.kt$EmptyStateContent</ID>
<ID>ComposableParamOrder:EnvironmentCharts.kt$ChartContent</ID>
@ -33,7 +30,6 @@
<ID>ComposableParamOrder:LinkedCoordinates.kt$LinkedCoordinates</ID>
<ID>ComposableParamOrder:MainAppBar.kt$MainAppBar</ID>
<ID>ComposableParamOrder:MapReportingPreference.kt$MapReportingPreference</ID>
<ID>ComposableParamOrder:MaterialBatteryInfo.kt$MaterialBatteryInfo</ID>
<ID>ComposableParamOrder:Message.kt$MessageScreen</ID>
<ID>ComposableParamOrder:Message.kt$QuickChatRow</ID>
<ID>ComposableParamOrder:MessageActions.kt$MessageActions</ID>
@ -59,23 +55,13 @@
<ID>ComposableParamOrder:SettingsItem.kt$SettingsItem</ID>
<ID>ComposableParamOrder:SignalInfo.kt$SignalInfo</ID>
<ID>ComposableParamOrder:SignalMetrics.kt$SignalMetricsChart</ID>
<ID>ComposableParamOrder:SwitchPreference.kt$SwitchPreference</ID>
<ID>ComposableParamOrder:TopLevelNavIcon.kt$ConnectionsNavIcon</ID>
<ID>ComposableParamOrder:TracerouteButton.kt$TracerouteButton</ID>
<ID>ComposableParamOrder:WarningDialog.kt$WarningDialog</ID>
<ID>ConstructorParameterNaming:MeshLog.kt$MeshLog$@ColumnInfo(name = "message") val raw_message: String</ID>
<ID>ConstructorParameterNaming:MeshLog.kt$MeshLog$@ColumnInfo(name = "received_date") val received_date: Long</ID>
<ID>ConstructorParameterNaming:MeshLog.kt$MeshLog$@ColumnInfo(name = "type") val message_type: String</ID>
<ID>ConstructorParameterNaming:Packet.kt$ContactSettings$@PrimaryKey val contact_key: String</ID>
<ID>ConstructorParameterNaming:Packet.kt$Packet$@ColumnInfo(name = "contact_key") val contact_key: String</ID>
<ID>ConstructorParameterNaming:Packet.kt$Packet$@ColumnInfo(name = "port_num") val port_num: Int</ID>
<ID>ConstructorParameterNaming:Packet.kt$Packet$@ColumnInfo(name = "received_time") val received_time: Long</ID>
<ID>ContentSlotReused:AdaptiveTwoPane.kt$second</ID>
<ID>CyclomaticComplexMethod:MeshService.kt$MeshService$private fun handleReceivedData(packet: MeshPacket)</ID>
<ID>CyclomaticComplexMethod:NetworkConfigItemList.kt$@Composable fun NetworkConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel())</ID>
<ID>CyclomaticComplexMethod:PositionConfigItemList.kt$@OptIn(ExperimentalPermissionsApi::class) @Composable fun PositionConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel())</ID>
<ID>CyclomaticComplexMethod:RadioConfigViewModel.kt$RadioConfigViewModel$private fun processPacketResponse(packet: MeshProtos.MeshPacket)</ID>
<ID>EmptyCatchBlock:MeshLog.kt$MeshLog${ }</ID>
<ID>EmptyClassBlock:DebugLogFile.kt$BinaryLogFile${ }</ID>
<ID>EmptyFunctionBlock:NopInterface.kt$NopInterface${ }</ID>
<ID>EmptyFunctionBlock:NsdManager.kt$&lt;no name provided&gt;${ }</ID>
@ -89,16 +75,13 @@
<ID>FinalNewline:DateUtils.kt$com.geeksville.mesh.android.DateUtils.kt</ID>
<ID>FinalNewline:DebugLogFile.kt$com.geeksville.mesh.android.DebugLogFile.kt</ID>
<ID>FinalNewline:DeferredExecution.kt$com.geeksville.mesh.concurrent.DeferredExecution.kt</ID>
<ID>FinalNewline:DeviceVersion.kt$com.geeksville.mesh.model.DeviceVersion.kt</ID>
<ID>FinalNewline:InterfaceId.kt$com.geeksville.mesh.repository.radio.InterfaceId.kt</ID>
<ID>FinalNewline:InterfaceSpec.kt$com.geeksville.mesh.repository.radio.InterfaceSpec.kt</ID>
<ID>FinalNewline:MockInterfaceFactory.kt$com.geeksville.mesh.repository.radio.MockInterfaceFactory.kt</ID>
<ID>FinalNewline:NopInterface.kt$com.geeksville.mesh.repository.radio.NopInterface.kt</ID>
<ID>FinalNewline:NopInterfaceFactory.kt$com.geeksville.mesh.repository.radio.NopInterfaceFactory.kt</ID>
<ID>FinalNewline:ProbeTableProvider.kt$com.geeksville.mesh.repository.usb.ProbeTableProvider.kt</ID>
<ID>FinalNewline:QuickChatActionRepository.kt$com.geeksville.mesh.database.QuickChatActionRepository.kt</ID>
<ID>FinalNewline:RadioNotConnectedException.kt$com.geeksville.mesh.service.RadioNotConnectedException.kt</ID>
<ID>FinalNewline:RegularPreference.kt$com.geeksville.mesh.ui.common.components.RegularPreference.kt</ID>
<ID>FinalNewline:SerialConnection.kt$com.geeksville.mesh.repository.usb.SerialConnection.kt</ID>
<ID>FinalNewline:SerialConnectionListener.kt$com.geeksville.mesh.repository.usb.SerialConnectionListener.kt</ID>
<ID>FinalNewline:SerialInterface.kt$com.geeksville.mesh.repository.radio.SerialInterface.kt</ID>
@ -107,9 +90,6 @@
<ID>FinalNewline:UsbBroadcastReceiver.kt$com.geeksville.mesh.repository.usb.UsbBroadcastReceiver.kt</ID>
<ID>FinalNewline:UsbRepositoryModule.kt$com.geeksville.mesh.repository.usb.UsbRepositoryModule.kt</ID>
<ID>ForbiddenComment:SafeBluetooth.kt$SafeBluetooth$// TODO: display some kind of UI about restarting BLE</ID>
<ID>FunctionNaming:PacketDao.kt$PacketDao$@Query("DELETE FROM packet WHERE uuid=:uuid") suspend fun _delete(uuid: Long)</ID>
<ID>FunctionNaming:QuickChatActionDao.kt$QuickChatActionDao$@Query("Delete from quick_chat where uuid=:uuid") fun _delete(uuid: Long)</ID>
<ID>ImplicitDefaultLocale:NodeInfo.kt$NodeInfo$String.format("%d%%", batteryLevel)</ID>
<ID>LambdaParameterEventTrailing:Channel.kt$onConfirm</ID>
<ID>LambdaParameterEventTrailing:MainAppBar.kt$onAction</ID>
<ID>LambdaParameterEventTrailing:Message.kt$onClick</ID>
@ -139,16 +119,6 @@
<ID>LongMethod:StoreForwardConfigItemList.kt$@Composable fun StoreForwardConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel())</ID>
<ID>LongMethod:TelemetryConfigItemList.kt$@Composable fun TelemetryConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel())</ID>
<ID>LongMethod:UserConfigItemList.kt$@Composable fun UserConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel())</ID>
<ID>MagicNumber:BatteryInfo.kt$100</ID>
<ID>MagicNumber:BatteryInfo.kt$101</ID>
<ID>MagicNumber:BatteryInfo.kt$14</ID>
<ID>MagicNumber:BatteryInfo.kt$15</ID>
<ID>MagicNumber:BatteryInfo.kt$34</ID>
<ID>MagicNumber:BatteryInfo.kt$35</ID>
<ID>MagicNumber:BatteryInfo.kt$4</ID>
<ID>MagicNumber:BatteryInfo.kt$5</ID>
<ID>MagicNumber:BatteryInfo.kt$79</ID>
<ID>MagicNumber:BatteryInfo.kt$80</ID>
<ID>MagicNumber:BluetoothInterface.kt$BluetoothInterface$1000</ID>
<ID>MagicNumber:BluetoothInterface.kt$BluetoothInterface$500</ID>
<ID>MagicNumber:BluetoothInterface.kt$BluetoothInterface$512</ID>
@ -156,30 +126,15 @@
<ID>MagicNumber:ChannelSet.kt$960</ID>
<ID>MagicNumber:Contacts.kt$7</ID>
<ID>MagicNumber:Contacts.kt$8</ID>
<ID>MagicNumber:DataPacket.kt$DataPacket.CREATOR$16</ID>
<ID>MagicNumber:Debug.kt$3</ID>
<ID>MagicNumber:DeviceVersion.kt$DeviceVersion$100</ID>
<ID>MagicNumber:DeviceVersion.kt$DeviceVersion$10000</ID>
<ID>MagicNumber:EditChannelDialog.kt$16</ID>
<ID>MagicNumber:EditChannelDialog.kt$32</ID>
<ID>MagicNumber:EditIPv4Preference.kt$0xff</ID>
<ID>MagicNumber:EditIPv4Preference.kt$16</ID>
<ID>MagicNumber:EditIPv4Preference.kt$24</ID>
<ID>MagicNumber:EditIPv4Preference.kt$8</ID>
<ID>MagicNumber:EditListPreference.kt$12</ID>
<ID>MagicNumber:EditListPreference.kt$12345</ID>
<ID>MagicNumber:EditListPreference.kt$67890</ID>
<ID>MagicNumber:Extensions.kt$1000</ID>
<ID>MagicNumber:Extensions.kt$1440000</ID>
<ID>MagicNumber:Extensions.kt$24</ID>
<ID>MagicNumber:Extensions.kt$2880</ID>
<ID>MagicNumber:Extensions.kt$60</ID>
<ID>MagicNumber:LazyColumnDragAndDropDemo.kt$50</ID>
<ID>MagicNumber:LocationRepository.kt$LocationRepository$1000L</ID>
<ID>MagicNumber:LocationRepository.kt$LocationRepository$30</ID>
<ID>MagicNumber:LocationRepository.kt$LocationRepository$31</ID>
<ID>MagicNumber:LocationUtils.kt$1e-7</ID>
<ID>MagicNumber:LocationUtils.kt$360</ID>
<ID>MagicNumber:MQTTRepository.kt$MQTTRepository$512</ID>
<ID>MagicNumber:MeshService.kt$MeshService$0xffffffff</ID>
<ID>MagicNumber:MeshService.kt$MeshService$1000</ID>
@ -193,28 +148,6 @@
<ID>MagicNumber:MetricsViewModel.kt$MetricsViewModel$1000L</ID>
<ID>MagicNumber:MetricsViewModel.kt$MetricsViewModel$1e-5</ID>
<ID>MagicNumber:MetricsViewModel.kt$MetricsViewModel$1e-7</ID>
<ID>MagicNumber:NodeInfo.kt$DeviceMetrics.Companion$1000</ID>
<ID>MagicNumber:NodeInfo.kt$EnvironmentMetrics.Companion$1000</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$0.114</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$0.299</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$0.587</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$0x0000FF</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$0x00FF00</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$0xFF0000</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$1000</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$1000.0</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$16</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$1609</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$1609.34</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$255</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$3.281</ID>
<ID>MagicNumber:NodeInfo.kt$NodeInfo$8</ID>
<ID>MagicNumber:NodeInfo.kt$Position$180</ID>
<ID>MagicNumber:NodeInfo.kt$Position$90</ID>
<ID>MagicNumber:NodeInfo.kt$Position$90.0</ID>
<ID>MagicNumber:NodeInfo.kt$Position.Companion$1000</ID>
<ID>MagicNumber:NodeInfo.kt$Position.Companion$1e-7</ID>
<ID>MagicNumber:NodeInfo.kt$Position.Companion$1e7</ID>
<ID>MagicNumber:PacketRepository.kt$PacketRepository$500</ID>
<ID>MagicNumber:PacketResponseStateDialog.kt$100</ID>
<ID>MagicNumber:PowerConfigItemList.kt$3600</ID>
@ -239,20 +172,12 @@
<ID>MagicNumber:TCPInterface.kt$TCPInterface$500</ID>
<ID>MagicNumber:UIState.kt$4</ID>
<ID>MatchingDeclarationName:AnalyticsClient.kt$AnalyticsProvider</ID>
<ID>MatchingDeclarationName:DistanceExtensions.kt$DistanceUnit</ID>
<ID>MatchingDeclarationName:LocationUtils.kt$GPSFormat</ID>
<ID>MatchingDeclarationName:MeshServiceStarter.kt$ServiceStarter : Worker</ID>
<ID>MatchingDeclarationName:SortOption.kt$NodeSortOption</ID>
<ID>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 &gt;= 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) */</ID>
<ID>MaxLineLength:BluetoothState.kt$BluetoothState$"BluetoothState(hasPermissions=$hasPermissions, enabled=$enabled, bondedDevices=${bondedDevices.map { it.anonymize }})"</ID>
<ID>MaxLineLength:DataPacket.kt$DataPacket$val dataType: Int</ID>
<ID>MaxLineLength:LocationRepository.kt$LocationRepository$info("Starting location updates with $providerList intervalMs=${intervalMs}ms and minDistanceM=${minDistanceM}m")</ID>
<ID>MaxLineLength:MQTTRepository.kt$MQTTRepository.Companion$*</ID>
<ID>MaxLineLength:ServiceClient.kt$ServiceClient$// Some phones seem to ahve a race where if you unbind and quickly rebind bindService returns false. Try</ID>
<ID>MaxLineLength:ServiceClient.kt$ServiceClient.&lt;no name provided&gt;$// If we start to close a service, it seems that there is a possibility a onServiceConnected event is the queue</ID>
<ID>ModifierClickableOrder:Channel.kt$clickable(onClick = onClick)</ID>
<ID>ModifierListSpacing:Packet.kt$Packet$@Entity( tableName = "packet", indices = [ Index(value = ["myNodeNum"]), Index(value = ["port_num"]), Index(value = ["contact_key"]), ] ) data</ID>
<ID>ModifierMissing:AdaptiveTwoPane.kt$AdaptiveTwoPane</ID>
<ID>ModifierMissing:BLEDevices.kt$BLEDevices</ID>
<ID>ModifierMissing:Channel.kt$ChannelScreen</ID>
<ID>ModifierMissing:ChannelSettingsItemList.kt$ChannelSelection</ID>
@ -270,11 +195,6 @@
<ID>ModifierMissing:EmptyStateContent.kt$EmptyStateContent</ID>
<ID>ModifierMissing:EnvironmentMetrics.kt$EnvironmentMetricsScreen</ID>
<ID>ModifierMissing:HostMetricsLog.kt$HostMetricsLogScreen</ID>
<ID>ModifierMissing:IndoorAirQuality.kt$IndoorAirQuality</ID>
<ID>ModifierMissing:LoraSignalIndicator.kt$LoraSignalIndicator</ID>
<ID>ModifierMissing:LoraSignalIndicator.kt$Rssi</ID>
<ID>ModifierMissing:LoraSignalIndicator.kt$Snr</ID>
<ID>ModifierMissing:LoraSignalIndicator.kt$SnrAndRssi</ID>
<ID>ModifierMissing:Main.kt$MainScreen</ID>
<ID>ModifierMissing:MapReportingPreference.kt$MapReportingPreference</ID>
<ID>ModifierMissing:MessageActions.kt$MessageStatusButton</ID>
@ -302,8 +222,6 @@
<ID>ModifierMissing:SettingsScreen.kt$SettingsScreen</ID>
<ID>ModifierMissing:Share.kt$ShareScreen</ID>
<ID>ModifierMissing:SignalMetrics.kt$SignalMetricsScreen</ID>
<ID>ModifierMissing:SimpleAlertDialog.kt$SimpleAlertDialog</ID>
<ID>ModifierMissing:SlidingSelector.kt$OptionLabel</ID>
<ID>ModifierMissing:TopLevelNavIcon.kt$TopLevelNavIcon</ID>
<ID>ModifierNotUsedAtRoot:DeviceMetrics.kt$modifier = modifier.weight(weight = Y_AXIS_WEIGHT)</ID>
<ID>ModifierNotUsedAtRoot:DeviceMetrics.kt$modifier = modifier.width(dp)</ID>
@ -317,13 +235,10 @@
<ID>ModifierNotUsedAtRoot:PowerMetrics.kt$modifier = modifier.weight(weight = Y_AXIS_WEIGHT)</ID>
<ID>ModifierNotUsedAtRoot:PowerMetrics.kt$modifier = modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:PowerMetrics.kt$modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:PreferenceFooter.kt$modifier = modifier .height(48.dp) .weight(1f)</ID>
<ID>ModifierNotUsedAtRoot:SignalInfo.kt$modifier = modifier</ID>
<ID>ModifierNotUsedAtRoot:SignalMetrics.kt$modifier = modifier.weight(weight = Y_AXIS_WEIGHT)</ID>
<ID>ModifierNotUsedAtRoot:SignalMetrics.kt$modifier = modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:SignalMetrics.kt$modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:TextDividerPreference.kt$modifier = modifier .fillMaxWidth() .padding(all = 16.dp)</ID>
<ID>ModifierNotUsedAtRoot:TextDividerPreference.kt$modifier = modifier .fillMaxWidth() .wrapContentWidth(Alignment.End)</ID>
<ID>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 &lt; telemetries.size) { val path = Path() index = createPath( telemetries = telemetries, index = index, path = path, oldestTime = oldest.time, timeRange = timeDiff, width = width, timeThreshold = selectedTime.timeThreshold(), ) { i -&gt; 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), ) } }</ID>
<ID>ModifierReused:DeviceMetrics.kt$HorizontalLinesOverlay( modifier.width(dp), lineColors = listOf(graphColor, Color.Yellow, Color.Red, graphColor, graphColor), )</ID>
<ID>ModifierReused:DeviceMetrics.kt$TimeAxisOverlay(modifier.width(dp), oldest = oldest.time, newest = newest.time, selectedTime.lineInterval())</ID>
@ -339,19 +254,11 @@
<ID>ModifierReused:PowerMetrics.kt$TimeAxisOverlay(modifier.width(dp), oldest = oldest.time, newest = newest.time, selectedTime.lineInterval())</ID>
<ID>ModifierReused:PowerMetrics.kt$YAxisLabels( modifier = modifier.weight(weight = Y_AXIS_WEIGHT), Power.CURRENT.color, minValue = Power.CURRENT.min, maxValue = Power.CURRENT.max, )</ID>
<ID>ModifierReused:PowerMetrics.kt$YAxisLabels( modifier = modifier.weight(weight = Y_AXIS_WEIGHT), VOLTAGE_COLOR, minValue = voltageMin, maxValue = voltageMax, )</ID>
<ID>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() } } }</ID>
<ID>ModifierReused:PreferenceCategory.kt$Text( text, modifier = modifier.padding(start = 16.dp, top = 24.dp, bottom = 8.dp, end = 16.dp), style = MaterialTheme.typography.titleLarge, )</ID>
<ID>ModifierReused:PreferenceFooter.kt$OutlinedButton( modifier = modifier .height(48.dp) .weight(1f), enabled = enabled, onClick = onPositiveClicked, ) { Text( text = stringResource(id = positiveText), ) }</ID>
<ID>ModifierReused:PreferenceFooter.kt$OutlinedButton( modifier = modifier .height(48.dp) .weight(1f), onClick = onNegativeClicked, ) { Text( text = stringResource(id = negativeText), ) }</ID>
<ID>ModifierReused:PreferenceFooter.kt$Row( modifier = modifier .fillMaxWidth() .height(64.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically, ) { OutlinedButton( modifier = modifier .height(48.dp) .weight(1f), onClick = onNegativeClicked, ) { Text( text = stringResource(id = negativeText), ) } OutlinedButton( modifier = modifier .height(48.dp) .weight(1f), enabled = enabled, onClick = onPositiveClicked, ) { Text( text = stringResource(id = positiveText), ) } }</ID>
<ID>ModifierReused:SignalMetrics.kt$Canvas(modifier = modifier.width(dp)) { val width = size.width /* Plot */ for (packet in meshPackets) { val xRatio = (packet.rxTime - oldest.rxTime).toFloat() / timeDiff val x = xRatio * width /* SNR */ plotPoint( drawContext = drawContext, color = Metric.SNR.color, x = x, value = packet.rxSnr - Metric.SNR.min, divisor = snrDiff, ) /* RSSI */ plotPoint( drawContext = drawContext, color = Metric.RSSI.color, x = x, value = packet.rxRssi - Metric.RSSI.min, divisor = rssiDiff, ) } }</ID>
<ID>ModifierReused:SignalMetrics.kt$HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { graphColor })</ID>
<ID>ModifierReused:SignalMetrics.kt$TimeAxisOverlay( modifier.width(dp), oldest = oldest.rxTime, newest = newest.rxTime, selectedTime.lineInterval(), )</ID>
<ID>ModifierReused:SignalMetrics.kt$YAxisLabels( modifier = modifier.weight(weight = Y_AXIS_WEIGHT), Metric.RSSI.color, minValue = Metric.RSSI.min, maxValue = Metric.RSSI.max, )</ID>
<ID>ModifierReused:SignalMetrics.kt$YAxisLabels( modifier = modifier.weight(weight = Y_AXIS_WEIGHT), Metric.SNR.color, minValue = Metric.SNR.min, maxValue = Metric.SNR.max, )</ID>
<ID>ModifierReused:TextDividerPreference.kt$Card( modifier = modifier.fillMaxWidth(), ) { Row( modifier = modifier .fillMaxWidth() .padding(all = 16.dp), verticalAlignment = Alignment.CenterVertically ) { Text( text = title, style = MaterialTheme.typography.bodyLarge, color = if (!enabled) { MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) } else { Color.Unspecified }, ) if (trailingIcon != null) { Icon( trailingIcon, "trailingIcon", modifier = modifier .fillMaxWidth() .wrapContentWidth(Alignment.End), ) } } }</ID>
<ID>ModifierReused:TextDividerPreference.kt$Icon( trailingIcon, "trailingIcon", modifier = modifier .fillMaxWidth() .wrapContentWidth(Alignment.End), )</ID>
<ID>ModifierReused:TextDividerPreference.kt$Row( modifier = modifier .fillMaxWidth() .padding(all = 16.dp), verticalAlignment = Alignment.CenterVertically ) { Text( text = title, style = MaterialTheme.typography.bodyLarge, color = if (!enabled) { MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) } else { Color.Unspecified }, ) if (trailingIcon != null) { Icon( trailingIcon, "trailingIcon", modifier = modifier .fillMaxWidth() .wrapContentWidth(Alignment.End), ) } }</ID>
<ID>ModifierWithoutDefault:CommonCharts.kt$modifier</ID>
<ID>ModifierWithoutDefault:EnvironmentCharts.kt$modifier</ID>
<ID>MultiLineIfElse:Exceptions.kt$Exceptions.errormsg("ignoring exception", ex)</ID>
@ -363,7 +270,6 @@
<ID>MultipleEmitters:NodeDetail.kt$MetricsSection</ID>
<ID>MultipleEmitters:PaxMetrics.kt$PaxMetricsChart</ID>
<ID>MultipleEmitters:PowerMetrics.kt$PowerMetricsChart</ID>
<ID>MultipleEmitters:PreferenceCategory.kt$PreferenceCategory</ID>
<ID>MultipleEmitters:RadioConfig.kt$RadioConfigItemList</ID>
<ID>MultipleEmitters:SignalMetrics.kt$SignalMetricsChart</ID>
<ID>MutableStateAutoboxing:Contacts.kt$mutableStateOf(2)</ID>
@ -380,16 +286,13 @@
<ID>NewLineAtEndOfFile:DateUtils.kt$com.geeksville.mesh.android.DateUtils.kt</ID>
<ID>NewLineAtEndOfFile:DebugLogFile.kt$com.geeksville.mesh.android.DebugLogFile.kt</ID>
<ID>NewLineAtEndOfFile:DeferredExecution.kt$com.geeksville.mesh.concurrent.DeferredExecution.kt</ID>
<ID>NewLineAtEndOfFile:DeviceVersion.kt$com.geeksville.mesh.model.DeviceVersion.kt</ID>
<ID>NewLineAtEndOfFile:InterfaceId.kt$com.geeksville.mesh.repository.radio.InterfaceId.kt</ID>
<ID>NewLineAtEndOfFile:InterfaceSpec.kt$com.geeksville.mesh.repository.radio.InterfaceSpec.kt</ID>
<ID>NewLineAtEndOfFile:MockInterfaceFactory.kt$com.geeksville.mesh.repository.radio.MockInterfaceFactory.kt</ID>
<ID>NewLineAtEndOfFile:NopInterface.kt$com.geeksville.mesh.repository.radio.NopInterface.kt</ID>
<ID>NewLineAtEndOfFile:NopInterfaceFactory.kt$com.geeksville.mesh.repository.radio.NopInterfaceFactory.kt</ID>
<ID>NewLineAtEndOfFile:ProbeTableProvider.kt$com.geeksville.mesh.repository.usb.ProbeTableProvider.kt</ID>
<ID>NewLineAtEndOfFile:QuickChatActionRepository.kt$com.geeksville.mesh.database.QuickChatActionRepository.kt</ID>
<ID>NewLineAtEndOfFile:RadioNotConnectedException.kt$com.geeksville.mesh.service.RadioNotConnectedException.kt</ID>
<ID>NewLineAtEndOfFile:RegularPreference.kt$com.geeksville.mesh.ui.common.components.RegularPreference.kt</ID>
<ID>NewLineAtEndOfFile:SerialConnection.kt$com.geeksville.mesh.repository.usb.SerialConnection.kt</ID>
<ID>NewLineAtEndOfFile:SerialConnectionListener.kt$com.geeksville.mesh.repository.usb.SerialConnectionListener.kt</ID>
<ID>NewLineAtEndOfFile:SerialInterface.kt$com.geeksville.mesh.repository.radio.SerialInterface.kt</ID>
@ -409,7 +312,6 @@
<ID>NoSemicolons:DateUtils.kt$DateUtils$;</ID>
<ID>NoWildcardImports:UsbRepository.kt$import kotlinx.coroutines.flow.*</ID>
<ID>OptionalAbstractKeyword:SyncContinuation.kt$Continuation$abstract</ID>
<ID>ParameterNaming:BitwisePreference.kt$onItemSelected</ID>
<ID>ParameterNaming:ChannelSettingsItemList.kt$onPositiveClicked</ID>
<ID>ParameterNaming:ChannelSettingsItemList.kt$onSelected</ID>
<ID>ParameterNaming:CleanNodeDatabaseScreen.kt$onCheckedChanged</ID>
@ -417,10 +319,7 @@
<ID>ParameterNaming:Contacts.kt$onDeleteSelected</ID>
<ID>ParameterNaming:Contacts.kt$onMuteSelected</ID>
<ID>ParameterNaming:DropDownPreference.kt$onItemSelected</ID>
<ID>ParameterNaming:EditIPv4Preference.kt$onValueChanged</ID>
<ID>ParameterNaming:EditListPreference.kt$onValuesChanged</ID>
<ID>ParameterNaming:EditPasswordPreference.kt$onValueChanged</ID>
<ID>ParameterNaming:EditTextPreference.kt$onValueChanged</ID>
<ID>ParameterNaming:MapReportingPreference.kt$onMapReportingEnabledChanged</ID>
<ID>ParameterNaming:MapReportingPreference.kt$onPositionPrecisionChanged</ID>
<ID>ParameterNaming:MapReportingPreference.kt$onPublishIntervalSecsChanged</ID>
@ -429,25 +328,15 @@
<ID>ParameterNaming:NodeDetail.kt$onFirmwareSelected</ID>
<ID>ParameterNaming:NodeFilterTextField.kt$onToggleShowIgnored</ID>
<ID>ParameterNaming:PositionPrecisionPreference.kt$onValueChanged</ID>
<ID>ParameterNaming:PreferenceFooter.kt$onCancelClicked</ID>
<ID>ParameterNaming:PreferenceFooter.kt$onNegativeClicked</ID>
<ID>ParameterNaming:PreferenceFooter.kt$onPositiveClicked</ID>
<ID>ParameterNaming:PreferenceFooter.kt$onSaveClicked</ID>
<ID>ParameterNaming:SlidingSelector.kt$onOptionSelected</ID>
<ID>ParameterNaming:UsbDevices.kt$onDeviceSelected</ID>
<ID>ParameterNaming:WelcomeScreen.kt$onGetStarted</ID>
<ID>PreviewAnnotationNaming:LargeFontPreview.kt$LargeFontPreview$LargeFontPreview</ID>
<ID>PreviewPublic:BatteryInfo.kt$BatteryInfoPreview</ID>
<ID>PreviewPublic:BatteryInfo.kt$BatteryInfoPreviewSimple</ID>
<ID>PreviewPublic:Channel.kt$ModemPresetInfoPreview</ID>
<ID>PreviewPublic:ElevationInfo.kt$ElevationInfoPreview</ID>
<ID>PreviewPublic:EmptyStateContent.kt$EmptyStateContentPreview</ID>
<ID>PreviewPublic:IndoorAirQuality.kt$IAQScalePreview</ID>
<ID>PreviewPublic:LastHeardInfo.kt$LastHeardInfoPreview</ID>
<ID>PreviewPublic:LazyColumnDragAndDropDemo.kt$LazyColumnDragAndDropDemo</ID>
<ID>PreviewPublic:LinkedCoordinates.kt$LinkedCoordinatesPreview</ID>
<ID>PreviewPublic:MapReportingPreference.kt$MapReportingPreview</ID>
<ID>PreviewPublic:MaterialBatteryInfo.kt$MaterialBatteryInfoPreview</ID>
<ID>PreviewPublic:NodeChip.kt$NodeChipPreview</ID>
<ID>PreviewPublic:NodeItem.kt$NodeInfoPreview</ID>
<ID>PreviewPublic:NodeItem.kt$NodeInfoSimplePreview</ID>
@ -458,17 +347,13 @@
<ID>PreviewPublic:SignalInfo.kt$SignalInfoPreview</ID>
<ID>PreviewPublic:SignalInfo.kt$SignalInfoSelfPreview</ID>
<ID>PreviewPublic:SignalInfo.kt$SignalInfoSimplePreview</ID>
<ID>PreviewPublic:SlidingSelector.kt$SlidingSelectorPreview</ID>
<ID>RethrowCaughtException:SyncContinuation.kt$Continuation$throw ex</ID>
<ID>ReturnCount:RadioConfigViewModel.kt$RadioConfigViewModel$private fun processPacketResponse(packet: MeshProtos.MeshPacket)</ID>
<ID>SpacingAroundKeyword:Exceptions.kt$if</ID>
<ID>SpacingAroundKeyword:Exceptions.kt$when</ID>
<ID>SpacingAroundRangeOperator:BatteryInfo.kt$..</ID>
<ID>SwallowedException:BluetoothInterface.kt$BluetoothInterface$ex: CancellationException</ID>
<ID>SwallowedException:ChannelSet.kt$ex: Throwable</ID>
<ID>SwallowedException:DeviceVersion.kt$DeviceVersion$e: Exception</ID>
<ID>SwallowedException:Exceptions.kt$ex: Throwable</ID>
<ID>SwallowedException:MeshLog.kt$MeshLog$e: IOException</ID>
<ID>SwallowedException:MeshService.kt$MeshService$ex: BLEException</ID>
<ID>SwallowedException:MeshService.kt$MeshService$ex: CancellationException</ID>
<ID>SwallowedException:NsdManager.kt$ex: IllegalArgumentException</ID>
@ -479,7 +364,6 @@
<ID>TooGenericExceptionCaught:BTScanModel.kt$BTScanModel$ex: Throwable</ID>
<ID>TooGenericExceptionCaught:BluetoothInterface.kt$BluetoothInterface$ex: Exception</ID>
<ID>TooGenericExceptionCaught:ChannelSet.kt$ex: Throwable</ID>
<ID>TooGenericExceptionCaught:DeviceVersion.kt$DeviceVersion$e: Exception</ID>
<ID>TooGenericExceptionCaught:Exceptions.kt$ex: Throwable</ID>
<ID>TooGenericExceptionCaught:LanguageUtils.kt$LanguageUtils$e: Exception</ID>
<ID>TooGenericExceptionCaught:LocationRepository.kt$LocationRepository$e: Exception</ID>
@ -492,7 +376,6 @@
<ID>TooGenericExceptionCaught:SafeBluetooth.kt$SafeBluetooth$ex: NullPointerException</ID>
<ID>TooGenericExceptionCaught:SyncContinuation.kt$Continuation$ex: Throwable</ID>
<ID>TooGenericExceptionCaught:TCPInterface.kt$TCPInterface$ex: Throwable</ID>
<ID>TooGenericExceptionThrown:DeviceVersion.kt$DeviceVersion$throw Exception("Can't parse version $s")</ID>
<ID>TooGenericExceptionThrown:MeshService.kt$MeshService$throw Exception("Can't set user without a NodeInfo")</ID>
<ID>TooGenericExceptionThrown:MeshService.kt$MeshService.&lt;no name provided&gt;$throw Exception("Port numbers must be non-zero!")</ID>
<ID>TooGenericExceptionThrown:ServiceClient.kt$ServiceClient$throw Exception("Haven't called connect")</ID>
@ -503,9 +386,7 @@
<ID>TooManyFunctions:MeshService.kt$MeshService : ServiceLogging</ID>
<ID>TooManyFunctions:MeshService.kt$MeshService$&lt;no name provided&gt; : Stub</ID>
<ID>TooManyFunctions:NodeDetail.kt$com.geeksville.mesh.ui.node.NodeDetail.kt</ID>
<ID>TooManyFunctions:PacketDao.kt$PacketDao</ID>
<ID>TooManyFunctions:PacketRepository.kt$PacketRepository</ID>
<ID>TooManyFunctions:RadioConfigRepository.kt$RadioConfigRepository</ID>
<ID>TooManyFunctions:RadioConfigViewModel.kt$RadioConfigViewModel : ViewModelLogging</ID>
<ID>TooManyFunctions:RadioInterfaceService.kt$RadioInterfaceService : Logging</ID>
<ID>TooManyFunctions:SafeBluetooth.kt$SafeBluetooth : LoggingCloseable</ID>
@ -521,15 +402,11 @@
<ID>ViewModelForwarding:NodeScreen.kt$AddContactFAB( modifier = Modifier.animateFloatingActionButton( visible = !isScrollInProgress &amp;&amp; connectionState == ConnectionState.CONNECTED &amp;&amp; shareCapable, alignment = Alignment.BottomEnd, ), model = model, onSharedContactImport = { contact -&gt; model.addSharedContact(contact) }, )</ID>
<ID>ViewModelInjection:DebugSearch.kt$viewModel</ID>
<ID>WildcardImport:UsbRepository.kt$import kotlinx.coroutines.flow.*</ID>
<ID>Wrapping:DebugFilters.kt$(</ID>
<ID>Wrapping:DebugFilters.kt$if (filter in filterTexts) { Icon( imageVector = Icons.Filled.Done, contentDescription = stringResource(id = R.string.debug_filter_included), ) }</ID>
<ID>Wrapping:MQTTRepository.kt$MQTTRepository.&lt;no name provided&gt;$(</ID>
<ID>Wrapping:Message.kt${ event -&gt; when (event) { is MessageScreenEvent.SendMessage -&gt; { viewModel.sendMessage(event.text, contactKey, event.replyingToPacketId) if (event.replyingToPacketId != null) replyingToPacketId = null messageInputState.clearText() } is MessageScreenEvent.SendReaction -&gt; viewModel.sendReaction(event.emoji, event.messageId, contactKey) is MessageScreenEvent.DeleteMessages -&gt; { viewModel.deleteMessages(event.ids) selectedMessageIds.value = emptySet() showDeleteDialog = false } is MessageScreenEvent.ClearUnreadCount -&gt; viewModel.clearUnreadCount(contactKey, event.lastReadMessageId) is MessageScreenEvent.HandleNodeMenuAction -&gt; { when (val action = event.action) { is NodeMenuAction.DirectMessage -&gt; { val hasPKC = ourNode?.hasPKC == true &amp;&amp; action.node.hasPKC val targetChannel = if (hasPKC) { DataPacket.PKC_CHANNEL_INDEX } else { action.node.channel } navigateToMessages("$targetChannel${action.node.user.id}") } is NodeMenuAction.MoreDetails -&gt; navigateToNodeDetails(action.node.num) is NodeMenuAction.Share -&gt; sharedContact = action.node else -&gt; viewModel.handleNodeMenuAction(action) } } is MessageScreenEvent.SetTitle -&gt; viewModel.setTitle(event.title) is MessageScreenEvent.NavigateToMessages -&gt; navigateToMessages(event.contactKey) is MessageScreenEvent.NavigateToNodeDetails -&gt; navigateToNodeDetails(event.nodeNum) MessageScreenEvent.NavigateBack -&gt; onNavigateBack() is MessageScreenEvent.CopyToClipboard -&gt; { clipboardManager.nativeClipboard.setPrimaryClip(ClipData.newPlainText(event.text, event.text)) selectedMessageIds.value = emptySet() } } }</ID>
<ID>Wrapping:SerialConnectionImpl.kt$SerialConnectionImpl$(</ID>
<ID>Wrapping:SerialConnectionImpl.kt$SerialConnectionImpl$(port, object : SerialInputOutputManager.Listener { override fun onNewData(data: ByteArray) { listener.onDataReceived(data) } override fun onRunError(e: Exception?) { closed.set(true) ignoreException { port.dtr = false port.rts = false port.close() } closedLatch.countDown() listener.onDisconnected(e) } })</ID>
<ID>Wrapping:SerialInterface.kt$SerialInterface$(</ID>
<ID>Wrapping:SerialInterface.kt$SerialInterface$(device, object : SerialConnectionListener { override fun onMissingPermission() { errormsg("Need permissions for port") } override fun onConnected() { onConnect.invoke() } override fun onDataReceived(bytes: ByteArray) { debug("Received ${bytes.size} byte(s)") bytes.forEach(::readChar) } override fun onDisconnected(thrown: Exception?) { thrown?.let { e -&gt; errormsg("Serial error: $e") } debug("$device disconnected") onDeviceDisconnect(false) } })</ID>
<ID>Wrapping:ServiceClient.kt$ServiceClient$Closeable, Logging</ID>
<ID>Wrapping:SlidingSelector.kt$;</ID>
</CurrentIssues>
</SmellBaseline>

View file

@ -64,11 +64,11 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.geeksville.mesh.MeshProtos.Waypoint
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.EmojiPickerDialog
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.waypoint
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.theme.AppTheme
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale

View file

@ -29,8 +29,8 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
@Composable
fun MapButton(

View file

@ -33,9 +33,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.res.stringResource
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.map.MapViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.StatusColors.StatusRed
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable

View file

@ -44,14 +44,14 @@ import com.geeksville.mesh.android.GeeksvilleApplication
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.MainScreen
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.MODE_DYNAMIC
import com.geeksville.mesh.ui.intro.AppIntroductionScreen
import com.geeksville.mesh.ui.sharing.toSharedContact
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.meshtastic.core.datastore.UiPreferencesDataSource
import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.ui.theme.MODE_DYNAMIC
import javax.inject.Inject
@AndroidEntryPoint

View file

@ -19,16 +19,16 @@ package com.geeksville.mesh.model
import androidx.compose.ui.graphics.Color
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.ui.common.theme.GraphColors.Green
import com.geeksville.mesh.ui.common.theme.GraphColors.InfantryBlue
import com.geeksville.mesh.ui.common.theme.GraphColors.LightGreen
import com.geeksville.mesh.ui.common.theme.GraphColors.Magenta
import com.geeksville.mesh.ui.common.theme.GraphColors.Orange
import com.geeksville.mesh.ui.common.theme.GraphColors.Pink
import com.geeksville.mesh.ui.common.theme.GraphColors.Purple
import com.geeksville.mesh.ui.common.theme.GraphColors.Red
import com.geeksville.mesh.ui.common.theme.GraphColors.Yellow
import org.meshtastic.core.model.util.UnitConversions
import org.meshtastic.core.ui.theme.GraphColors.Green
import org.meshtastic.core.ui.theme.GraphColors.InfantryBlue
import org.meshtastic.core.ui.theme.GraphColors.LightGreen
import org.meshtastic.core.ui.theme.GraphColors.Magenta
import org.meshtastic.core.ui.theme.GraphColors.Orange
import org.meshtastic.core.ui.theme.GraphColors.Pink
import org.meshtastic.core.ui.theme.GraphColors.Purple
import org.meshtastic.core.ui.theme.GraphColors.Red
import org.meshtastic.core.ui.theme.GraphColors.Yellow
@Suppress("MagicNumber")
enum class Environment(val color: Color) {

View file

@ -91,16 +91,7 @@ import com.geeksville.mesh.repository.radio.MeshActivity
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.service.MeshService
import com.geeksville.mesh.ui.common.components.MainAppBar
import com.geeksville.mesh.ui.common.components.MultipleChoiceAlertDialog
import com.geeksville.mesh.ui.common.components.ScannedQrCodeDialog
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
import com.geeksville.mesh.ui.common.icons.Conversations
import com.geeksville.mesh.ui.common.icons.Map
import com.geeksville.mesh.ui.common.icons.MeshtasticIcons
import com.geeksville.mesh.ui.common.icons.Nodes
import com.geeksville.mesh.ui.common.icons.Settings
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusBlue
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.connections.DeviceType
import com.geeksville.mesh.ui.connections.components.TopLevelNavIcon
import com.geeksville.mesh.ui.node.components.NodeMenuAction
@ -120,6 +111,15 @@ import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.MultipleChoiceAlertDialog
import org.meshtastic.core.ui.component.SimpleAlertDialog
import org.meshtastic.core.ui.icon.Conversations
import org.meshtastic.core.ui.icon.Map
import org.meshtastic.core.ui.icon.MeshtasticIcons
import org.meshtastic.core.ui.icon.Nodes
import org.meshtastic.core.ui.icon.Settings
import org.meshtastic.core.ui.theme.StatusColors.StatusBlue
import org.meshtastic.core.ui.theme.StatusColors.StatusGreen
import kotlin.reflect.KClass
enum class TopLevelDestination(@StringRes val label: Int, val icon: ImageVector, val route: Route) {

View file

@ -46,6 +46,7 @@ import com.geeksville.mesh.copy
import com.geeksville.mesh.remoteHardwarePin
import com.google.protobuf.ByteString
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
@Suppress("LongMethod")
@Composable

View file

@ -31,6 +31,7 @@ import androidx.emoji2.emojipicker.RecentEmojiProviderAdapter
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.geeksville.mesh.ui.common.EmojiPickerViewModel
import com.geeksville.mesh.util.CustomRecentEmojiProvider
import org.meshtastic.core.ui.component.BottomSheetDialog
@Composable
fun EmojiPicker(

View file

@ -50,7 +50,6 @@ import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.navigation.isConfigRoute
import com.geeksville.mesh.navigation.isNodeDetailRoute
import com.geeksville.mesh.ui.TopLevelDestination.Companion.isTopLevel
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.debug.DebugMenuActions
import com.geeksville.mesh.ui.node.components.NodeChip
import com.geeksville.mesh.ui.node.components.NodeMenuAction
@ -59,6 +58,7 @@ import org.meshtastic.core.navigation.ContactsRoutes
import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
@Suppress("CyclomaticComplexMethod")
@Composable

View file

@ -34,6 +34,7 @@ import androidx.compose.ui.unit.dp
import org.meshtastic.core.model.util.DistanceUnit
import org.meshtastic.core.model.util.toDistanceString
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.SwitchPreference
import kotlin.math.pow
import kotlin.math.roundToInt

View file

@ -64,11 +64,11 @@ import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.ChannelProtos.ChannelSettings
import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig
import com.geeksville.mesh.model.getChannel
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow
import org.meshtastic.core.model.Channel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.StatusColors.StatusGreen
import org.meshtastic.core.ui.theme.StatusColors.StatusRed
import org.meshtastic.core.ui.theme.StatusColors.StatusYellow
private const val PRECISE_POSITION_BITS = 32

View file

@ -27,9 +27,10 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewParameter
import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.NodeSignalQuality
import org.meshtastic.core.ui.theme.AppTheme
const val MAX_VALID_SNR = 100F
const val MAX_VALID_RSSI = 0

View file

@ -66,7 +66,6 @@ import com.geeksville.mesh.navigation.ConfigRoute
import com.geeksville.mesh.navigation.getNavRouteFrom
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.ui.common.components.MainAppBar
import com.geeksville.mesh.ui.common.components.TitledCard
import com.geeksville.mesh.ui.connections.components.BLEDevices
import com.geeksville.mesh.ui.connections.components.ConnectionsSegmentedBar
import com.geeksville.mesh.ui.connections.components.CurrentlyConnectedInfo
@ -83,6 +82,7 @@ import org.meshtastic.core.database.model.Node
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.TitledCard
fun String?.isIPAddress(): Boolean = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
@Suppress("DEPRECATION")

View file

@ -49,11 +49,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.DeviceListEntry
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.ui.common.components.TitledCard
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.MultiplePermissionsState
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.TitledCard
/**
* Composable that displays a list of Bluetooth Low Energy (BLE) devices and allows scanning. It handles Bluetooth

View file

@ -33,9 +33,9 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.connections.DeviceType
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
@Suppress("LambdaParameterEventTrailing")
@Composable

View file

@ -43,13 +43,13 @@ 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.common.components.MaterialBatteryInfo
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.node.components.NodeChip
import com.geeksville.mesh.ui.node.components.NodeMenuAction
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.theme.AppTheme
import org.meshtastic.core.ui.theme.StatusColors.StatusRed
@Composable
fun CurrentlyConnectedInfo(

View file

@ -36,7 +36,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.ui.theme.AppTheme
@Composable
fun EmptyStateContent(imageVector: ImageVector? = null, text: String, actionButton: @Composable (() -> Unit)? = null) {

View file

@ -55,11 +55,11 @@ import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.DeviceListEntry
import com.geeksville.mesh.repository.network.NetworkRepository
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.ui.common.components.TitledCard
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.connections.isIPAddress
import kotlinx.coroutines.launch
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.TitledCard
import org.meshtastic.core.ui.theme.AppTheme
@OptIn(ExperimentalMaterial3Api::class)
@Suppress("MagicNumber", "LongMethod")

View file

@ -38,14 +38,14 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.ui.TopLevelDestination
import com.geeksville.mesh.ui.common.icons.Device
import com.geeksville.mesh.ui.common.icons.MeshtasticIcons
import com.geeksville.mesh.ui.common.icons.NoDevice
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow
import com.geeksville.mesh.ui.connections.DeviceType
import org.meshtastic.core.ui.icon.Device
import org.meshtastic.core.ui.icon.MeshtasticIcons
import org.meshtastic.core.ui.icon.NoDevice
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.ui.theme.StatusColors.StatusGreen
import org.meshtastic.core.ui.theme.StatusColors.StatusRed
import org.meshtastic.core.ui.theme.StatusColors.StatusYellow
@Composable
fun TopLevelNavIcon(destination: TopLevelDestination, connectionState: ConnectionState, deviceType: DeviceType?) {

View file

@ -26,9 +26,9 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.DeviceListEntry
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.ui.common.components.TitledCard
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.TitledCard
import org.meshtastic.core.ui.theme.AppTheme
@Composable
fun UsbDevices(

View file

@ -52,8 +52,8 @@ import androidx.compose.ui.unit.dp
import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.model.Contact
import com.geeksville.mesh.ui.common.components.SecurityIcon
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
@Suppress("LongMethod")
@Composable

View file

@ -73,7 +73,6 @@ import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.size
import androidx.compose.ui.unit.sp
import androidx.datastore.core.IOException
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
@ -81,15 +80,15 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.android.BuildUtils.warn
import com.geeksville.mesh.model.DebugViewModel
import com.geeksville.mesh.model.DebugViewModel.UiMeshLog
import com.geeksville.mesh.ui.common.components.CopyIconButton
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
import com.geeksville.mesh.ui.common.theme.AnnotationColor
import com.geeksville.mesh.ui.common.theme.AppTheme
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.CopyIconButton
import org.meshtastic.core.ui.component.SimpleAlertDialog
import org.meshtastic.core.ui.theme.AnnotationColor
import org.meshtastic.core.ui.theme.AppTheme
import java.io.OutputStreamWriter
import java.nio.charset.StandardCharsets
import java.text.SimpleDateFormat

View file

@ -57,8 +57,8 @@ import com.geeksville.mesh.model.DebugViewModel
import com.geeksville.mesh.model.DebugViewModel.UiMeshLog
import com.geeksville.mesh.model.LogSearchManager.SearchMatch
import com.geeksville.mesh.model.LogSearchManager.SearchState
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
@Composable
internal fun DebugSearchNavigation(

View file

@ -98,7 +98,6 @@ import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.model.getChannel
import com.geeksville.mesh.ui.common.components.SecurityIcon
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.node.components.NodeKeyStatusIcon
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import com.geeksville.mesh.ui.sharing.SharedContactDialog
@ -109,6 +108,7 @@ import org.meshtastic.core.database.model.Message
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
import java.nio.charset.StandardCharsets
private const val MESSAGE_CHARACTER_LIMIT_BYTES = 200

View file

@ -71,12 +71,12 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.common.components.dragContainer
import com.geeksville.mesh.ui.common.components.dragDropItemsIndexed
import com.geeksville.mesh.ui.common.components.rememberDragDropState
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.database.entity.QuickChatAction
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.dragContainer
import org.meshtastic.core.ui.component.dragDropItemsIndexed
import org.meshtastic.core.ui.component.rememberDragDropState
import org.meshtastic.core.ui.theme.AppTheme
@Composable
internal fun QuickChatScreen(modifier: Modifier = Modifier, viewModel: UIViewModel = hiltViewModel()) {

View file

@ -49,12 +49,7 @@ 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.components.MDText
import com.geeksville.mesh.ui.common.components.Rssi
import com.geeksville.mesh.ui.common.components.Snr
import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.MessageItemColors
import com.geeksville.mesh.ui.node.components.NodeChip
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import org.meshtastic.core.database.entity.Reaction
@ -62,6 +57,11 @@ 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.Rssi
import org.meshtastic.core.ui.component.Snr
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.ui.theme.MessageItemColors
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable

View file

@ -52,9 +52,9 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.ui.common.components.BottomSheetDialog
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.database.entity.Reaction
import org.meshtastic.core.ui.component.BottomSheetDialog
import org.meshtastic.core.ui.theme.AppTheme
@Composable
private fun ReactionItem(emoji: String, emojiCount: Int = 1, onClick: () -> Unit = {}, onLongClick: () -> Unit = {}) {

View file

@ -63,14 +63,6 @@ import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.TimeFrame
import com.geeksville.mesh.ui.common.components.BatteryInfo
import com.geeksville.mesh.ui.common.components.OptionLabel
import com.geeksville.mesh.ui.common.components.SlidingSelector
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.GraphColors.Cyan
import com.geeksville.mesh.ui.common.theme.GraphColors.Green
import com.geeksville.mesh.ui.common.theme.GraphColors.Magenta
import com.geeksville.mesh.ui.common.theme.GraphColors.Red
import com.geeksville.mesh.ui.metrics.CommonCharts.DATE_TIME_FORMAT
import com.geeksville.mesh.ui.metrics.CommonCharts.MAX_PERCENT_VALUE
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
@ -78,6 +70,13 @@ import com.geeksville.mesh.util.GraphUtil
import com.geeksville.mesh.util.GraphUtil.createPath
import com.geeksville.mesh.util.GraphUtil.plotPoint
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.BatteryInfo
import org.meshtastic.core.ui.component.OptionLabel
import org.meshtastic.core.ui.component.SlidingSelector
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.ui.theme.GraphColors.Cyan
import org.meshtastic.core.ui.theme.GraphColors.Green
import org.meshtastic.core.ui.theme.GraphColors.Magenta
private const val CHART_WEIGHT = 1f
private const val Y_AXIS_WEIGHT = 0.1f

View file

@ -53,14 +53,14 @@ import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.copy
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.TimeFrame
import com.geeksville.mesh.ui.common.components.IaqDisplayMode
import com.geeksville.mesh.ui.common.components.IndoorAirQuality
import com.geeksville.mesh.ui.common.components.OptionLabel
import com.geeksville.mesh.ui.common.components.SlidingSelector
import com.geeksville.mesh.ui.metrics.CommonCharts.DATE_TIME_FORMAT
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
import org.meshtastic.core.model.util.UnitConversions.celsiusToFahrenheit
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.IaqDisplayMode
import org.meshtastic.core.ui.component.IndoorAirQuality
import org.meshtastic.core.ui.component.OptionLabel
import org.meshtastic.core.ui.component.SlidingSelector
@Composable
fun EnvironmentMetricsScreen(viewModel: MetricsViewModel = hiltViewModel()) {

View file

@ -55,10 +55,10 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.TelemetryProtos
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.metrics.CommonCharts.DATE_TIME_FORMAT
import org.meshtastic.core.model.util.formatUptime
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
import java.text.DecimalFormat
@OptIn(ExperimentalFoundationApi::class)

View file

@ -57,11 +57,11 @@ import com.geeksville.mesh.PaxcountProtos
import com.geeksville.mesh.Portnums.PortNum
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.TimeFrame
import com.geeksville.mesh.ui.common.components.OptionLabel
import com.geeksville.mesh.ui.common.components.SlidingSelector
import org.meshtastic.core.database.entity.MeshLog
import org.meshtastic.core.model.util.formatUptime
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.OptionLabel
import org.meshtastic.core.ui.component.SlidingSelector
import java.text.DateFormat
import java.util.Date

View file

@ -64,10 +64,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig.DisplayUnits
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.model.util.metersIn
import org.meshtastic.core.model.util.toString
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
import java.text.DateFormat
import kotlin.time.Duration.Companion.days

View file

@ -62,15 +62,15 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.TimeFrame
import com.geeksville.mesh.ui.common.components.OptionLabel
import com.geeksville.mesh.ui.common.components.SlidingSelector
import com.geeksville.mesh.ui.common.theme.GraphColors.InfantryBlue
import com.geeksville.mesh.ui.common.theme.GraphColors.Red
import com.geeksville.mesh.ui.metrics.CommonCharts.DATE_TIME_FORMAT
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
import com.geeksville.mesh.util.GraphUtil
import com.geeksville.mesh.util.GraphUtil.createPath
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.OptionLabel
import org.meshtastic.core.ui.component.SlidingSelector
import org.meshtastic.core.ui.theme.GraphColors.InfantryBlue
import org.meshtastic.core.ui.theme.GraphColors.Red
import kotlin.math.ceil
import kotlin.math.floor

View file

@ -59,14 +59,14 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.MeshProtos.MeshPacket
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.TimeFrame
import com.geeksville.mesh.ui.common.components.LoraSignalIndicator
import com.geeksville.mesh.ui.common.components.OptionLabel
import com.geeksville.mesh.ui.common.components.SlidingSelector
import com.geeksville.mesh.ui.common.components.SnrAndRssi
import com.geeksville.mesh.ui.metrics.CommonCharts.DATE_TIME_FORMAT
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
import com.geeksville.mesh.util.GraphUtil.plotPoint
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.LoraSignalIndicator
import org.meshtastic.core.ui.component.OptionLabel
import org.meshtastic.core.ui.component.SlidingSelector
import org.meshtastic.core.ui.component.SnrAndRssi
@Suppress("MagicNumber")
private enum class Metric(val color: Color, val min: Float, val max: Float) {

View file

@ -58,12 +58,12 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
import org.meshtastic.core.model.fullRouteDiscovery
import org.meshtastic.core.model.getTracerouteResponse
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.SimpleAlertDialog
import org.meshtastic.core.ui.theme.AppTheme
import java.text.DateFormat
@OptIn(ExperimentalFoundationApi::class)

View file

@ -134,13 +134,7 @@ import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.service.ServiceAction
import com.geeksville.mesh.ui.common.components.MainAppBar
import com.geeksville.mesh.ui.common.components.TitledCard
import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusOrange
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow
import com.geeksville.mesh.ui.node.components.NodeActionDialogs
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import com.geeksville.mesh.ui.node.components.TracerouteButton
@ -168,6 +162,12 @@ import org.meshtastic.core.navigation.NodeDetailRoutes
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.TitledCard
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
private data class VectorMetricInfo(
@StringRes val label: Int,

View file

@ -49,7 +49,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.ui.common.components.MainAppBar
import com.geeksville.mesh.ui.common.components.rememberTimeTickWithLifecycle
import com.geeksville.mesh.ui.node.components.NodeFilterTextField
import com.geeksville.mesh.ui.node.components.NodeItem
import com.geeksville.mesh.ui.node.components.NodeMenuAction
@ -60,6 +59,7 @@ import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.DeviceVersion
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.rememberTimeTickWithLifecycle
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3ExpressiveApi::class)
@Suppress("LongMethod", "CyclomaticComplexMethod")

View file

@ -31,8 +31,8 @@ import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.model.util.formatAgo
import org.meshtastic.core.ui.theme.AppTheme
@Composable
fun LastHeardInfo(modifier: Modifier = Modifier, lastHeard: Int, currentTimeMillis: Long) {

View file

@ -41,10 +41,10 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.core.net.toUri
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.HyperlinkBlue
import kotlinx.coroutines.launch
import org.meshtastic.core.model.util.GPSFormat
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.ui.theme.HyperlinkBlue
import java.net.URLEncoder
@OptIn(ExperimentalFoundationApi::class)

View file

@ -57,9 +57,9 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.preview.LargeFontPreview
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.database.model.NodeSortOption
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
@Suppress("LongParameterList")
@Composable

View file

@ -51,14 +51,14 @@ import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ConfigProtos.Config.DeviceConfig
import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.ui.common.components.BatteryInfo
import com.geeksville.mesh.ui.common.components.SignalInfo
import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
import com.geeksville.mesh.ui.common.theme.AppTheme
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.BatteryInfo
import org.meshtastic.core.ui.theme.AppTheme
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable

View file

@ -54,14 +54,14 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.geeksville.mesh.ui.common.components.CopyIconButton
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow
import com.google.protobuf.ByteString
import org.meshtastic.core.model.Channel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.CopyIconButton
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.ui.theme.StatusColors.StatusGreen
import org.meshtastic.core.ui.theme.StatusColors.StatusRed
import org.meshtastic.core.ui.theme.StatusColors.StatusYellow
@Composable
private fun KeyStatusDialog(@StringRes title: Int, @StringRes text: Int, key: ByteString?, onDismiss: () -> Unit = {}) =

View file

@ -38,10 +38,10 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.database.model.isUnmessageableRole
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.SimpleAlertDialog
@Suppress("LongMethod")
@Composable

View file

@ -39,10 +39,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.StatusColors.StatusGreen
import org.meshtastic.core.ui.theme.StatusColors.StatusRed
import org.meshtastic.core.ui.theme.StatusColors.StatusYellow
@Suppress("LongMethod")
@OptIn(ExperimentalMaterial3Api::class)

View file

@ -30,17 +30,14 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.ui.theme.AppTheme
@Composable
fun SatelliteCountInfo(
modifier: Modifier = Modifier,
satCount: Int,
) {
fun SatelliteCountInfo(modifier: Modifier = Modifier, satCount: Int) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Icon(
modifier = Modifier.size(18.dp),
@ -59,9 +56,5 @@ fun SatelliteCountInfo(
@PreviewLightDark
@Composable
fun SatelliteCountInfoPreview() {
AppTheme {
SatelliteCountInfo(
satCount = 5,
)
}
AppTheme { SatelliteCountInfo(satCount = 5) }
}

View file

@ -34,9 +34,9 @@ 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.common.theme.AppTheme
import com.geeksville.mesh.ui.settings.components.SettingsItem
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
private const val COOL_DOWN_TIME_MS = 30000L

View file

@ -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.common.components.MultipleChoiceAlertDialog
import com.geeksville.mesh.ui.common.components.TitledCard
import com.geeksville.mesh.ui.common.theme.MODE_DYNAMIC
import com.geeksville.mesh.ui.node.components.NodeMenuAction
import com.geeksville.mesh.ui.settings.components.SettingsItem
import com.geeksville.mesh.ui.settings.components.SettingsItemDetail
@ -78,6 +75,9 @@ import com.google.accompanist.permissions.rememberMultiplePermissionsState
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.TitledCard
import org.meshtastic.core.ui.theme.MODE_DYNAMIC
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

View file

@ -38,7 +38,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.ui.theme.AppTheme
/** A clickable settings button item. */
@Composable

View file

@ -44,14 +44,14 @@ 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.common.components.TitledCard
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
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.TitledCard
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.ui.theme.StatusColors.StatusRed
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable

View file

@ -28,11 +28,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun AmbientLightingConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -30,11 +30,11 @@ import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.AudioConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.DropDownPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun AudioConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -30,11 +30,11 @@ import com.geeksville.mesh.ConfigProtos.Config.BluetoothConfig
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.DropDownPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun BluetoothConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -36,11 +36,11 @@ import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.CannedMessageConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.DropDownPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun CannedMessageConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -73,16 +73,16 @@ import androidx.navigation.NavController
import com.geeksville.mesh.ChannelProtos.ChannelSettings
import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig
import com.geeksville.mesh.channelSettings
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.PreferenceFooter
import com.geeksville.mesh.ui.common.components.SecurityIcon
import com.geeksville.mesh.ui.common.components.dragContainer
import com.geeksville.mesh.ui.common.components.dragDropItemsIndexed
import com.geeksville.mesh.ui.common.components.rememberDragDropState
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.model.Channel
import org.meshtastic.core.model.DeviceVersion
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.PreferenceFooter
import org.meshtastic.core.ui.component.dragContainer
import org.meshtastic.core.ui.component.dragDropItemsIndexed
import org.meshtastic.core.ui.component.rememberDragDropState
@Composable
private fun ChannelItem(

View file

@ -33,11 +33,11 @@ import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.DropDownPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun DetectionSensorConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -51,11 +51,11 @@ import com.geeksville.mesh.ConfigProtos.Config.DeviceConfig
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.DropDownPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
private val DeviceConfig.Role.description: Int
get() =

View file

@ -30,11 +30,11 @@ import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.DropDownPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun DisplayConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -46,11 +46,11 @@ import com.geeksville.mesh.ChannelProtos
import com.geeksville.mesh.channelSettings
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.EditBase64Preference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PositionPrecisionPreference
import com.geeksville.mesh.ui.common.components.SwitchPreference
import org.meshtastic.core.model.Channel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.SwitchPreference
@Suppress("LongMethod")
@Composable

View file

@ -41,9 +41,9 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ClientOnlyProtos.DeviceProfile
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.google.protobuf.Descriptors
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.SwitchPreference
private const val SUPPORTED_FIELDS = 7

View file

@ -34,12 +34,12 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.common.components.TextDividerPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
import org.meshtastic.core.ui.component.TextDividerPreference
@Composable
fun ExternalNotificationConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -33,15 +33,15 @@ import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.DropDownPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SignedIntegerEditTextPreference
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.model.Channel
import org.meshtastic.core.model.RegionInfo
import org.meshtastic.core.model.numChannels
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SignedIntegerEditTextPreference
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun LoRaConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -33,12 +33,12 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.EditPasswordPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditPasswordPreference
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun MQTTConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -40,12 +40,12 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.common.components.precisionBitsToMeters
import org.meshtastic.core.model.util.DistanceUnit
import org.meshtastic.core.model.util.toDistanceString
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.SwitchPreference
import kotlin.math.roundToInt
private const val POSITION_PRECISION_MIN = 12

View file

@ -28,11 +28,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun NeighborInfoConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -44,16 +44,16 @@ import com.geeksville.mesh.ConfigProtos.Config.NetworkConfig
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.DropDownPreference
import com.geeksville.mesh.ui.common.components.EditIPv4Preference
import com.geeksville.mesh.ui.common.components.EditPasswordPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanOptions
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditIPv4Preference
import org.meshtastic.core.ui.component.EditPasswordPreference
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SimpleAlertDialog
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
private fun ScanErrorDialog(onDismiss: () -> Unit = {}) =

View file

@ -28,12 +28,12 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SignedIntegerEditTextPreference
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SignedIntegerEditTextPreference
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun PaxcounterConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -43,17 +43,17 @@ import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.ConfigProtos.Config.PositionConfig
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.BitwisePreference
import com.geeksville.mesh.ui.common.components.DropDownPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberPermissionState
import kotlinx.coroutines.launch
import org.meshtastic.core.model.Position
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.BitwisePreference
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@OptIn(ExperimentalPermissionsApi::class)
@Composable

View file

@ -28,11 +28,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun PowerConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -26,9 +26,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import com.geeksville.mesh.ui.common.components.MainAppBar
import com.geeksville.mesh.ui.common.components.PreferenceFooter
import com.geeksville.mesh.ui.settings.radio.ResponseState
import com.google.protobuf.MessageLite
import org.meshtastic.core.ui.component.PreferenceFooter
@Composable
fun <T : MessageLite> RadioConfigScreenList(

View file

@ -28,11 +28,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun RangeTestConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -29,10 +29,10 @@ import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.EditListPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun RemoteHardwareConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -46,17 +46,17 @@ import androidx.navigation.NavController
import com.geeksville.mesh.ConfigProtos.Config.SecurityConfig
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.CopyIconButton
import com.geeksville.mesh.ui.common.components.EditBase64Preference
import com.geeksville.mesh.ui.common.components.EditListPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.node.NodeActionButton
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import com.geeksville.mesh.util.encodeToString
import com.geeksville.mesh.util.toByteString
import com.google.protobuf.ByteString
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.CopyIconButton
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
import java.security.SecureRandom
@OptIn(ExperimentalMaterial3ExpressiveApi::class)

View file

@ -30,11 +30,11 @@ import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.SerialConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.DropDownPreference
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun SerialConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -28,11 +28,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun StoreForwardConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -28,11 +28,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.moduleConfig
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun TelemetryConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -30,14 +30,14 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.EditTextPreference
import com.geeksville.mesh.ui.common.components.PreferenceCategory
import com.geeksville.mesh.ui.common.components.RegularPreference
import com.geeksville.mesh.ui.common.components.SwitchPreference
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import org.meshtastic.core.database.model.isUnmessageableRole
import org.meshtastic.core.model.DeviceVersion
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.EditTextPreference
import org.meshtastic.core.ui.component.PreferenceCategory
import org.meshtastic.core.ui.component.RegularPreference
import org.meshtastic.core.ui.component.SwitchPreference
@Composable
fun UserConfigScreen(navController: NavController, viewModel: RadioConfigViewModel = hiltViewModel()) {

View file

@ -28,8 +28,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
@Composable
fun WarningDialog(

View file

@ -102,8 +102,6 @@ import com.geeksville.mesh.model.toChannelSet
import com.geeksville.mesh.navigation.ConfigRoute
import com.geeksville.mesh.navigation.getNavRouteFrom
import com.geeksville.mesh.service.ConnectionState
import com.geeksville.mesh.ui.common.components.AdaptiveTwoPane
import com.geeksville.mesh.ui.common.components.PreferenceFooter
import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel
import com.geeksville.mesh.ui.settings.radio.components.ChannelSelection
import com.geeksville.mesh.ui.settings.radio.components.PacketResponseStateDialog
@ -116,6 +114,8 @@ import kotlinx.coroutines.launch
import org.meshtastic.core.model.Channel
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.AdaptiveTwoPane
import org.meshtastic.core.ui.component.PreferenceFooter
/**
* Composable screen for managing and sharing Meshtastic channels. Allows users to view, edit, and share channel

View file

@ -55,8 +55,6 @@ import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.BuildUtils.errormsg
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.common.components.CopyIconButton
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
@ -71,6 +69,8 @@ import com.journeyapps.barcodescanner.ScanOptions
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.model.DeviceVersion
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.CopyIconButton
import org.meshtastic.core.ui.component.SimpleAlertDialog
import timber.log.Timber
import java.net.MalformedURLException

View file

@ -41,9 +41,9 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.model.Contact
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.contact.ContactItem
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.AppTheme
@Composable
fun ShareScreen(viewModel: UIViewModel = hiltViewModel(), onConfirm: (String) -> Unit) {

28
core/ui/build.gradle.kts Normal file
View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
alias(libs.plugins.meshtastic.android.library)
alias(libs.plugins.meshtastic.android.library.compose)
}
android { namespace = "org.meshtastic.core.ui" }
dependencies {
implementation(projects.core.strings)
implementation(libs.bundles.markdown)
}

View file

@ -0,0 +1,57 @@
<?xml version="1.0" ?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>ComposableParamOrder:AlertDialogs.kt$SimpleAlertDialog</ID>
<ID>ComposableParamOrder:BatteryInfo.kt$BatteryInfo</ID>
<ID>ComposableParamOrder:EditTextPreference.kt$EditTextPreference</ID>
<ID>ComposableParamOrder:MaterialBatteryInfo.kt$MaterialBatteryInfo</ID>
<ID>ComposableParamOrder:SwitchPreference.kt$SwitchPreference</ID>
<ID>ContentSlotReused:AdaptiveTwoPane.kt$second</ID>
<ID>MagicNumber:BatteryInfo.kt$100</ID>
<ID>MagicNumber:BatteryInfo.kt$101</ID>
<ID>MagicNumber:BatteryInfo.kt$14</ID>
<ID>MagicNumber:BatteryInfo.kt$15</ID>
<ID>MagicNumber:BatteryInfo.kt$34</ID>
<ID>MagicNumber:BatteryInfo.kt$35</ID>
<ID>MagicNumber:BatteryInfo.kt$4</ID>
<ID>MagicNumber:BatteryInfo.kt$5</ID>
<ID>MagicNumber:BatteryInfo.kt$79</ID>
<ID>MagicNumber:BatteryInfo.kt$80</ID>
<ID>MagicNumber:EditIPv4Preference.kt$0xff</ID>
<ID>MagicNumber:EditIPv4Preference.kt$16</ID>
<ID>MagicNumber:EditIPv4Preference.kt$24</ID>
<ID>MagicNumber:EditIPv4Preference.kt$8</ID>
<ID>MagicNumber:LazyColumnDragAndDropDemo.kt$50</ID>
<ID>ModifierMissing:AdaptiveTwoPane.kt$AdaptiveTwoPane</ID>
<ID>ModifierMissing:IndoorAirQuality.kt$IndoorAirQuality</ID>
<ID>ModifierMissing:LoraSignalIndicator.kt$LoraSignalIndicator</ID>
<ID>ModifierMissing:LoraSignalIndicator.kt$Rssi</ID>
<ID>ModifierMissing:LoraSignalIndicator.kt$Snr</ID>
<ID>ModifierMissing:LoraSignalIndicator.kt$SnrAndRssi</ID>
<ID>ModifierMissing:SimpleAlertDialog.kt$SimpleAlertDialog</ID>
<ID>ModifierMissing:SlidingSelector.kt$OptionLabel</ID>
<ID>ModifierNotUsedAtRoot:TextDividerPreference.kt$modifier = modifier.fillMaxWidth().padding(all = 16.dp)</ID>
<ID>ModifierNotUsedAtRoot:TextDividerPreference.kt$modifier = modifier.fillMaxWidth().wrapContentWidth(Alignment.End)</ID>
<ID>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() } } }</ID>
<ID>ModifierReused:PreferenceCategory.kt$Text( text, modifier = modifier.padding(start = 16.dp, top = 24.dp, bottom = 8.dp, end = 16.dp), style = MaterialTheme.typography.titleLarge, )</ID>
<ID>ModifierReused:TextDividerPreference.kt$Card(modifier = modifier.fillMaxWidth()) { Row(modifier = modifier.fillMaxWidth().padding(all = 16.dp), verticalAlignment = Alignment.CenterVertically) { Text( text = title, style = MaterialTheme.typography.bodyLarge, color = if (!enabled) { MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) } else { Color.Unspecified }, ) if (trailingIcon != null) { Icon(trailingIcon, "trailingIcon", modifier = modifier.fillMaxWidth().wrapContentWidth(Alignment.End)) } } }</ID>
<ID>ModifierReused:TextDividerPreference.kt$Icon(trailingIcon, "trailingIcon", modifier = modifier.fillMaxWidth().wrapContentWidth(Alignment.End))</ID>
<ID>ModifierReused:TextDividerPreference.kt$Row(modifier = modifier.fillMaxWidth().padding(all = 16.dp), verticalAlignment = Alignment.CenterVertically) { Text( text = title, style = MaterialTheme.typography.bodyLarge, color = if (!enabled) { MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) } else { Color.Unspecified }, ) if (trailingIcon != null) { Icon(trailingIcon, "trailingIcon", modifier = modifier.fillMaxWidth().wrapContentWidth(Alignment.End)) } }</ID>
<ID>MultipleEmitters:PreferenceCategory.kt$PreferenceCategory</ID>
<ID>ParameterNaming:BitwisePreference.kt$onItemSelected</ID>
<ID>ParameterNaming:EditIPv4Preference.kt$onValueChanged</ID>
<ID>ParameterNaming:EditPasswordPreference.kt$onValueChanged</ID>
<ID>ParameterNaming:EditTextPreference.kt$onValueChanged</ID>
<ID>ParameterNaming:PreferenceFooter.kt$onCancelClicked</ID>
<ID>ParameterNaming:PreferenceFooter.kt$onNegativeClicked</ID>
<ID>ParameterNaming:PreferenceFooter.kt$onPositiveClicked</ID>
<ID>ParameterNaming:PreferenceFooter.kt$onSaveClicked</ID>
<ID>ParameterNaming:SlidingSelector.kt$onOptionSelected</ID>
<ID>PreviewPublic:BatteryInfo.kt$BatteryInfoPreview</ID>
<ID>PreviewPublic:BatteryInfo.kt$BatteryInfoPreviewSimple</ID>
<ID>PreviewPublic:IndoorAirQuality.kt$IAQScalePreview</ID>
<ID>PreviewPublic:LazyColumnDragAndDropDemo.kt$LazyColumnDragAndDropDemo</ID>
<ID>PreviewPublic:MaterialBatteryInfo.kt$MaterialBatteryInfoPreview</ID>
</CurrentIssues>
</SmellBaseline>

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
@ -26,24 +26,20 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun AdaptiveTwoPane(
first: @Composable ColumnScope.() -> Unit,
second: @Composable ColumnScope.() -> Unit,
) = BoxWithConstraints {
val compactWidth = maxWidth < 600.dp
Row {
Column(modifier = Modifier.weight(1f)) {
first()
if (compactWidth) {
second()
}
}
if (!compactWidth) {
fun AdaptiveTwoPane(first: @Composable ColumnScope.() -> Unit, second: @Composable ColumnScope.() -> Unit) =
BoxWithConstraints {
val compactWidth = maxWidth < 600.dp
Row {
Column(modifier = Modifier.weight(1f)) {
second()
first()
if (compactWidth) {
second()
}
}
if (!compactWidth) {
Column(modifier = Modifier.weight(1f)) { second() }
}
}
}
}

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height
@ -32,8 +32,8 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.common.theme.AppTheme
import org.meshtastic.core.ui.R
import org.meshtastic.core.ui.theme.AppTheme
@Composable
fun BatteryInfo(modifier: Modifier = Modifier, batteryLevel: Int?, voltage: Float?) {

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -40,30 +40,28 @@ import androidx.compose.ui.window.DialogProperties
fun BottomSheetDialog(
onDismiss: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit
) = Dialog(
onDismissRequest = onDismiss,
properties = DialogProperties(usePlatformDefaultWidth = false),
) {
content: @Composable ColumnScope.() -> Unit,
) = Dialog(onDismissRequest = onDismiss, properties = DialogProperties(usePlatformDefaultWidth = false)) {
Box(
modifier = Modifier
.fillMaxSize()
modifier =
Modifier.fillMaxSize()
.background(Color.Transparent)
.clickable(
onClick = onDismiss,
indication = null,
interactionSource = remember { MutableInteractionSource() }
)
interactionSource = remember { MutableInteractionSource() },
),
) {
Column(
modifier = modifier
modifier =
modifier
.align(Alignment.BottomCenter)
.background(
color = MaterialTheme.colorScheme.surface.copy(alpha = 1f),
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
)
.padding(16.dp),
content = content
content = content,
)
}
}

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.annotation.StringRes
import androidx.compose.foundation.interaction.MutableInteractionSource

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import android.content.ClipData
import androidx.compose.material.icons.Icons

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
@ -40,15 +40,14 @@ fun EditIPv4Preference(
) {
val pattern = """\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b""".toRegex()
fun convertIntToIpAddress(int: Int): String {
return "${int and 0xff}.${int shr 8 and 0xff}.${int shr 16 and 0xff}.${int shr 24 and 0xff}"
}
fun convertIntToIpAddress(int: Int): String =
"${int and 0xff}.${int shr 8 and 0xff}.${int shr 16 and 0xff}.${int shr 24 and 0xff}"
fun convertIpAddressToInt(ipAddress: String): Int? = ipAddress.split(".")
.map { it.toIntOrNull() }.reversed() // little-endian byte order
.fold(0) { total, next ->
if (next == null) return null else total shl 8 or next
}
fun convertIpAddressToInt(ipAddress: String): Int? = ipAddress
.split(".")
.map { it.toIntOrNull() }
.reversed() // little-endian byte order
.fold(0) { total, next -> if (next == null) return null else total shl 8 or next }
var valueState by remember(value) { mutableStateOf(convertIntToIpAddress(value)) }
@ -57,16 +56,14 @@ fun EditIPv4Preference(
value = valueState,
enabled = enabled,
isError = convertIntToIpAddress(value) != valueState,
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number, imeAction = ImeAction.Done
),
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = keyboardActions,
onValueChanged = {
valueState = it
if (pattern.matches(it)) convertIpAddressToInt(it)?.let { int -> onValueChanged(int) }
},
onFocusChanged = {},
modifier = modifier
modifier = modifier,
)
}
@ -78,6 +75,6 @@ private fun EditIPv4PreferencePreview() {
value = 16820416,
enabled = true,
keyboardActions = KeyboardActions {},
onValueChanged = {}
onValueChanged = {},
)
}

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -57,15 +57,15 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQDangerouslyPolluted
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQExcellent
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQExtremelyPolluted
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQGood
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQHeavilyPolluted
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQLightlyPolluted
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQModeratelyPolluted
import com.geeksville.mesh.ui.common.theme.IAQColors.IAQSeverelyPolluted
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.theme.IAQColors.IAQDangerouslyPolluted
import org.meshtastic.core.ui.theme.IAQColors.IAQExcellent
import org.meshtastic.core.ui.theme.IAQColors.IAQExtremelyPolluted
import org.meshtastic.core.ui.theme.IAQColors.IAQGood
import org.meshtastic.core.ui.theme.IAQColors.IAQHeavilyPolluted
import org.meshtastic.core.ui.theme.IAQColors.IAQLightlyPolluted
import org.meshtastic.core.ui.theme.IAQColors.IAQModeratelyPolluted
import org.meshtastic.core.ui.theme.IAQColors.IAQSeverelyPolluted
@Suppress("MagicNumber")
enum class Iaq(val color: Color, val description: String, val range: IntRange) {

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.Spring
@ -60,43 +60,36 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
// Derived in part from: https://github.com/androidx/androidx/blob/c92ad2941368202b2d78b8d14c71bf81e9525944/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LazyColumnDragAndDropDemo.kt
// Derived in part from:
// https://github.com/androidx/androidx/blob/c92ad2941368202b2d78b8d14c71bf81e9525944/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LazyColumnDragAndDropDemo.kt
@Preview
@Composable
fun LazyColumnDragAndDropDemo() {
var list by remember { mutableStateOf(List(50) { it }) }
val listState = rememberLazyListState()
val dragDropState = rememberDragDropState(listState, headerCount = 1) { fromIndex, toIndex ->
if (fromIndex in list.indices && toIndex in list.indices) {
list = list.toMutableList().apply { add(toIndex, removeAt(fromIndex)) }
}
}
LazyColumn(
modifier = Modifier.dragContainer(
dragDropState = dragDropState,
haptics = LocalHapticFeedback.current,
),
state = listState,
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
item {
Text("Header", Modifier.fillMaxWidth().padding(20.dp))
}
itemsIndexed(list, key = { _, item -> item }) { index, item ->
DraggableItem(dragDropState, index + 1) { isDragging ->
Card {
Text("Item $item", Modifier.fillMaxWidth().padding(20.dp))
}
val dragDropState =
rememberDragDropState(listState, headerCount = 1) { fromIndex, toIndex ->
if (fromIndex in list.indices && toIndex in list.indices) {
list = list.toMutableList().apply { add(toIndex, removeAt(fromIndex)) }
}
}
item {
Text("Footer", Modifier.fillMaxWidth().padding(20.dp))
LazyColumn(
modifier = Modifier.dragContainer(dragDropState = dragDropState, haptics = LocalHapticFeedback.current),
state = listState,
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
item { Text("Header", Modifier.fillMaxWidth().padding(20.dp)) }
itemsIndexed(list, key = { _, item -> item }) { index, item ->
DraggableItem(dragDropState, index + 1) { isDragging ->
Card { Text("Item $item", Modifier.fillMaxWidth().padding(20.dp)) }
}
}
item { Text("Footer", Modifier.fillMaxWidth().padding(20.dp)) }
}
}
@ -104,7 +97,7 @@ fun LazyColumnDragAndDropDemo() {
fun rememberDragDropState(
lazyListState: LazyListState,
headerCount: Int = 0,
onMove: (Int, Int) -> Unit
onMove: (Int, Int) -> Unit,
): DragDropState {
val scope = rememberCoroutineScope()
val state = remember(lazyListState) { DragDropState(lazyListState, headerCount, scope, onMove) }
@ -122,19 +115,20 @@ internal constructor(
private val state: LazyListState,
private val headerCount: Int,
private val scope: CoroutineScope,
private val onMove: (Int, Int) -> Unit
private val onMove: (Int, Int) -> Unit,
) {
private var draggingItemIndex by mutableStateOf<Int?>(null)
val adjustedItemIndex get() = draggingItemIndex?.minus(headerCount)
val adjustedItemIndex
get() = draggingItemIndex?.minus(headerCount)
internal val scrollChannel = Channel<Float>()
private var draggingItemDraggedDelta by mutableFloatStateOf(0f)
private var draggingItemInitialOffset by mutableIntStateOf(0)
internal val draggingItemOffset: Float
get() = draggingItemLayoutInfo?.let { item ->
draggingItemInitialOffset + draggingItemDraggedDelta - item.offset
} ?: 0f
get() =
draggingItemLayoutInfo?.let { item -> draggingItemInitialOffset + draggingItemDraggedDelta - item.offset }
?: 0f
private val draggingItemLayoutInfo: LazyListItemInfo?
get() = state.layoutInfo.visibleItemsInfo.firstOrNull { it.index == draggingItemIndex }
@ -146,7 +140,7 @@ internal constructor(
private set
internal fun onDragStart(offset: Offset): LazyListItemInfo? = state.layoutInfo.visibleItemsInfo
.filter { it.contentType == DragDropContentType }
.filter { it.contentType == DRAG_DROP_CONTENT_TYPE }
.firstOrNull { item -> offset.y.toInt() in item.offset..(item.offset + item.size) }
?.also {
draggingItemIndex = it.index
@ -161,7 +155,7 @@ internal constructor(
previousItemOffset.snapTo(startOffset)
previousItemOffset.animateTo(
0f,
spring(stiffness = Spring.StiffnessMediumLow, visibilityThreshold = 1f)
spring(stiffness = Spring.StiffnessMediumLow, visibilityThreshold = 1f),
)
previousIndexOfDraggedItem = null
}
@ -179,33 +173,26 @@ internal constructor(
val endOffset = startOffset + draggingItem.size
val middleOffset = startOffset + (endOffset - startOffset) / 2f
val targetItem = state.layoutInfo.visibleItemsInfo
.find { item ->
middleOffset.toInt() in item.offset..item.offsetEnd &&
draggingItem.index != item.index
val targetItem =
state.layoutInfo.visibleItemsInfo.find { item ->
middleOffset.toInt() in item.offset..item.offsetEnd && draggingItem.index != item.index
}
if (targetItem != null) {
if (
draggingItem.index == state.firstVisibleItemIndex ||
targetItem.index == state.firstVisibleItemIndex
) {
state.requestScrollToItem(
state.firstVisibleItemIndex,
state.firstVisibleItemScrollOffset
)
if (draggingItem.index == state.firstVisibleItemIndex || targetItem.index == state.firstVisibleItemIndex) {
state.requestScrollToItem(state.firstVisibleItemIndex, state.firstVisibleItemScrollOffset)
}
onMove.invoke(draggingItem.index - headerCount, targetItem.index - headerCount)
draggingItemIndex = targetItem.index
} else {
val overscroll = when {
draggingItemDraggedDelta > 0 ->
(endOffset - state.layoutInfo.viewportEndOffset).coerceAtLeast(0f)
val overscroll =
when {
draggingItemDraggedDelta > 0 -> (endOffset - state.layoutInfo.viewportEndOffset).coerceAtLeast(0f)
draggingItemDraggedDelta < 0 ->
(startOffset - state.layoutInfo.viewportStartOffset).coerceAtMost(0f)
draggingItemDraggedDelta < 0 ->
(startOffset - state.layoutInfo.viewportStartOffset).coerceAtMost(0f)
else -> 0f
}
else -> 0f
}
if (overscroll != 0f) {
scrollChannel.trySend(overscroll)
}
@ -216,10 +203,7 @@ internal constructor(
get() = this.offset + this.size
}
fun Modifier.dragContainer(
dragDropState: DragDropState,
haptics: HapticFeedback,
): Modifier {
fun Modifier.dragContainer(dragDropState: DragDropState, haptics: HapticFeedback): Modifier {
return this.pointerInput(dragDropState) {
detectDragGesturesAfterLongPress(
onDrag = { change, offset ->
@ -231,7 +215,7 @@ fun Modifier.dragContainer(
haptics.performHapticFeedback(HapticFeedbackType.LongPress)
},
onDragEnd = { dragDropState.onDragInterrupted() },
onDragCancel = { dragDropState.onDragInterrupted() }
onDragCancel = { dragDropState.onDragInterrupted() },
)
}
}
@ -241,45 +225,42 @@ fun LazyItemScope.DraggableItem(
dragDropState: DragDropState,
index: Int,
modifier: Modifier = Modifier,
content: @Composable ColumnScope.(isDragging: Boolean) -> Unit
content: @Composable ColumnScope.(isDragging: Boolean) -> Unit,
) {
val dragging = index == dragDropState.adjustedItemIndex
val draggingModifier = if (dragging) {
Modifier
.zIndex(1f)
.graphicsLayer { translationY = dragDropState.draggingItemOffset }
} else if (index == dragDropState.previousIndexOfDraggedItem) {
Modifier
.zIndex(1f)
.graphicsLayer { translationY = dragDropState.previousItemOffset.value }
} else {
Modifier.animateItem(fadeInSpec = null, fadeOutSpec = null)
}
val draggingModifier =
if (dragging) {
Modifier.zIndex(1f).graphicsLayer { translationY = dragDropState.draggingItemOffset }
} else if (index == dragDropState.previousIndexOfDraggedItem) {
Modifier.zIndex(1f).graphicsLayer { translationY = dragDropState.previousItemOffset.value }
} else {
Modifier.animateItem(fadeInSpec = null, fadeOutSpec = null)
}
Column(modifier = modifier.then(draggingModifier)) { content(dragging) }
}
const val DragDropContentType = "drag-and-drop"
const val DRAG_DROP_CONTENT_TYPE = "drag-and-drop"
/**
* Extension function for [LazyListScope] with drag-and-drop functionality for indexed items.
*
* Wraps [itemsIndexed] function with [detectDragGesturesAfterLongPress] to enable long-press
* drag gestures and allow items in the list to be reordered using the provided [DragDropState].
* Wraps [itemsIndexed] function with [detectDragGesturesAfterLongPress] to enable long-press drag gestures and allow
* items in the list to be reordered using the provided [DragDropState].
*/
inline fun <T> LazyListScope.dragDropItemsIndexed(
items: List<T>,
dragDropState: DragDropState,
noinline key: ((index: Int, item: T) -> Any)? = null,
crossinline itemContent: @Composable LazyItemScope.(index: Int, item: T, isDragging: Boolean) -> Unit
crossinline itemContent: @Composable LazyItemScope.(index: Int, item: T, isDragging: Boolean) -> Unit,
) = itemsIndexed(
items = items,
key = key,
contentType = { _, _ -> DragDropContentType },
contentType = { _, _ -> DRAG_DROP_CONTENT_TYPE },
itemContent = { index, item ->
DraggableItem(
dragDropState = dragDropState,
index = index,
content = { isDragging -> itemContent(index, item, isDragging) }
content = { isDragging -> itemContent(index, item, isDragging) },
)
}
},
)

View file

@ -17,7 +17,7 @@
@file:Suppress("MagicNumber")
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@ -47,11 +47,11 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusOrange
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow
import org.meshtastic.core.strings.R
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
private const val SNR_GOOD_THRESHOLD = -7f
private const val SNR_FAIR_THRESHOLD = -15f

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
@ -27,11 +27,11 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ui.common.theme.HyperlinkBlue
import com.mikepenz.markdown.compose.components.markdownComponents
import com.mikepenz.markdown.m3.Markdown
import com.mikepenz.markdown.model.DefaultMarkdownColors
import com.mikepenz.markdown.model.DefaultMarkdownTypography
import org.meshtastic.core.ui.theme.HyperlinkBlue
@Composable
fun MDText(

View file

@ -15,16 +15,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.BatteryUnknown
import androidx.compose.material.icons.rounded.BatteryUnknown
import androidx.compose.material.icons.rounded.Power
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
@ -40,13 +36,13 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.ui.common.icons.BatteryEmpty
import com.geeksville.mesh.ui.common.icons.BatteryUnknown
import com.geeksville.mesh.ui.common.icons.MeshtasticIcons
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusOrange
import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed
import org.meshtastic.core.ui.icon.BatteryEmpty
import org.meshtastic.core.ui.icon.BatteryUnknown
import org.meshtastic.core.ui.icon.MeshtasticIcons
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
private const val FORMAT = "%d%%"
private const val SIZE_ICON = 20

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.common.components
package org.meshtastic.core.ui.component
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
@ -35,7 +35,7 @@ import androidx.compose.ui.unit.dp
fun PreferenceCategory(
text: String,
modifier: Modifier = Modifier,
content: (@Composable ColumnScope.() -> Unit)? = null
content: (@Composable ColumnScope.() -> Unit)? = null,
) {
Text(
text,
@ -43,18 +43,12 @@ fun PreferenceCategory(
style = MaterialTheme.typography.titleLarge,
)
if (content != null) {
Card(
modifier = modifier.padding(bottom = 8.dp),
) {
Card(modifier = modifier.padding(bottom = 8.dp)) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 16.dp),
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
ProvideTextStyle(MaterialTheme.typography.bodyLarge) {
content()
}
ProvideTextStyle(MaterialTheme.typography.bodyLarge) { content() }
}
}
}
@ -63,7 +57,5 @@ fun PreferenceCategory(
@Preview(showBackground = true)
@Composable
private fun PreferenceCategoryPreview() {
PreferenceCategory(
text = "Advanced settings"
)
PreferenceCategory(text = "Advanced settings")
}

Some files were not shown because too many files have changed in this diff Show more