Merge branch 'main' into copilot/add-messaging-feature-android-auto

This commit is contained in:
Garth Vander Houwen
2026-04-25 21:40:40 -07:00
committed by GitHub
10 changed files with 83 additions and 16 deletions

View File

@@ -110,8 +110,9 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val
dao.upsertContactSettings(listOf(updated))
}
override suspend fun getQueuedPackets(): List<DataPacket> =
withContext(dispatchers.io) { dbManager.currentDb.value.packetDao().getQueuedPackets() }
override suspend fun getQueuedPackets(): List<DataPacket> = withContext(dispatchers.io) {
dbManager.currentDb.value.packetDao().getAllDataPackets().filter { it.status == MessageStatus.QUEUED }
}
suspend fun insertRoomPacket(packet: RoomPacket) =
withContext(dispatchers.io) { dbManager.currentDb.value.packetDao().insert(packet) }

View File

@@ -338,15 +338,16 @@ interface PacketDao {
)
suspend fun findPacketBySfppHash(hash: ByteString): Packet?
// Fetches all DataPackets for the current node, ordered by time.
// Callers should filter by status in Kotlin (avoids SQLite json_extract dependency).
@Query(
"""
SELECT data FROM packet
WHERE (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
AND json_extract(data, '${"$"}.status') = 'QUEUED'
ORDER BY received_time ASC
""",
)
suspend fun getQueuedPackets(): List<DataPacket>
suspend fun getAllDataPackets(): List<DataPacket>
@Query(
"""

View File

@@ -164,7 +164,7 @@ abstract class CommonPacketDaoTest {
),
)
packetDao.insert(queuedPacket)
val queued = packetDao.getQueuedPackets()
val queued = packetDao.getAllDataPackets().filter { it.status == MessageStatus.QUEUED }
assertNotNull(queued)
assertEquals(1, queued.size)
assertEquals("Queued", queued.first().text)

View File

@@ -114,6 +114,10 @@
<string name="label_short_turbo">Kurze Reichweite - Turbo</string>
<string name="label_short_fast">Kurze Reichweite - Schnell</string>
<string name="label_short_slow">Kurze Reichweite - Langsam</string>
<string name="label_lite_fast">Leicht - Schnell</string>
<string name="label_lite_slow">Leicht - Langsam</string>
<string name="label_narrow_fast">Schmal - Schnell</string>
<string name="label_narrow_slow">Schmal - Langsam</string>
<string name="config_network_wifi_enabled_summary">Durch die Aktivierung von WLAN wird die Bluetooth Verbindung zur App deaktiviert.</string>
<string name="config_network_eth_enabled_summary">Durch Aktivieren von Ethernet wird die Bluetooth Verbindung zur App deaktiviert. TCP Knotenverbindungen sind auf Apple Geräten nicht verfügbar.</string>
<string name="config_network_udp_enabled_summary">Aktivieren Sie die Übertragung von Paketen per UDP über das lokale Netzwerk.</string>
@@ -794,6 +798,13 @@
<string name="request_host_metrics">Host Kennzahlen</string>
<string name="request_pax_metrics">Benutzerzählerdaten</string>
<string name="request_metadata">Metadaten</string>
<string name="refresh_metadata">Metadaten aktualisieren</string>
<string name="establish_session">Verbinden &amp; Verwalten</string>
<string name="establishing_session">Fernverwaltung wird aufgebaut</string>
<string name="session_active">Sitzung aktiv</string>
<string name="session_refresh_required">Aktualisierung erforderlich</string>
<string name="connect_radio_for_remote_admin">Verbinden Sie sich mit einem Funkgerät, um entfernte Knoten zu verwalten.</string>
<string name="remote_admin_unreachable">Knoten nicht erreichbar - erneut versuchen oder Standort wechseln.</string>
<string name="retry">Erneut versuchen</string>
<string name="actions">Aktionen</string>
<string name="firmware">Firmware</string>
@@ -905,10 +916,24 @@
<string name="firmware_edition">Firmware-Version</string>
<string name="recent_network_devices">Kürzliche Netzwerkgeräte</string>
<string name="discovered_network_devices">Entdeckte Netzwerkgeräte</string>
<string name="scan_network_devices">Suche nach Netzwerkgeräten</string>
<string name="scanning_network">Suche...</string>
<string name="scan_bluetooth_devices">Suche nach Bluetoothgeräten</string>
<string name="scanning_bluetooth">Suche...</string>
<string name="bluetooth_available_devices">Verfügbare Bluetooth Geräte</string>
<string name="add_network_device_manually">Gerät manuell hinzufügen.</string>
<string name="no_devices_found">Keine Geräte gefunden</string>
<string name="no_bluetooth_devices_seen">Keine Bluetoothgeräte gefunden</string>
<string name="no_bluetooth_devices_hint">Stelle sicher, daß Du in der Reichweite des Gerätes bist.</string>
<string name="no_network_devices_seen">Kein Netzwerkgerät gefunden</string>
<string name="no_network_devices_hint">Stelle sicher, daß Du im selben Netzwerk bist wie das Gerät.</string>
<string name="no_usb_devices_seen">Kein USB-Gerät gefunden</string>
<string name="no_usb_devices_hint">Verbinde das Gerät über den seriellen Anschluß oder USB.</string>
<string name="nodes_empty_disconnected_title">Kein Gerät verbunden</string>
<string name="nodes_empty_disconnected_hint">Verbinden Sie sich mit einem Gerät, um Knoten in der Nähe zu finden.</string>
<string name="nodes_empty_searching_title">Suche nach Knoten</string>
<string name="nodes_empty_searching_hint">Knoten in der Nähe erscheinen hier, sobald sie erreicht wurden.</string>
<string name="set_up_connection">Verbindung einrichten</string>
<string name="get_started">Erste Schritte</string>
<string name="intro_welcome">Willkommen bei</string>
<string name="stay_connected_anywhere">Bleibe überall in Verbindung</string>
@@ -1228,8 +1253,18 @@
<string name="wifi_provision_ssid_placeholder">Netzwerk eingeben oder auswählen</string>
<string name="wifi_provision_status_applied">WLAN erfolgreich konfiguriert!</string>
<string name="wifi_provision_status_failed">WLAN Konfiguration konnte nicht angewendet werden</string>
<string name="wifi_provision_success_device_connected">Gerät verbunden</string>
<string name="wifi_provision_success_description">Ihr mPWRD-OS Gerät ist dem Wi-Fi-Netzwerk beigetreten.</string>
<string name="wifi_provision_success_ip_address">IP Adresse</string>
<string name="wifi_provision_success_setup_title">Geräteeinrichtung abschließen</string>
<string name="wifi_provision_success_setup_description">Melden Sie sich über SSH an, um den Standardnamen und das Standardpasswort zu ändern.</string>
<string name="wifi_provision_success_username">Benutzername</string>
<string name="wifi_provision_success_ssh_label">SSH Kommando</string>
<string name="wifi_provision_success_ssh_command">ssh %1$s@%2$s</string>
<string name="wifi_provision_success_ssh_unavailable">SSH Kommando verfügbar, nachdem eine IP zugewiesen wurde.</string>
<string name="wifi_provision_success_open_ssh">SSH Client öffnen</string>
<string name="wifi_provision_success_open_ssh_fallback">Wenn sich keine App öffnet, kopieren Sie den SSH Befehl und fügen ihn in Ihren SSH Client ein.</string>
<string name="wifi_provision_success_missing_ip">IP nicht verfügbar</string>
<string name="wifi_provision_success_done">Fertig</string>
<string name="desktop_tray_tooltip">Meshtastic Desktop</string>
<string name="desktop_tray_show">Meshtastic anzeigen</string>

View File

@@ -25,6 +25,8 @@
<string name="via_mqtt">μέσω MQTT</string>
<string name="message_status_enroute">Αναμονή για αναγνώριση</string>
<string name="routing_error_timeout">Λήξη χρονικού ορίου</string>
<string name="routing_error_max_retransmit">Max. Anzahl Wiederholungen erreicht</string>
<string name="routing_error_no_channel">Kein Kanal</string>
<string name="routing_error_bad_request">Εσφαλμένο Αίτημα</string>
<string name="routing_error_pki_unknown_pubkey">Άγνωστο Δημόσιο Κλειδί</string>
<!-- Position Config -->

View File

@@ -805,7 +805,7 @@
<string name="request_pax_metrics">Показники Pax</string>
<string name="request_metadata">Метадані</string>
<string name="refresh_metadata">Оновити метаданні</string>
<string name="session_active">Сессія активна</string>
<string name="session_active">Сесія активна</string>
<string name="retry">Повторити</string>
<string name="actions">Дії</string>
<string name="firmware">Прошивка</string>
@@ -981,7 +981,7 @@
<string name="unset">Невстановлене - 0</string>
<plurals name="relays">
<item quantity="one">Пройшло через %1$d вузол</item>
<item quantity="few">Пройшло через %1$d вузлів</item>
<item quantity="few">Пройшло через %1$d вузли</item>
<item quantity="many">Пройшло через %1$d вузлів</item>
<item quantity="other">Пройшло через %1$d вузли</item>
</plurals>
@@ -1046,6 +1046,18 @@
<string name="back">Назад</string>
<string name="interval_unset">Скинути</string>
<string name="interval_always_on">Завжди увімк.</string>
<plurals name="plurals_seconds">
<item quantity="one">%1$d секунда</item>
<item quantity="few">%1$d секунд</item>
<item quantity="many">%1$d секунд</item>
<item quantity="other">%1$d секунд</item>
</plurals>
<plurals name="plurals_minutes">
<item quantity="one">%1$d хвилина</item>
<item quantity="few">%1$d хвилин</item>
<item quantity="many">%1$d хвилин</item>
<item quantity="other">%1$d хвилин</item>
</plurals>
<plurals name="plurals_hours">
<item quantity="one">%1$d година</item>
<item quantity="few">%1$d години</item>

View File

@@ -52,6 +52,12 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.isShiftPressed
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction
@@ -458,7 +464,18 @@ private fun MessageInput(
val canSend = !isOverLimit && currentText.isNotEmpty() && isEnabled
OutlinedTextField(
modifier = modifier.fillMaxWidth().padding(horizontal = 8.dp, vertical = 4.dp),
modifier =
modifier.fillMaxWidth().padding(horizontal = 8.dp, vertical = 4.dp).onKeyEvent { keyEvent ->
val isEnterNoShift = keyEvent.key == Key.Enter && !keyEvent.isShiftPressed
if (isEnterNoShift) {
if (keyEvent.type == KeyEventType.KeyUp && canSend) {
onSendMessage()
}
true // consume both KeyDown and KeyUp to prevent newline insertion
} else {
false
}
},
state = textFieldState,
lineLimits = TextFieldLineLimits.MultiLine(1, MAX_LINES),
label = { Text(stringResource(Res.string.message_input_label)) },

View File

@@ -18,6 +18,7 @@ package org.meshtastic.feature.widget
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
@@ -36,13 +37,13 @@ import androidx.glance.Image
import androidx.glance.ImageProvider
import androidx.glance.LocalContext
import androidx.glance.LocalSize
import androidx.glance.action.actionStartActivity
import androidx.glance.action.clickable
import androidx.glance.appwidget.CircularProgressIndicator
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.LinearProgressIndicator
import androidx.glance.appwidget.SizeMode
import androidx.glance.appwidget.action.actionRunCallback
import androidx.glance.appwidget.action.actionStartActivity
import androidx.glance.appwidget.components.CircleIconButton
import androidx.glance.appwidget.components.Scaffold
import androidx.glance.appwidget.components.TitleBar
@@ -148,10 +149,8 @@ class LocalStatsWidget :
GlanceModifier.fillMaxSize()
.clickable(
actionStartActivity(
android.content.ComponentName(
context.packageName,
"org.meshtastic.app.MainActivity",
),
context.packageManager.getLaunchIntentForPackage(context.packageName)
?: Intent().setClassName(context.packageName, "org.meshtastic.app.MainActivity"),
),
),
) {

View File

@@ -80,7 +80,7 @@ uri-kmp = "0.0.21"
osmdroid-android = "6.1.20"
spotless = "8.4.0"
wire = "6.2.0"
vico = "3.2.0-next.1"
vico = "3.2.0-next.2"
kable = "0.42.0"
mqttastic = "0.2.0"
jmdns = "3.6.3"
@@ -251,7 +251,7 @@ androidx-room-gradlePlugin = { module = "androidx.room3:room3-gradle-plugin", ve
compose-gradlePlugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" }
compose-multiplatform-gradlePlugin = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "compose-multiplatform" }
datadog-gradlePlugin = { module = "com.datadoghq.dd-sdk-android-gradle-plugin:com.datadoghq.dd-sdk-android-gradle-plugin.gradle.plugin", version.ref = "datadog-gradle" }
detekt-compose = { module = "io.nlopez.compose.rules:detekt", version = "0.5.7" }
detekt-compose = { module = "io.nlopez.compose.rules:detekt", version = "0.5.8" }
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
detekt-gradlePlugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" }
firebase-crashlytics-gradlePlugin = { module = "com.google.firebase:firebase-crashlytics-gradle", version.ref = "firebase-crashlytics-gradle" }