From a26104e1a3394cef68c2b315da16f4be9d6f0bb2 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Wed, 3 Feb 2021 18:55:17 +0100
Subject: [PATCH] Experimenting with jetpack compose and flow

---
 app/build.gradle.kts                          |   2 +
 .../de/kuschku/quasseldroid/MainActivity.kt   | 224 ++++++++++++++++--
 2 files changed, 205 insertions(+), 21 deletions(-)

diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index cdabc2143..7a3e24cc6 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -60,6 +60,8 @@ dependencies {
   val androidxLifecycleVersion: String by project.extra
   implementation("androidx.lifecycle", "lifecycle-runtime-ktx", androidxLifecycleVersion)
 
+  implementation("org.threeten", "threetenbp", "1.4.0")
+
   implementation("io.coil-kt", "coil", "1.1.1")
   implementation("dev.chrisbanes.accompanist", "accompanist-coil", "0.5.0")
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/MainActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/MainActivity.kt
index a7b09a45e..b3b573a1f 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/MainActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/MainActivity.kt
@@ -2,37 +2,219 @@ package de.kuschku.quasseldroid
 
 import android.os.Bundle
 import androidx.appcompat.app.AppCompatActivity
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.Surface
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.*
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.MoreVert
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.platform.setContent
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.font.FontFamily
 import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
 import de.kuschku.quasseldroid.ui.theme.QuasseldroidTheme
+import de.kuschku.quasseldroid.ui.theme.shapes
+import de.kuschku.quasseldroid.ui.theme.typography
+import dev.chrisbanes.accompanist.coil.CoilImage
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.flow
+import org.threeten.bp.ZonedDateTime
+import org.threeten.bp.format.DateTimeFormatter
+import kotlin.random.Random
+
+val time = flow<ZonedDateTime> {
+  emit(ZonedDateTime.now())
+  delay(1000)
+}
 
 class MainActivity : AppCompatActivity() {
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-        setContent {
-            QuasseldroidTheme {
-                // A surface container using the 'background' color from the theme
-                Surface(color = MaterialTheme.colors.background) {
-                    Greeting("Android")
-                }
-            }
-        }
+  var timer: Job? = null
+  override fun onCreate(savedInstanceState: Bundle?) {
+    super.onCreate(savedInstanceState)
+    setContent {
+      JetChat()
     }
+  }
 }
 
+fun randomColor(): Color = Color(
+  red = Random.nextInt(0, 255),
+  green = Random.nextInt(0, 255),
+  blue = Random.nextInt(0, 255)
+)
+
 @Composable
-fun Greeting(name: String) {
-    Text(text = "Hello $name!")
+fun UserPhoto(
+  imageUrl: String,
+  modifier: Modifier = Modifier,
+) {
+  val ringColor = remember { randomColor() }
+  CoilImage(
+    data = imageUrl as Any,
+    contentDescription = null,
+    modifier = modifier
+      .border(2.dp, ringColor, CircleShape)
+      .padding(4.dp)
+      .clip(CircleShape)
+      .size(38.dp)
+  )
+}
+
+fun parseString(text: String): AnnotatedString {
+  val builder = AnnotatedString.Builder()
+  var monospace = false
+  var lastIndex = 0
+  fun addText(index: Int) {
+    val before = builder.length
+    builder.append(text.substring(lastIndex, index))
+    val after = builder.length
+    if (monospace) builder.addStyle(
+      SpanStyle(
+        fontFamily = FontFamily.Monospace,
+        background = Color.Gray,
+      ),
+      before,
+      after
+    )
+    lastIndex = index + 1
+  }
+  for (i in text.indices) {
+    if (text[i] == '`') {
+      addText(i)
+      monospace = !monospace
+    }
+  }
+  addText(text.length)
+
+  return builder.toAnnotatedString()
 }
 
-@Preview(showBackground = true)
 @Composable
-fun DefaultPreview() {
-    QuasseldroidTheme {
-        Greeting("Android")
+fun ChatText(
+  text: String,
+  modifier: Modifier = Modifier
+) {
+  Text(
+    parseString(text),
+    style = typography.body1,
+    modifier = modifier.padding(8.dp)
+  )
+}
+
+@Composable
+fun ChatBubble(
+  content: @Composable () -> Unit
+) {
+  Surface(
+    color = Color.LightGray,
+    shape = shapes.medium,
+    modifier = Modifier
+      .padding(2.dp)
+  ) {
+    content()
+  }
+}
+
+@Composable
+fun ChatMessage(
+  authorName: String,
+  authorImageUrl: String,
+  dateSent: String,
+  content: @Composable () -> Unit
+) {
+  Row {
+    UserPhoto(
+      authorImageUrl,
+      modifier = Modifier.padding(
+        start = 4.dp,
+        top = 4.dp,
+        bottom = 4.dp,
+        end = 12.dp
+      )
+    )
+    Column {
+      Row(verticalAlignment = Alignment.CenterVertically) {
+        Text(authorName, style = typography.h6)
+        Spacer(modifier = Modifier.padding(4.dp))
+        Text(
+          dateSent,
+          style = typography.body2.copy(
+            color = MaterialTheme.colors.onSurface
+          )
+        )
+      }
+      content()
     }
-}
\ No newline at end of file
+  }
+}
+
+@Composable
+fun InputLine() {
+  var text by remember { mutableStateOf("") }
+
+  Row {
+    Box {
+      TextField(
+        value = text,
+        onValueChange = { text = it },
+        textStyle = typography.body1,
+      )
+      if (text.isEmpty()) {
+        Text("Send a message")
+      }
+    }
+    Icon(Icons.Outlined.MoreVert, "more")
+  }
+}
+
+@Composable
+fun TimeDisplay() {
+  val time: ZonedDateTime by time.collectAsState(ZonedDateTime.now())
+
+  Text(time.format(DateTimeFormatter.ISO_DATE_TIME))
+}
+
+@Preview
+@Composable
+fun JetChat() {
+  QuasseldroidTheme {
+    Scaffold(
+      topBar = { TimeDisplay() },
+      bottomBar = { InputLine() },
+      bodyContent = {
+        Column {
+          ChatMessage(
+            authorName = "Ali Conors",
+            authorImageUrl = "https://picsum.photos/300/300",
+            dateSent = "3:50 PM",
+          ) {
+            ChatBubble {
+              ChatText("Yeah i’ve been mainly referring to the JetNews Sample :+1:")
+            }
+          }
+          ChatMessage(
+            authorName = "Taylor Brooks",
+            authorImageUrl = "https://picsum.photos/300/300",
+            dateSent = "10:50 PM",
+          ) {
+            ChatBubble {
+              ChatText("Take a look at the `Flow.collectAsState()` APIs")
+            }
+            ChatBubble {
+              ChatText("You can use all the same stuff")
+            }
+          }
+
+        }
+      }
+    )
+  }
+}
-- 
GitLab