start cleaning up models

pull/8/head
geeksville 2020-02-17 13:34:52 -08:00
rodzic 52deba7d4b
commit f18ac28dc0
9 zmienionych plików z 307 dodań i 268 usunięć

Wyświetl plik

@ -16,8 +16,13 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.ui.core.setContent
import com.geeksville.android.Logging
import com.geeksville.mesh.model.MessagesState
import com.geeksville.mesh.model.NodeDB
import com.geeksville.mesh.model.TextMessage
import com.geeksville.mesh.model.UIState
import com.geeksville.mesh.service.*
import com.geeksville.mesh.ui.*
import com.geeksville.mesh.ui.MeshApp
import com.geeksville.mesh.ui.getInitials
import com.geeksville.util.exceptionReporter
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
@ -315,7 +320,12 @@ class MainActivity : AppCompatActivity(), Logging,
// FIXME - use the real time from the packet
// FIXME - don't just slam in a new list each time, it probably causes extra drawing. Figure out how to be Compose smarter...
val modded = MessagesState.messages.value.toMutableList()
modded.add(TextMessage(sender, payload.toString(utf8)))
modded.add(
TextMessage(
sender,
payload.toString(utf8)
)
)
MessagesState.messages.value = modded
}
else -> TODO()

Wyświetl plik

@ -0,0 +1,36 @@
package com.geeksville.mesh.model
import androidx.compose.mutableStateOf
import com.geeksville.android.Logging
import java.util.*
/**
* the model object for a text message
*/
data class TextMessage(val from: String, val text: String, val date: Date = Date())
object MessagesState : Logging {
val testTexts = listOf(
TextMessage(
"+16508675310",
"I found the cache"
),
TextMessage(
"+16508675311",
"Help! I've fallen and I can't get up."
)
)
// If the following (unused otherwise) line is commented out, the IDE preview window works.
// if left in the preview always renders as empty.
val messages = mutableStateOf(testTexts, { a, b ->
a.size == b.size // If the # of messages changes, consider it important for rerender
})
fun addMessage(m: TextMessage) {
val l = messages.value.toMutableList()
l.add(m)
messages.value = l
}
}

Wyświetl plik

@ -0,0 +1,48 @@
package com.geeksville.mesh.model
import androidx.compose.mutableStateOf
import com.geeksville.mesh.MeshUser
import com.geeksville.mesh.NodeInfo
import com.geeksville.mesh.Position
object NodeDB {
private val testPositions = arrayOf(
Position(32.776665, -96.796989, 35), // dallas
Position(32.960758, -96.733521, 35), // richardson
Position(
32.912901,
-96.781776,
35
) // north dallas
)
val testNodeNoPosition = NodeInfo(
8,
MeshUser(
"+16508765308".format(8),
"Kevin MesterNoLoc",
"KLO"
),
null,
12345
)
val testNodes = testPositions.mapIndexed { index, it ->
NodeInfo(
9 + index,
MeshUser(
"+165087653%02d".format(9 + index),
"Kevin Mester$index",
"KM$index"
),
it,
12345
)
}
/// The unique ID of our node
val myId = mutableStateOf("+16508765309")
/// A map from nodeid to to nodeinfo
val nodes = mutableStateOf(testNodes.map { it.user!!.id to it }.toMap())
}

Wyświetl plik

@ -0,0 +1,32 @@
package com.geeksville.mesh.model
import android.util.Base64
import androidx.compose.mutableStateOf
import com.geeksville.mesh.MeshProtos
/// FIXME - figure out how to merge this staate with the AppStatus Model
object UIState {
/// Kinda ugly - created in the activity but used from Compose - figure out if there is a cleaner way GIXME
// lateinit var googleSignInClient: GoogleSignInClient
/// Are we connected to our radio device
val isConnected = mutableStateOf(false)
/// various radio settings (including the channel)
val radioConfig = mutableStateOf(MeshProtos.RadioConfig.getDefaultInstance())
/// our name in hte radio
/// Note, we generate owner initials automatically for now
val ownerName = mutableStateOf("fixme readfromprefs")
/// Return an URL that represents the current channel values
val channelUrl
get(): String {
val channelBytes = radioConfig.value.channelSettings.toByteArray()
val enc = Base64.encodeToString(channelBytes, Base64.URL_SAFE + Base64.NO_WRAP)
return "https://www.meshtastic.org/c/$enc"
}
}

Wyświetl plik

