kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
commit
8a18680d0a
|
@ -1242,7 +1242,7 @@ class MeshService : Service(), Logging {
|
||||||
MyNodeInfo(
|
MyNodeInfo(
|
||||||
myNodeNum,
|
myNodeNum,
|
||||||
hasGps,
|
hasGps,
|
||||||
hwModel,
|
hwModelDeprecated,
|
||||||
firmwareVersion,
|
firmwareVersion,
|
||||||
firmwareUpdateFilename != null,
|
firmwareUpdateFilename != null,
|
||||||
isBluetoothInterface && SoftwareUpdateService.shouldUpdate(
|
isBluetoothInterface && SoftwareUpdateService.shouldUpdate(
|
||||||
|
@ -1552,10 +1552,10 @@ class MeshService : Service(), Logging {
|
||||||
*/
|
*/
|
||||||
private fun setFirmwareUpdateFilename(info: MeshProtos.MyNodeInfo) {
|
private fun setFirmwareUpdateFilename(info: MeshProtos.MyNodeInfo) {
|
||||||
firmwareUpdateFilename = try {
|
firmwareUpdateFilename = try {
|
||||||
if (info.region != null && info.firmwareVersion != null && info.hwModel != null)
|
if (info.region != null && info.firmwareVersion != null && info.hwModelDeprecated != null)
|
||||||
SoftwareUpdateService.getUpdateFilename(
|
SoftwareUpdateService.getUpdateFilename(
|
||||||
this,
|
this,
|
||||||
info.hwModel
|
info.hwModelDeprecated
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
null
|
null
|
||||||
|
|
|
@ -160,7 +160,7 @@ class MockInterface(private val service: RadioInterfaceService) : Logging, IRadi
|
||||||
MeshProtos.FromRadio.newBuilder().apply {
|
MeshProtos.FromRadio.newBuilder().apply {
|
||||||
myInfo = MeshProtos.MyNodeInfo.newBuilder().apply {
|
myInfo = MeshProtos.MyNodeInfo.newBuilder().apply {
|
||||||
myNodeNum = MY_NODE
|
myNodeNum = MY_NODE
|
||||||
hwModel = "Sim"
|
hwModelDeprecated = "Sim"
|
||||||
messageTimeoutMsec = 5 * 60 * 1000
|
messageTimeoutMsec = 5 * 60 * 1000
|
||||||
firmwareVersion = service.getString(R.string.cur_firmware_version)
|
firmwareVersion = service.getString(R.string.cur_firmware_version)
|
||||||
numBands = 13
|
numBands = 13
|
||||||
|
|
|
@ -13,6 +13,7 @@ import com.geeksville.android.Logging
|
||||||
import com.geeksville.mesh.NodeInfo
|
import com.geeksville.mesh.NodeInfo
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.model.UIViewModel
|
import com.geeksville.mesh.model.UIViewModel
|
||||||
|
import com.geeksville.util.formatAgo
|
||||||
import com.mapbox.geojson.Feature
|
import com.mapbox.geojson.Feature
|
||||||
import com.mapbox.geojson.FeatureCollection
|
import com.mapbox.geojson.FeatureCollection
|
||||||
import com.mapbox.geojson.Point
|
import com.mapbox.geojson.Point
|
||||||
|
@ -79,7 +80,7 @@ class MapFragment : ScreenFragment("Map"), Logging {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
node.user?.let {
|
node.user?.let {
|
||||||
f.addStringProperty("name", it.longName)
|
f.addStringProperty("name", it.longName + " " + formatAgo(p.time))
|
||||||
}
|
}
|
||||||
f
|
f
|
||||||
}
|
}
|
||||||
|
@ -93,7 +94,8 @@ class MapFragment : ScreenFragment("Map"), Logging {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun zoomToNodes(map: MapboxMap) {
|
fun zoomToNodes(map: MapboxMap) {
|
||||||
val nodesWithPosition = model.nodeDB.nodes.value?.values?.filter { it.validPosition != null }
|
val nodesWithPosition =
|
||||||
|
model.nodeDB.nodes.value?.values?.filter { it.validPosition != null }
|
||||||
if (nodesWithPosition != null && nodesWithPosition.isNotEmpty()) {
|
if (nodesWithPosition != null && nodesWithPosition.isNotEmpty()) {
|
||||||
val update = if (nodesWithPosition.size >= 2) {
|
val update = if (nodesWithPosition.size >= 2) {
|
||||||
// Multiple nodes, make them all fit on the map view
|
// Multiple nodes, make them all fit on the map view
|
||||||
|
@ -158,7 +160,10 @@ class MapFragment : ScreenFragment("Map"), Logging {
|
||||||
if (view != null) { // it might have gone away by now
|
if (view != null) { // it might have gone away by now
|
||||||
// val markerIcon = BitmapFactory.decodeResource(context.resources, R.drawable.ic_twotone_person_pin_24)
|
// val markerIcon = BitmapFactory.decodeResource(context.resources, R.drawable.ic_twotone_person_pin_24)
|
||||||
val markerIcon =
|
val markerIcon =
|
||||||
ContextCompat.getDrawable(requireActivity(), R.drawable.ic_twotone_person_pin_24)!!
|
ContextCompat.getDrawable(
|
||||||
|
requireActivity(),
|
||||||
|
R.drawable.ic_twotone_person_pin_24
|
||||||
|
)!!
|
||||||
|
|
||||||
map.setStyle(Style.OUTDOORS) { style ->
|
map.setStyle(Style.OUTDOORS) { style ->
|
||||||
style.addSource(nodePositions)
|
style.addSource(nodePositions)
|
||||||
|
|
|
@ -2,11 +2,13 @@ package com.geeksville.mesh.ui
|
||||||
|
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.format.DateFormat
|
import android.text.Html
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
@ -17,13 +19,14 @@ import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.databinding.AdapterNodeLayoutBinding
|
import com.geeksville.mesh.databinding.AdapterNodeLayoutBinding
|
||||||
import com.geeksville.mesh.databinding.NodelistFragmentBinding
|
import com.geeksville.mesh.databinding.NodelistFragmentBinding
|
||||||
import com.geeksville.mesh.model.UIViewModel
|
import com.geeksville.mesh.model.UIViewModel
|
||||||
import java.text.ParseException
|
import com.geeksville.util.formatAgo
|
||||||
import java.util.*
|
import java.net.URLEncoder
|
||||||
|
|
||||||
|
|
||||||
class UsersFragment : ScreenFragment("Users"), Logging {
|
class UsersFragment : ScreenFragment("Users"), Logging {
|
||||||
|
|
||||||
private var _binding: NodelistFragmentBinding? = null
|
private var _binding: NodelistFragmentBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and onDestroyView.
|
// This property is only valid between onCreateView and onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
@ -34,6 +37,7 @@ class UsersFragment : ScreenFragment("Users"), Logging {
|
||||||
class ViewHolder(itemView: AdapterNodeLayoutBinding) : RecyclerView.ViewHolder(itemView.root) {
|
class ViewHolder(itemView: AdapterNodeLayoutBinding) : RecyclerView.ViewHolder(itemView.root) {
|
||||||
val nodeNameView = itemView.nodeNameView
|
val nodeNameView = itemView.nodeNameView
|
||||||
val distanceView = itemView.distanceView
|
val distanceView = itemView.distanceView
|
||||||
|
val coordsView = itemView.coordsView
|
||||||
val batteryPctView = itemView.batteryPercentageView
|
val batteryPctView = itemView.batteryPercentageView
|
||||||
val lastTime = itemView.lastConnectionView
|
val lastTime = itemView.lastConnectionView
|
||||||
val powerIcon = itemView.batteryIcon
|
val powerIcon = itemView.batteryIcon
|
||||||
|
@ -104,8 +108,26 @@ class UsersFragment : ScreenFragment("Users"), Logging {
|
||||||
*/
|
*/
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val n = nodes[position]
|
val n = nodes[position]
|
||||||
|
val name = n.user?.longName ?: n.user?.id ?: "Unknown node"
|
||||||
|
holder.nodeNameView.text = name
|
||||||
|
|
||||||
holder.nodeNameView.text = n.user?.longName ?: n.user?.id ?: "Unknown node"
|
val pos = n.validPosition;
|
||||||
|
if (pos != null) {
|
||||||
|
val coords =
|
||||||
|
String.format("%.5f %.5f", pos.latitude, pos.longitude).replace(",", ".")
|
||||||
|
val html =
|
||||||
|
"<a href='geo:${pos.latitude},${pos.longitude}?z=17&label=${
|
||||||
|
URLEncoder.encode(
|
||||||
|
name,
|
||||||
|
"utf-8"
|
||||||
|
)
|
||||||
|
}'>${coords}</a>"
|
||||||
|
holder.coordsView.text = HtmlCompat.fromHtml(html, Html.FROM_HTML_MODE_LEGACY)
|
||||||
|
holder.coordsView.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
holder.coordsView.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
holder.coordsView.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
val ourNodeInfo = model.nodeDB.ourNodeInfo
|
val ourNodeInfo = model.nodeDB.ourNodeInfo
|
||||||
val distance = ourNodeInfo?.distanceStr(n)
|
val distance = ourNodeInfo?.distanceStr(n)
|
||||||
|
@ -118,7 +140,7 @@ class UsersFragment : ScreenFragment("Users"), Logging {
|
||||||
|
|
||||||
renderBattery(n.batteryPctLevel, holder)
|
renderBattery(n.batteryPctLevel, holder)
|
||||||
|
|
||||||
holder.lastTime.text = getLastTimeValue(n)
|
holder.lastTime.text = formatAgo(n.lastSeen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private var nodes = arrayOf<NodeInfo>()
|
private var nodes = arrayOf<NodeInfo>()
|
||||||
|
@ -150,30 +172,6 @@ class UsersFragment : ScreenFragment("Users"), Logging {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLastTimeValue(n: NodeInfo): String {
|
|
||||||
var lastTimeText = "?"
|
|
||||||
val currentTime = (System.currentTimeMillis()/1000).toInt()
|
|
||||||
val threeDaysLong = 3 * 60*60*24
|
|
||||||
|
|
||||||
//if the lastSeen is too old
|
|
||||||
if (n.lastSeen < (currentTime - threeDaysLong))
|
|
||||||
return lastTimeText
|
|
||||||
|
|
||||||
try {
|
|
||||||
val toLong: Long = n.lastSeen.toLong()
|
|
||||||
val long1000 = toLong * 1000L
|
|
||||||
val date = Date(long1000)
|
|
||||||
val timeFormat = DateFormat.getTimeFormat(context)
|
|
||||||
|
|
||||||
lastTimeText = timeFormat.format(date)
|
|
||||||
|
|
||||||
} catch (e: ParseException) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
return lastTimeText
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 7c025b9a4d54bb410ec17ee653122861b413f177
|
Subproject commit ac26ffdc71dad5765124186df5ec38771a0e5240
|
|
@ -51,6 +51,20 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/coords_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:text="@string/sample_coords"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/distance_view"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/imageView"
|
||||||
|
app:layout_constraintVertical_bias="0.0" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/batteryIcon"
|
android:id="@+id/batteryIcon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -94,5 +94,6 @@
|
||||||
<string name="okay">Okay</string>
|
<string name="okay">Okay</string>
|
||||||
<string name="must_set_region">You must set a region!</string>
|
<string name="must_set_region">You must set a region!</string>
|
||||||
<string name="region">Region</string>
|
<string name="region">Region</string>
|
||||||
|
<string name="sample_coords">55.332244 34.442211</string>
|
||||||
<string name="save_messages">Save messages as csv...</string>
|
<string name="save_messages">Save messages as csv...</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
2
design
2
design
|
@ -1 +1 @@
|
||||||
Subproject commit a81074152157fa54b0d02ccbbd6a6357cc3cedcf
|
Subproject commit d0339f0297c629f1bd6873b4abccfecb98443538
|
|
@ -1 +1 @@
|
||||||
Subproject commit 99cf0da30fe41163a735ac291f3dd018a7d6295d
|
Subproject commit 6da250358ed13e3c58fd4fa2a123b01b3826d4bf
|
Ładowanie…
Reference in New Issue