From 56bf4523cba5602a72c4db9e0a1f5568a0cbfb50 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 17 Feb 2020 11:22:47 -0800 Subject: [PATCH] messages look better --- TODO.md | 3 +- .../java/com/geeksville/mesh/MainActivity.kt | 13 ++-- .../java/com/geeksville/mesh/ui/MeshApp.kt | 3 +- .../java/com/geeksville/mesh/ui/Messages.kt | 61 ++++++++++++++++--- .../com/geeksville/mesh/ui/NodeInfoCard.kt | 4 +- .../java/com/geeksville/mesh/ui/Status.kt | 16 ++--- .../res/drawable/ic_twotone_person_24.xml | 18 ++++++ 7 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 app/src/main/res/drawable/ic_twotone_person_24.xml diff --git a/TODO.md b/TODO.md index 92987cbde..e7dab9ab0 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,8 @@ # High priority MVP features required for first public alpha -( show username icons in the next window) +* show user icons in chat +* show sent messages in chat * make chat pretty and functional * let user set name and shortname * take video diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index 0314ac849..406967d37 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -21,11 +21,9 @@ import com.geeksville.mesh.ui.* import com.geeksville.util.exceptionReporter import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignInAccount -import com.google.android.gms.auth.api.signin.GoogleSignInOptions import com.google.android.gms.common.api.ApiException import com.google.android.gms.tasks.Task import java.nio.charset.Charset -import java.util.* /* @@ -195,6 +193,7 @@ class MainActivity : AppCompatActivity(), Logging, requestPermission() + /* not yet working // Configure sign-in to request the user's ID, email address, and basic // profile. ID and basic profile are included in DEFAULT_SIGN_IN. // Configure sign-in to request the user's ID, email address, and basic @@ -206,6 +205,8 @@ class MainActivity : AppCompatActivity(), Logging, // Build a GoogleSignInClient with the options specified by gso. UIState.googleSignInClient = GoogleSignIn.getClient(this, gso); + + */ } override fun onDestroy() { @@ -297,9 +298,9 @@ class MainActivity : AppCompatActivity(), Logging, // We only care about nodes that have user info info.user?.id?.let { - val newnodes = UIState.nodes.value.toMutableMap() + val newnodes = NodeDB.nodes.value.toMutableMap() newnodes[it] = info - UIState.nodes.value = newnodes + NodeDB.nodes.value = newnodes } } @@ -314,7 +315,7 @@ 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(Date(), sender, payload.toString(utf8))) + modded.add(TextMessage(sender, payload.toString(utf8))) MessagesState.messages.value = modded } else -> TODO() @@ -347,7 +348,7 @@ class MainActivity : AppCompatActivity(), Logging, debug("connected to mesh service, isConnected=${UIState.isConnected.value}") // make some placeholder nodeinfos - UIState.nodes.value = + NodeDB.nodes.value = m.nodes.toList().map { it.user?.id!! to it }.toMap() diff --git a/app/src/main/java/com/geeksville/mesh/ui/MeshApp.kt b/app/src/main/java/com/geeksville/mesh/ui/MeshApp.kt index 285493f03..270e78c6c 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MeshApp.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MeshApp.kt @@ -42,7 +42,7 @@ fun HomeContent() { Text(if (UIState.isConnected.value) "Connected" else "Not Connected") } - UIState.nodes.value.values.forEach { + NodeDB.nodes.value.values.forEach { NodeInfoCard(it) } @@ -106,7 +106,6 @@ fun HomeContent() { val palette = lightColorPalette() // darkColorPalette() - @Composable fun MeshApp() { val (drawerState, onDrawerStateChange) = state { DrawerState.Closed } diff --git a/app/src/main/java/com/geeksville/mesh/ui/Messages.kt b/app/src/main/java/com/geeksville/mesh/ui/Messages.kt index 39e105941..7063fdf55 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/Messages.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/Messages.kt @@ -3,6 +3,7 @@ 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 import androidx.ui.core.TextField import androidx.ui.foundation.shape.corner.RoundedCornerShape @@ -10,23 +11,30 @@ import androidx.ui.input.ImeAction import androidx.ui.layout.Column import androidx.ui.layout.LayoutPadding import androidx.ui.layout.LayoutSize +import androidx.ui.layout.Row import androidx.ui.material.MaterialTheme +import androidx.ui.material.ProvideEmphasis 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.R import com.geeksville.mesh.ui.MessagesState.messages +import java.text.SimpleDateFormat import java.util.* -data class TextMessage(val date: Date, val from: String, val text: String, val time: Date? = null) +/** + * 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(Date(), "+6508675310", "I found the cache"), - TextMessage(Date(), "+6508675311", "Help! I've fallen and I can't get up.") + 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. @@ -34,6 +42,43 @@ object MessagesState : Logging { val messages = mutableStateOf(MessagesState.testTexts) } +private val dateFormat = SimpleDateFormat("h:mm a") + +/** + * A pretty version the text, with user icon to the left, name and time of arrival (copy slack look and feel) + */ +@Composable +fun MessageCard(msg: TextMessage, modifier: Modifier = Modifier.None) { + + + Row(modifier = modifier) { + VectorImage(id = R.drawable.ic_twotone_person_24, tint = palette.onSecondary) + + Column { + Row { + val nodes = NodeDB.nodes.value + + // If we can't find the sender, just use the ID + val node = nodes?.get(msg.from) + val user = node?.user + val senderName = user?.longName ?: msg.from + Text(text = senderName) + ProvideEmphasis(emphasis = MaterialTheme.emphasisLevels().disabled) { + Text( + text = dateFormat.format(msg.date), + modifier = LayoutPadding(left = 8.dp), + style = MaterialTheme.typography().caption + ) + } + + } + Text( + text = msg.text + ) + } + } +} + @Composable fun MessagesContent() { Column(modifier = LayoutSize.Fill) { @@ -42,9 +87,8 @@ fun MessagesContent() { val topPad = 4.dp messages.value.forEach { - Text( - text = "Text: ${it.text}", - modifier = LayoutPadding( + MessageCard( + it, modifier = LayoutPadding( left = sidePad, right = sidePad, top = topPad, @@ -55,8 +99,7 @@ fun MessagesContent() { val message = state { "text message" } - val colors = MaterialTheme.colors() - val backgroundColor = colors.secondary.copy(alpha = 0.12f) + val backgroundColor = palette.secondary.copy(alpha = 0.12f) Surface( modifier = LayoutPadding(8.dp), @@ -67,7 +110,7 @@ fun MessagesContent() { value = message.value, onValueChange = { message.value = it }, textStyle = TextStyle( - color = colors.onSecondary.copy(alpha = 0.8f) + color = palette.onSecondary.copy(alpha = 0.8f) ), imeAction = ImeAction.Send, onImeActionPerformed = { diff --git a/app/src/main/java/com/geeksville/mesh/ui/NodeInfoCard.kt b/app/src/main/java/com/geeksville/mesh/ui/NodeInfoCard.kt index b29fe7cfe..67e4c4843 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/NodeInfoCard.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/NodeInfoCard.kt @@ -83,7 +83,7 @@ fun NodeInfoCard(node: NodeInfo) { @Composable fun nodeInfoPreview() { Column { - NodeInfoCard(UIState.testNodes[0]) - NodeInfoCard(UIState.testNodeNoPosition) + NodeInfoCard(NodeDB.testNodes[0]) + NodeInfoCard(NodeDB.testNodeNoPosition) } } \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/ui/Status.kt b/app/src/main/java/com/geeksville/mesh/ui/Status.kt index ba75db3b1..d7fc68fed 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/Status.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/Status.kt @@ -4,7 +4,6 @@ import android.util.Base64 import androidx.compose.Model import androidx.compose.mutableStateOf import com.geeksville.mesh.* -import com.google.android.gms.auth.api.signin.GoogleSignInClient data class ScreenInfo(val icon: Int, val label: String) @@ -23,12 +22,7 @@ object AppStatus { var currentScreen: ScreenInfo = Screen.messages } -/// 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 - +object NodeDB { private val testPositions = arrayOf( Position(32.776665, -96.796989, 35), // dallas Position(32.960758, -96.733521, 35), // richardson @@ -66,6 +60,14 @@ object UIState { /// 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) diff --git a/app/src/main/res/drawable/ic_twotone_person_24.xml b/app/src/main/res/drawable/ic_twotone_person_24.xml new file mode 100644 index 000000000..5306b665e --- /dev/null +++ b/app/src/main/res/drawable/ic_twotone_person_24.xml @@ -0,0 +1,18 @@ + + + + +