@ -12,177 +12,175 @@ import kotlin.math.sin
******************************************************************************/
object LocationUtils {
/**
* Format as degrees, minutes, secs
*
* @param degIn
* @param isLatitude
* @return a string like 120deg
*/
fun degreesToDMS(
_degIn: Double,
isLatitude: Boolean
): Array<String> {
var degIn = _degIn
val isPos = degIn >= 0
val dirLetter =
if (isLatitude) if (isPos) 'N' else 'S' else if (isPos) 'E' else 'W'
degIn = Math.abs(degIn)
val degOut = degIn.toInt()
val minutes = 60 * (degIn - degOut)
val minwhole = minutes.toInt()
val seconds = (minutes - minwhole) * 60
return arrayOf(
Integer.toString(degOut), Integer.toString(minwhole),
java.lang.Double.toString(seconds),
Character.toString(dirLetter)
/**
* Format as degrees, minutes, secs
*
* @param degIn
* @param isLatitude
* @return a string like 120deg
*/
fun degreesToDMS(
_degIn: Double,
isLatitude: Boolean
): Array<String> {
var degIn = _degIn
val isPos = degIn >= 0
val dirLetter =
if (isLatitude) if (isPos) 'N' else 'S' else if (isPos) 'E' else 'W'
degIn = Math.abs(degIn)
val degOut = degIn.toInt()
val minutes = 60 * (degIn - degOut)
val minwhole = minutes.toInt()
val seconds = (minutes - minwhole) * 60
return arrayOf(
Integer.toString(degOut), Integer.toString(minwhole),
java.lang.Double.toString(seconds),
Character.toString(dirLetter)
)
}
fun degreesToDM(_degIn: Double, isLatitude: Boolean): Array<String> {
var degIn = _degIn
val isPos = degIn >= 0
val dirLetter =
if (isLatitude) if (isPos) 'N' else 'S' else if (isPos) 'E' else 'W'
degIn = Math.abs(degIn)
val degOut = degIn.toInt()
val minutes = 60 * (degIn - degOut)
val seconds = 0
return arrayOf(
Integer.toString(degOut), java.lang.Double.toString(minutes),
Integer.toString(seconds),
Character.toString(dirLetter)
)
}
fun degreesToD(_degIn: Double, isLatitude: Boolean): Array<String> {
var degIn = _degIn
val isPos = degIn >= 0
val dirLetter =
if (isLatitude) if (isPos) 'N' else 'S' else if (isPos) 'E' else 'W'
degIn = Math.abs(degIn)
val degOut = degIn
val minutes = 0
val seconds = 0
return arrayOf(
java.lang.Double.toString(degOut), Integer.toString(minutes),
Integer.toString(seconds),
Character.toString(dirLetter)
)
}
/**
* A not super efficent mapping from a starting lat/long + a distance at a
* certain direction
*
* @param lat
* @param longitude
* @param distMeters
* @param theta
* in radians, 0 == north
* @return an array with lat and long
*/
fun addDistance(
lat: Double,
longitude: Double,
distMeters: Double,
theta: Double
): DoubleArray {
val dx = distMeters * Math.sin(theta) // theta measured clockwise
// from due north
val dy = distMeters * Math.cos(theta) // dx, dy same units as R
val dLong = dx / (111320 * Math.cos(lat)) // dx, dy in meters
val dLat = dy / 110540 // result in degrees long/lat
return doubleArrayOf(lat + dLat, longitude + dLong)
}
fun LatLongToMeter(
lat_a: Double,
lng_a: Double,
lat_b: Double,
lng_b: Double
): Double {
val pk = (180 / 3.14169)
val a1 = lat_a / pk
val a2 = lng_a / pk
val b1 = lat_b / pk
val b2 = lng_b / pk
val t1 =
Math.cos(a1) * Math.cos(a2) * Math.cos(b1) * Math.cos(
b2
)
}
fun degreesToDM(_degIn: Double, isLatitude: Boolean): Array<String> {
var degIn = _degIn
val isPos = degIn >= 0
val dirLetter =
if (isLatitude) if (isPos) 'N' else 'S' else if (isPos) 'E' else 'W'
degIn = Math.abs(degIn)
val degOut = degIn.toInt()
val minutes = 60 * (degIn - degOut)
val seconds = 0
return arrayOf(
Integer.toString(degOut), java.lang.Double.toString(minutes),
Integer.toString(seconds),
Character.toString(dirLetter)
val t2 =
Math.cos(a1) * Math.sin(a2) * Math.cos(b1) * Math.sin(
b2
)
}
val t3 = Math.sin(a1) * Math.sin(b1)
var tt = Math.acos(t1 + t2 + t3)
if (java.lang.Double.isNaN(tt)) tt = 0.0 // Must have been the same point?
return 6366000 * tt
}
fun degreesToD(_degIn: Double, isLatitude: Boolean): Array<String> {
var degIn = _degIn
val isPos = degIn >= 0
val dirLetter =
if (isLatitude) if (isPos) 'N' else 'S' else if (isPos) 'E' else 'W'
degIn = Math.abs(degIn)
val degOut = degIn
val minutes = 0
val seconds = 0
return arrayOf(
java.lang.Double.toString(degOut), Integer.toString(minutes),
Integer.toString(seconds),
Character.toString(dirLetter)
)
}
/**
* Convert degrees/mins/secs to a single double
*
* @param degrees
* @param minutes
* @param seconds
* @param isPostive
* @return
*/
fun DMSToDegrees(
degrees: Int,
minutes: Int,
seconds: Float,
isPostive: Boolean
): Double {
return (if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0)
}
/**
* A not super efficent mapping from a starting lat/long + a distance at a
* certain direction
*
* @param lat
* @param longitude
* @param distMeters
* @param theta
* in radians, 0 == north
* @return an array with lat and long
*/
fun addDistance(
lat: Double,
longitude: Double,
distMeters: Double,
theta: Double
): DoubleArray {
val dx = distMeters * Math.sin(theta) // theta measured clockwise
// from due north
val dy = distMeters * Math.cos(theta) // dx, dy same units as R
val dLong = dx / (111320 * Math.cos(lat)) // dx, dy in meters
val dLat = dy / 110540 // result in degrees long/lat
return doubleArrayOf(lat + dLat, longitude + dLong)
}
fun DMSToDegrees(
degrees: Double,
minutes: Double,
seconds: Double,
isPostive: Boolean
): Double {
return (if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0)
}
fun LatLongToMeter(
lat_a: Double,
lng_a: Double,
lat_b: Double,
lng_b: Double
): Double {
val pk = (180 / 3.14169)
val a1 = lat_a / pk
val a2 = lng_a / pk
val b1 = lat_b / pk
val b2 = lng_b / pk
val t1 =
Math.cos(a1) * Math.cos(a2) * Math.cos(b1) * Math.cos(
b2
)
val t2 =
Math.cos(a1) * Math.sin(a2) * Math.cos(b1) * Math.sin(
b2
)
val t3 = Math.sin(a1) * Math.sin(b1)
var tt = Math.acos(t1 + t2 + t3)
if (java.lang.Double.isNaN(tt)) tt = 0.0 // Must have been the same point?
return 6366000 * tt
}
/**
* Computes the bearing in degrees between two points on Earth.
*
* @param lat1
* Latitude of the first point
* @param lon1
* Longitude of the first point
* @param lat2
* Latitude of the second point
* @param lon2
* Longitude of the second point
* @return Bearing between the two points in degrees. A value of 0 means due
* north.
*/
fun bearing(
lat1: Double,
lon1: Double,
lat2: Double,
lon2: Double
): Double {
val lat1Rad = Math.toRadians(lat1)
val lat2Rad = Math.toRadians(lat2)
val deltaLonRad = Math.toRadians(lon2 - lon1)
val y = sin(deltaLonRad) * cos(lat2Rad)
val x =
cos(lat1Rad) * sin(lat2Rad) - (sin(lat1Rad) * cos(lat2Rad)
* Math.cos(deltaLonRad))
return radToBearing(Math.atan2(y, x))
}
/**
* Convert degrees/mins/secs to a single double
*
* @param degrees
* @param minutes
* @param seconds
* @param isPostive
* @return
*/
fun DMSToDegrees(
degrees: Int,
minutes: Int,
seconds: Float,
isPostive: Boolean
): Double {
return (if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0)
}
fun DMSToDegrees(
degrees: Double,
minutes: Double,
seconds: Double,
isPostive: Boolean
): Double {
return (if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0)
}
/**
* Computes the bearing in degrees between two points on Earth.
*
* @param lat1
* Latitude of the first point
* @param lon1
* Longitude of the first point
* @param lat2
* Latitude of the second point
* @param lon2
* Longitude of the second point
* @return Bearing between the two points in degrees. A value of 0 means due
* north.
*/
fun bearing(
lat1: Double,
lon1: Double,
lat2: Double,
lon2: Double
): Double {
val lat1Rad = Math.toRadians(lat1)
val lat2Rad = Math.toRadians(lat2)
val deltaLonRad = Math.toRadians(lon2 - lon1)
val y = sin(deltaLonRad) * cos(lat2Rad)
val x =
cos(lat1Rad) * sin(lat2Rad) - (sin(lat1Rad) * cos(lat2Rad)
* Math.cos(deltaLonRad))
return radToBearing(Math.atan2(y, x))
}
/**
* Converts an angle in radians to degrees
*/
fun radToBearing(rad: Double): Double {
return (Math.toDegrees(rad) + 360) % 360
}
/**
* Converts an angle in radians to degrees
*/
fun radToBearing(rad: Double): Double {
return (Math.toDegrees(rad) + 360) % 360
}

Wyświetl plik

@ -18,6 +18,8 @@ import androidx.ui.tooling.preview.Preview
import androidx.ui.unit.dp
import com.geeksville.android.Logging
import com.geeksville.mesh.R
import com.geeksville.mesh.model.NodeDB
import com.geeksville.mesh.model.UIState
object UILog : Logging

Wyświetl plik

@ -1,7 +1,6 @@
package com.geeksville.mesh.ui
import androidx.compose.Composable
import androidx.compose.mutableStateOf
import androidx.compose.state
import androidx.ui.core.Modifier
import androidx.ui.core.Text
@ -20,37 +19,13 @@ import androidx.ui.material.surface.Surface
import androidx.ui.text.TextStyle
import androidx.ui.tooling.preview.Preview
import androidx.ui.unit.dp
import com.geeksville.android.Logging
import com.geeksville.mesh.ui.MessagesState.messages
import com.geeksville.mesh.model.MessagesState
import com.geeksville.mesh.model.MessagesState.messages
import com.geeksville.mesh.model.NodeDB
import com.geeksville.mesh.model.TextMessage
import java.text.SimpleDateFormat
import java.util.*
/**
* the model object for a text message
*/
data class TextMessage(val from: String, val text: String, val date: Date = Date())
object MessagesState : Logging {
val testTexts = listOf(
TextMessage("+6508675310", "I found the cache"),
TextMessage("+6508675311", "Help! I've fallen and I can't get up.")
)
// If the following (unused otherwise) line is commented out, the IDE preview window works.
// if left in the preview always renders as empty.
val messages = mutableStateOf(MessagesState.testTexts, { a, b ->
a.size == b.size // If the # of messages changes, consider it important for rerender
})
fun addMessage(m: TextMessage) {
val l = messages.value.toMutableList()
l.add(m)
messages.value = l
}
}
private val dateFormat = SimpleDateFormat("h:mm a")
val TimestampEmphasis = object : Emphasis {
@ -129,7 +104,12 @@ fun MessagesContent() {
imeAction = ImeAction.Send,
onImeActionPerformed = {
MessagesState.info("did IME action")
MessagesState.addMessage(TextMessage("fixme", message.value))
MessagesState.addMessage(
TextMessage(
"fixme",
message.value
)
)
},
modifier = LayoutPadding(4.dp)
)

Wyświetl plik

@ -10,6 +10,7 @@ import androidx.ui.tooling.preview.Preview
import androidx.ui.unit.dp
import com.geeksville.mesh.NodeInfo
import com.geeksville.mesh.R
import com.geeksville.mesh.model.NodeDB
import androidx.ui.core.Modifier as Modifier1

Wyświetl plik

@ -1,9 +1,7 @@
package com.geeksville.mesh.ui
import android.util.Base64
import androidx.compose.Model
import androidx.compose.mutableStateOf
import com.geeksville.mesh.*
import com.geeksville.mesh.R
data class ScreenInfo(val icon: Int, val label: String)
@ -22,72 +20,6 @@ object AppStatus {
var currentScreen: ScreenInfo = Screen.messages
}
object NodeDB {
private val testPositions = arrayOf(
Position(32.776665, -96.796989, 35), // dallas
Position(32.960758, -96.733521, 35), // richardson
Position(
32.912901,
-96.781776,
35
) // north dallas
)
val testNodeNoPosition = NodeInfo(
8,
MeshUser(
"+6508765308".format(8),
"Kevin MesterNoLoc",
"KLO"
),
null,
12345
)
val testNodes = testPositions.mapIndexed { index, it ->
NodeInfo(
9 + index,
MeshUser(
"+65087653%02d".format(9 + index),
"Kevin Mester$index",
"KM$index"
),
it,
12345
)
}
/// A map from nodeid to to nodeinfo
val nodes = mutableStateOf(testNodes.map { it.user!!.id to it }.toMap())
}
/// FIXME - figure out how to merge this staate with the AppStatus Model
object UIState {
/// Kinda ugly - created in the activity but used from Compose - figure out if there is a cleaner way GIXME
// lateinit var googleSignInClient: GoogleSignInClient
/// Are we connected to our radio device
val isConnected = mutableStateOf(false)
/// various radio settings (including the channel)
val radioConfig = mutableStateOf(MeshProtos.RadioConfig.getDefaultInstance())
/// our name in hte radio
/// Note, we generate owner initials automatically for now
val ownerName = mutableStateOf("fixme readfromprefs")
/// Return an URL that represents the current channel values
val channelUrl
get(): String {
val channelBytes = radioConfig.value.channelSettings.toByteArray()
val enc = Base64.encodeToString(channelBytes, Base64.URL_SAFE + Base64.NO_WRAP)
return "https://www.meshtastic.org/c/$enc"
}
}
/**
* Temporary solution pending navigation support.