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