rename Packet to MeshLog

master
andrekir 2022-09-13 22:49:38 -03:00
rodzic c2d681b11e
commit a93d4e1dcd
14 zmienionych plików z 294 dodań i 294 usunięć

Wyświetl plik

@ -1,7 +1,7 @@
package com.geeksville.mesh.database
import android.app.Application
import com.geeksville.mesh.database.dao.PacketDao
import com.geeksville.mesh.database.dao.MeshLogDao
import com.geeksville.mesh.database.dao.QuickChatActionDao
import dagger.Module
import dagger.Provides
@ -18,8 +18,8 @@ class DatabaseModule {
MeshtasticDatabase.getDatabase(app)
@Provides
fun providePacketDao(database: MeshtasticDatabase): PacketDao {
return database.packetDao()
fun provideMeshLogDao(database: MeshtasticDatabase): MeshLogDao {
return database.meshLogDao()
}
@Provides

Wyświetl plik

@ -0,0 +1,34 @@
package com.geeksville.mesh.database
import com.geeksville.mesh.database.dao.MeshLogDao
import com.geeksville.mesh.database.entity.MeshLog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
import javax.inject.Inject
class MeshLogRepository @Inject constructor(private val meshLogDaoLazy: dagger.Lazy<MeshLogDao>) {
private val meshLogDao by lazy {
meshLogDaoLazy.get()
}
suspend fun getAllLogs(): Flow<List<MeshLog>> = withContext(Dispatchers.IO) {
meshLogDao.getAllLogs(MAX_ITEMS)
}
suspend fun getAllLogsInReceiveOrder(maxItems: Int = MAX_ITEMS): Flow<List<MeshLog>> = withContext(Dispatchers.IO) {
meshLogDao.getAllLogsInReceiveOrder(maxItems)
}
suspend fun insert(log: MeshLog) = withContext(Dispatchers.IO) {
meshLogDao.insert(log)
}
suspend fun deleteAll() = withContext(Dispatchers.IO) {
meshLogDao.deleteAll()
}
companion object {
private const val MAX_ITEMS = 500
}
}

Wyświetl plik

@ -4,14 +4,14 @@ import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.geeksville.mesh.database.dao.PacketDao
import com.geeksville.mesh.database.dao.MeshLogDao
import com.geeksville.mesh.database.dao.QuickChatActionDao
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.database.entity.QuickChatAction
@Database(entities = [Packet::class, QuickChatAction::class], version = 2, exportSchema = false)
@Database(entities = [MeshLog::class, QuickChatAction::class], version = 3, exportSchema = false)
abstract class MeshtasticDatabase : RoomDatabase() {
abstract fun packetDao(): PacketDao
abstract fun meshLogDao(): MeshLogDao
abstract fun quickChatActionDao(): QuickChatActionDao
companion object {

Wyświetl plik

@ -1,34 +0,0 @@
package com.geeksville.mesh.database
import com.geeksville.mesh.database.dao.PacketDao
import com.geeksville.mesh.database.entity.Packet
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
import javax.inject.Inject
class PacketRepository @Inject constructor(private val packetDaoLazy: dagger.Lazy<PacketDao>) {
private val packetDao by lazy {
packetDaoLazy.get()
}
suspend fun getAllPackets(): Flow<List<Packet>> = withContext(Dispatchers.IO) {
packetDao.getAllPacket(MAX_ITEMS)
}
suspend fun getAllPacketsInReceiveOrder(maxItems: Int = MAX_ITEMS): Flow<List<Packet>> = withContext(Dispatchers.IO) {
packetDao.getAllPacketsInReceiveOrder(maxItems)
}
suspend fun insert(packet: Packet) = withContext(Dispatchers.IO) {
packetDao.insert(packet)
}
suspend fun deleteAll() = withContext(Dispatchers.IO) {
packetDao.deleteAll()
}
companion object {
private const val MAX_ITEMS = 500
}
}

Wyświetl plik

@ -0,0 +1,24 @@
package com.geeksville.mesh.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.geeksville.mesh.database.entity.MeshLog
import kotlinx.coroutines.flow.Flow
@Dao
interface MeshLogDao {
@Query("Select * from log order by received_date desc limit 0,:maxItem")
fun getAllLogs(maxItem: Int): Flow<List<MeshLog>>
@Query("Select * from log order by received_date asc limit 0,:maxItem")
fun getAllLogsInReceiveOrder(maxItem: Int): Flow<List<MeshLog>>
@Insert
fun insert(log: MeshLog)
@Query("DELETE from log")
fun deleteAll()
}

Wyświetl plik

@ -1,24 +0,0 @@
package com.geeksville.mesh.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.geeksville.mesh.database.entity.Packet
import kotlinx.coroutines.flow.Flow
@Dao
interface PacketDao {
@Query("Select * from packet order by received_date desc limit 0,:maxItem")
fun getAllPacket(maxItem: Int): Flow<List<Packet>>
@Query("Select * from packet order by received_date asc limit 0,:maxItem")
fun getAllPacketsInReceiveOrder(maxItem: Int): Flow<List<Packet>>
@Insert
fun insert(packet: Packet)
@Query("DELETE from packet")
fun deleteAll()
}

Wyświetl plik

@ -1,54 +1,54 @@
package com.geeksville.mesh.database.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.Portnums
import com.google.protobuf.TextFormat
import java.io.IOException
@Entity(tableName = "packet")
data class Packet(@PrimaryKey val uuid: String,
@ColumnInfo(name = "type") val message_type: String,
@ColumnInfo(name = "received_date") val received_date: Long,
@ColumnInfo(name = "message") val raw_message: String
) {
val meshPacket: MeshProtos.MeshPacket?
get() {
if (message_type == "Packet") {
val builder = MeshProtos.MeshPacket.newBuilder()
try {
TextFormat.getParser().merge(raw_message, builder)
return builder.build()
} catch (e: IOException) {
}
}
return null
}
val nodeInfo: MeshProtos.NodeInfo?
get() {
if (message_type == "NodeInfo") {
val builder = MeshProtos.NodeInfo.newBuilder()
try {
TextFormat.getParser().merge(raw_message, builder)
return builder.build()
} catch (e: IOException) {
}
}
return null
}
val position: MeshProtos.Position?
get() {
return meshPacket?.run {
if (hasDecoded() && decoded.portnumValue == Portnums.PortNum.POSITION_APP_VALUE) {
return MeshProtos.Position.parseFrom(decoded.payload)
}
return null
} ?: nodeInfo?.position
}
package com.geeksville.mesh.database.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.Portnums
import com.google.protobuf.TextFormat
import java.io.IOException
@Entity(tableName = "log")
data class MeshLog(@PrimaryKey val uuid: String,
@ColumnInfo(name = "type") val message_type: String,
@ColumnInfo(name = "received_date") val received_date: Long,
@ColumnInfo(name = "message") val raw_message: String
) {
val meshPacket: MeshProtos.MeshPacket?
get() {
if (message_type == "Packet") {
val builder = MeshProtos.MeshPacket.newBuilder()
try {
TextFormat.getParser().merge(raw_message, builder)
return builder.build()
} catch (e: IOException) {
}
}
return null
}
val nodeInfo: MeshProtos.NodeInfo?
get() {
if (message_type == "NodeInfo") {
val builder = MeshProtos.NodeInfo.newBuilder()
try {
TextFormat.getParser().merge(raw_message, builder)
return builder.build()
} catch (e: IOException) {
}
}
return null
}
val position: MeshProtos.Position?
get() {
return meshPacket?.run {
if (hasDecoded() && decoded.portnumValue == Portnums.PortNum.POSITION_APP_VALUE) {
return MeshProtos.Position.parseFrom(decoded.payload)
}
return null
} ?: nodeInfo?.position
}
}

Wyświetl plik

@ -14,9 +14,9 @@ import androidx.lifecycle.viewModelScope
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.*
import com.geeksville.mesh.ConfigProtos.Config
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.QuickChatActionRepository
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.LocalOnlyProtos.LocalConfig
import com.geeksville.mesh.repository.datastore.ChannelSetRepository
@ -65,15 +65,15 @@ fun getInitials(nameIn: String): String {
@HiltViewModel
class UIViewModel @Inject constructor(
private val app: Application,
private val packetRepository: PacketRepository,
private val meshLogRepository: MeshLogRepository,
private val channelSetRepository: ChannelSetRepository,
private val localConfigRepository: LocalConfigRepository,
private val quickChatActionRepository: QuickChatActionRepository,
private val preferences: SharedPreferences
) : ViewModel(), Logging {
private val _allPacketState = MutableStateFlow<List<Packet>>(emptyList())
val allPackets: StateFlow<List<Packet>> = _allPacketState
private val _meshLog = MutableStateFlow<List<MeshLog>>(emptyList())
val meshLog: StateFlow<List<MeshLog>> = _meshLog
private val _localConfig = MutableStateFlow<LocalConfig>(LocalConfig.getDefaultInstance())
val localConfig: StateFlow<LocalConfig> = _localConfig
@ -87,8 +87,8 @@ class UIViewModel @Inject constructor(
init {
viewModelScope.launch {
packetRepository.getAllPackets().collect { packets ->
_allPacketState.value = packets
meshLogRepository.getAllLogs().collect { logs ->
_meshLog.value = logs
}
}
viewModelScope.launch {
@ -109,8 +109,8 @@ class UIViewModel @Inject constructor(
debug("ViewModel created")
}
fun deleteAllPacket() = viewModelScope.launch(Dispatchers.IO) {
packetRepository.deleteAll()
fun deleteAllLogs() = viewModelScope.launch(Dispatchers.IO) {
meshLogRepository.deleteAll()
}
companion object {
@ -341,7 +341,7 @@ class UIViewModel @Inject constructor(
// Packets are ordered by time, we keep most recent position of
// our device in localNodePosition.
val dateFormat = SimpleDateFormat("yyyy-MM-dd,HH:mm:ss", Locale.getDefault())
packetRepository.getAllPacketsInReceiveOrder(Int.MAX_VALUE).first().forEach { packet ->
meshLogRepository.getAllLogsInReceiveOrder(Int.MAX_VALUE).first().forEach { packet ->
// If we get a NodeInfo packet, use it to update our position data (if valid)
packet.nodeInfo?.let { nodeInfo ->
positionToPos.invoke(nodeInfo.position)?.let { _ ->

Wyświetl plik

@ -15,8 +15,8 @@ import com.geeksville.mesh.LocalOnlyProtos.LocalConfig
import com.geeksville.mesh.MeshProtos.MeshPacket
import com.geeksville.mesh.MeshProtos.ToRadio
import com.geeksville.mesh.android.hasBackgroundPermission
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.model.DeviceVersion
import com.geeksville.mesh.repository.datastore.ChannelSetRepository
import com.geeksville.mesh.repository.datastore.LocalConfigRepository
@ -50,7 +50,7 @@ class MeshService : Service(), Logging {
lateinit var dispatchers: CoroutineDispatchers
@Inject
lateinit var packetRepository: Lazy<PacketRepository>
lateinit var meshLogRepository: Lazy<MeshLogRepository>
@Inject
lateinit var radioInterfaceService: RadioInterfaceService
@ -740,13 +740,13 @@ class MeshService : Service(), Logging {
val ch = a.getChannelResponse
debug("Admin: Received channel ${ch.index}")
val packetToSave = Packet(
val packetToSave = MeshLog(
UUID.randomUUID().toString(),
"Channel",
System.currentTimeMillis(),
ch.toString()
)
insertPacket(packetToSave)
insertMeshLog(packetToSave)
if (ch.index + 1 < mi.maxChannels) {
@ -852,13 +852,13 @@ class MeshService : Service(), Logging {
sendToRadio(packet)
if (packet.hasDecoded()) {
val packetToSave = Packet(
val packetToSave = MeshLog(
UUID.randomUUID().toString(),
"Packet",
System.currentTimeMillis(),
packet.toString()
)
insertPacket(packetToSave)
insertMeshLog(packetToSave)
}
}
@ -898,13 +898,13 @@ class MeshService : Service(), Logging {
// debug("Recieved: $packet")
if (packet.hasDecoded()) {
val packetToSave = Packet(
val packetToSave = MeshLog(
UUID.randomUUID().toString(),
"Packet",
System.currentTimeMillis(),
packet.toString()
)
insertPacket(packetToSave)
insertMeshLog(packetToSave)
// Update last seen for the node that sent the packet, but also for _our node_ because anytime a packet passes
// through our node on the way to the phone that means that local node is also alive in the mesh
@ -930,11 +930,11 @@ class MeshService : Service(), Logging {
}
}
private fun insertPacket(packetToSave: Packet) {
private fun insertMeshLog(packetToSave: MeshLog) {
serviceScope.handledLaunch {
// Do not log, because might contain PII
// info("insert: ${packetToSave.message_type} = ${packetToSave.raw_message.toOneLineString()}")
packetRepository.get().insert(packetToSave)
meshLogRepository.get().insert(packetToSave)
}
}
@ -1148,13 +1148,13 @@ class MeshService : Service(), Logging {
private fun handleDeviceConfig(config: ConfigProtos.Config) {
debug("Received config ${config.toOneLineString()}")
val packetToSave = Packet(
val packetToSave = MeshLog(
UUID.randomUUID().toString(),
"Config ${config.payloadVariantCase}",
System.currentTimeMillis(),
config.toString()
)
insertPacket(packetToSave)
insertMeshLog(packetToSave)
setLocalConfig(config)
}
@ -1190,13 +1190,13 @@ class MeshService : Service(), Logging {
private fun handleNodeInfo(info: MeshProtos.NodeInfo) {
debug("Received nodeinfo num=${info.num}, hasUser=${info.hasUser()}, hasPosition=${info.hasPosition()}, hasDeviceMetrics=${info.hasDeviceMetrics()}")
val packetToSave = Packet(
val packetToSave = MeshLog(
UUID.randomUUID().toString(),
"NodeInfo",
System.currentTimeMillis(),
info.toString()
)
insertPacket(packetToSave)
insertMeshLog(packetToSave)
logAssert(newNodes.size <= 256) // Sanity check to make sure a device bug can't fill this list forever
newNodes.add(info)
@ -1273,13 +1273,13 @@ class MeshService : Service(), Logging {
* Update the nodeinfo (called from either new API version or the old one)
*/
private fun handleMyInfo(myInfo: MeshProtos.MyNodeInfo) {
val packetToSave = Packet(
val packetToSave = MeshLog(
UUID.randomUUID().toString(),
"MyNodeInfo",
System.currentTimeMillis(),
myInfo.toString()
)
insertPacket(packetToSave)
insertMeshLog(packetToSave)
rawMyNodeInfo = myInfo
regenMyNodeInfo()
@ -1305,13 +1305,13 @@ class MeshService : Service(), Logging {
private fun handleConfigComplete(configCompleteId: Int) {
if (configCompleteId == configNonce) {
val packetToSave = Packet(
val packetToSave = MeshLog(
UUID.randomUUID().toString(),
"ConfigComplete",
System.currentTimeMillis(),
configCompleteId.toString()
)
insertPacket(packetToSave)
insertMeshLog(packetToSave)
// This was our config request
if (newMyNodeInfo == null || newNodes.isEmpty())

Wyświetl plik

@ -0,0 +1,50 @@
package com.geeksville.mesh.ui
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.MeshLog
import java.text.DateFormat
import java.util.*
class DebugAdapter internal constructor(
context: Context
) : RecyclerView.Adapter<DebugAdapter.DebugViewHolder>() {
private val inflater: LayoutInflater = LayoutInflater.from(context)
private var logs = emptyList<MeshLog>()
private val timeFormat: DateFormat =
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM)
inner class DebugViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val logTypeView: TextView = itemView.findViewById(R.id.type)
val logDateReceivedView: TextView = itemView.findViewById(R.id.dateReceived)
val logRawMessage: TextView = itemView.findViewById(R.id.rawMessage)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DebugViewHolder {
val itemView = inflater.inflate(R.layout.adapter_debug_layout, parent, false)
return DebugViewHolder(itemView)
}
override fun onBindViewHolder(holder: DebugViewHolder, position: Int) {
val current = logs[position]
holder.logTypeView.text = current.message_type
holder.logRawMessage.text = current.raw_message
val date = Date(current.received_date)
holder.logDateReceivedView.text = timeFormat.format(date)
}
internal fun setLogs(logs: List<MeshLog>) {
this.logs = logs
notifyDataSetChanged()
}
override fun getItemCount() = logs.size
}

Wyświetl plik

@ -10,14 +10,14 @@ import androidx.lifecycle.asLiveData
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.geeksville.mesh.R
import com.geeksville.mesh.databinding.DebugFragmentBinding
import com.geeksville.mesh.databinding.FragmentDebugBinding
import com.geeksville.mesh.model.UIViewModel
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class DebugFragment : Fragment() {
private var _binding: DebugFragmentBinding? = null
private var _binding: FragmentDebugBinding? = null
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
@ -28,27 +28,27 @@ class DebugFragment : Fragment() {
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = DebugFragmentBinding.inflate(inflater, container, false)
_binding = FragmentDebugBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView = view.findViewById<RecyclerView>(R.id.packets_recyclerview)
val adapter = PacketListAdapter(requireContext())
val recyclerView = view.findViewById<RecyclerView>(R.id.debug_recyclerview)
val adapter = DebugAdapter(requireContext())
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())
binding.clearButton.setOnClickListener {
model.deleteAllPacket()
model.deleteAllLogs()
}
binding.closeButton.setOnClickListener {
parentFragmentManager.popBackStack()
}
model.allPackets.asLiveData().observe(viewLifecycleOwner) { packets ->
packets?.let { adapter.setPackets(it) }
model.meshLog.asLiveData().observe(viewLifecycleOwner) { logs ->
logs?.let { adapter.setLogs(it) }
}
}
}

Wyświetl plik

@ -1,50 +0,0 @@
package com.geeksville.mesh.ui
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.Packet
import java.text.DateFormat
import java.util.*
class PacketListAdapter internal constructor(
context: Context
) : RecyclerView.Adapter<PacketListAdapter.PacketViewHolder>() {
private val inflater: LayoutInflater = LayoutInflater.from(context)
private var packets = emptyList<Packet>()
private val timeFormat: DateFormat =
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM)
inner class PacketViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val packetTypeView: TextView = itemView.findViewById(R.id.type)
val packetDateReceivedView: TextView = itemView.findViewById(R.id.dateReceived)
val packetRawMessage: TextView = itemView.findViewById(R.id.rawMessage)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PacketViewHolder {
val itemView = inflater.inflate(R.layout.adapter_packet_layout, parent, false)
return PacketViewHolder(itemView)
}
override fun onBindViewHolder(holder: PacketViewHolder, position: Int) {
val current = packets[position]
holder.packetTypeView.text = current.message_type
holder.packetRawMessage.text = current.raw_message
val date = Date(current.received_date)
holder.packetDateReceivedView.text = timeFormat.format(date)
}
internal fun setPackets(packets: List<Packet>) {
this.packets = packets
notifyDataSetChanged()
}
override fun getItemCount() = packets.size
}

Wyświetl plik

@ -1,86 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/adapterPacketLayout"
style="@style/Widget.App.CardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="@+id/cloudDownloadIcon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/cloudDownloadIcon"
tools:text="NodeInfo" />
<TextView
android:id="@+id/dateReceived"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="@+id/cloudDownloadIcon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/cloudDownloadIcon"
tools:text="9/27/20 21:00:58" />
<TextView
android:id="@+id/rawMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:fontFamily="monospace"
android:singleLine="false"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textIsSelectable="true"
android:textSize="8sp"
android:typeface="monospace"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cloudDownloadIcon"
app:layout_constraintVertical_weight="1"
tools:text="# com.geeksville.mesh.MeshProtos$MeshPacket@1b1ea594\n
decoded {\n
position {\n
altitude: 60\n
battery_level: 81\n
latitude_i: 411111136\n
longitude_i: -711111805\n
time: 1600390966\n
}\n
}\n
from: -1409794164\n
hop_limit: 3\n
id: 1737414295\n
rx_snr: 9.5\n
rx_time: 316400569\n
to: -1409790708" />
<ImageView
android:id="@+id/cloudDownloadIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:alpha="0.4"
app:layout_constraintEnd_toStartOf="@+id/dateReceived"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/cloud_download_outline_24"
android:contentDescription="TODO"
app:tint="@color/colorIconTint" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/adapterDebugLayout"
style="@style/Widget.App.CardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="@+id/cloudDownloadIcon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/cloudDownloadIcon"
tools:text="NodeInfo" />
<TextView
android:id="@+id/dateReceived"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="@+id/cloudDownloadIcon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/cloudDownloadIcon"
tools:text="9/27/20 21:00:58" />
<TextView
android:id="@+id/rawMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:fontFamily="monospace"
android:singleLine="false"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textIsSelectable="true"
android:textSize="8sp"
android:typeface="monospace"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cloudDownloadIcon"
app:layout_constraintVertical_weight="1"
tools:text="# com.geeksville.mesh.MeshProtos$MeshPacket@1b1ea594\n
decoded {\n
position {\n
altitude: 60\n
battery_level: 81\n
latitude_i: 411111136\n
longitude_i: -711111805\n
time: 1600390966\n
}\n
}\n
from: -1409794164\n
hop_limit: 3\n
id: 1737414295\n
rx_snr: 9.5\n
rx_time: 316400569\n
to: -1409790708" />
<ImageView
android:id="@+id/cloudDownloadIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:alpha="0.4"
app:layout_constraintEnd_toStartOf="@+id/dateReceived"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/cloud_download_outline_24"
android:contentDescription="TODO"
app:tint="@color/colorIconTint" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>

Wyświetl plik

@ -8,7 +8,7 @@
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/packets_recyclerview"
android:id="@+id/debug_recyclerview"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
@ -19,7 +19,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/clearButton"
tools:itemCount="8"
tools:listitem="@layout/adapter_packet_layout" />
tools:listitem="@layout/adapter_debug_layout" />
<Button
android:id="@+id/clearButton"
@ -57,7 +57,7 @@
android:layout_height="wrap_content"
android:text="@string/debug_last_messages"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/packets_recyclerview"
app:layout_constraintBottom_toTopOf="@+id/debug_recyclerview"
app:layout_constraintEnd_toStartOf="@+id/clearButton"
app:layout_constraintStart_toEndOf="@+id/closeButton"
app:layout_constraintTop_toTopOf="parent" />