Added footer, scrollable conversation and global UI improvements
This commit is contained in:
parent
2157a7e26f
commit
75bf1c3389
@ -11,7 +11,9 @@
|
|||||||
<entry key="../../../../../layout/compose-model-1641145605520.xml" value="0.8685185185185185" />
|
<entry key="../../../../../layout/compose-model-1641145605520.xml" value="0.8685185185185185" />
|
||||||
<entry key="../../../../../layout/compose-model-1641154451614.xml" value="0.8768518518518519" />
|
<entry key="../../../../../layout/compose-model-1641154451614.xml" value="0.8768518518518519" />
|
||||||
<entry key="../../../../../layout/compose-model-1641155782430.xml" value="0.7886363636363637" />
|
<entry key="../../../../../layout/compose-model-1641155782430.xml" value="0.7886363636363637" />
|
||||||
|
<entry key="../../../../../layout/compose-model-1641156150634.xml" value="0.33" />
|
||||||
<entry key="app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.5307291666666667" />
|
<entry key="app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.5307291666666667" />
|
||||||
|
<entry key="app/src/main/res/drawable/ic_baseline_more_vert_24.xml" value="0.38981481481481484" />
|
||||||
<entry key="app/src/main/res/drawable/ic_baseline_person_24.xml" value="0.5307291666666667" />
|
<entry key="app/src/main/res/drawable/ic_baseline_person_24.xml" value="0.5307291666666667" />
|
||||||
<entry key="app/src/main/res/drawable/ic_launcher_background.xml" value="0.5307291666666667" />
|
<entry key="app/src/main/res/drawable/ic_launcher_background.xml" value="0.5307291666666667" />
|
||||||
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.5307291666666667" />
|
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.5307291666666667" />
|
||||||
|
@ -4,9 +4,7 @@ import android.os.Bundle
|
|||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
@ -16,8 +14,6 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.font.Font
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@ -79,9 +75,32 @@ fun Base() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Footer() {
|
||||||
|
//We create a row that we align to the bottom center of the parent box
|
||||||
|
Row(
|
||||||
|
Modifier
|
||||||
|
.padding(bottom = 50.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.Bottom,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
//Microphone floating button to manually start/stop listening
|
||||||
|
FloatingActionButton(onClick = { /*TODO*/ }) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_baseline_mic_24),
|
||||||
|
contentDescription = "microphone"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MessageFromJarvis(text: String) {
|
fun MessageFromJarvis(text: String) {
|
||||||
|
//We create a row to contain the message and the robot image (to look like an sms)
|
||||||
Row(Modifier.padding(bottom = 25.dp)) {
|
Row(Modifier.padding(bottom = 25.dp)) {
|
||||||
|
|
||||||
|
// Adding the robot image as the sender
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(id = R.drawable.robot256),
|
painter = painterResource(id = R.drawable.robot256),
|
||||||
contentDescription = "robot",
|
contentDescription = "robot",
|
||||||
@ -90,13 +109,13 @@ fun MessageFromJarvis(text: String) {
|
|||||||
.padding(end = 10.dp)
|
.padding(end = 10.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Adding the message box with the text given in the params
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(fraction = 0.9F)
|
.fillMaxWidth(fraction = 0.9F)
|
||||||
.clip(RoundedCornerShape(15.dp))
|
.clip(RoundedCornerShape(15.dp))
|
||||||
.background(color = MaterialTheme.colors.secondaryVariant)
|
.background(color = MaterialTheme.colors.secondaryVariant)
|
||||||
.padding(horizontal = 10.dp, vertical = 5.dp)
|
.padding(horizontal = 10.dp, vertical = 5.dp)
|
||||||
|
|
||||||
) {
|
) {
|
||||||
Text(text = text, fontFamily = productSansFont)
|
Text(text = text, fontFamily = productSansFont)
|
||||||
}
|
}
|
||||||
@ -105,10 +124,13 @@ fun MessageFromJarvis(text: String) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MessageFromUser(text: String) {
|
fun MessageFromUser(text: String) {
|
||||||
|
//We create a row to contain the user message and we align the row to the right side (to look like a conversation between two people)
|
||||||
Row(
|
Row(
|
||||||
Modifier
|
Modifier
|
||||||
.padding(bottom = 25.dp)
|
.padding(bottom = 25.dp)
|
||||||
.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
|
.fillMaxWidth(), horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
// The message box with the text
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(fraction = 0.8F)
|
.fillMaxWidth(fraction = 0.8F)
|
||||||
@ -119,23 +141,48 @@ fun MessageFromUser(text: String) {
|
|||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
fontFamily = productSansFont,
|
fontFamily = productSansFont,
|
||||||
color = if (!isSystemInDarkTheme()) Color.White else Color(15, 15, 15, 255))
|
color = if (!isSystemInDarkTheme()) Color.White else Color(15, 15, 15, 255)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun DefaultPreview() {
|
fun DefaultPreview() {
|
||||||
JarvisComposeTheme {
|
JarvisComposeTheme {
|
||||||
Column(Modifier.padding(top = 40.dp, start = 20.dp, end = 20.dp)) {
|
//We create a main box with basic padding to avoid having stuff too close to every side.
|
||||||
Base()
|
Box(
|
||||||
MessageFromJarvis(text = "Salut, je suis Jarvis! \nPose moi une question et je ferais de mon mieux pour te renseigner.")
|
Modifier
|
||||||
MessageFromUser(text = "Quel temps fait-il à Paris en ce moment ?")
|
.fillMaxHeight()
|
||||||
MessageFromJarvis(text = "A Paris, il fait actuellement 10 degrés et le ciel est nuageux.")
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 20.dp)
|
||||||
|
.padding(top = 30.dp, bottom = 0.dp)
|
||||||
|
) {
|
||||||
|
|
||||||
|
// This column regroup the base and all the conversations (everything except the footer)
|
||||||
|
Column {
|
||||||
|
Base()
|
||||||
|
|
||||||
|
// This column regroup only the conversations and make them scrollable
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.weight(weight = 1f, fill = false)
|
||||||
|
) {
|
||||||
|
// Basic interaction stuff for demo
|
||||||
|
MessageFromJarvis(text = "Salut, je suis Jarvis! \nPose moi une question et je ferais de mon mieux pour te renseigner.")
|
||||||
|
MessageFromUser(text = "Quel temps fait-il à Paris en ce moment ?")
|
||||||
|
MessageFromJarvis(text = "A Paris, il fait actuellement 10 degrés et le ciel est nuageux.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Finally we add the footer to the bottom center of the main box
|
||||||
|
Column(Modifier.align(Alignment.BottomCenter)) {
|
||||||
|
Footer()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,332 @@
|
|||||||
|
// Thanks to EugeneTheDev : https://gist.github.com/EugeneTheDev/a27664cb7e7899f964348b05883cbccd
|
||||||
|
|
||||||
|
package ch.mathieubroillet.jarvis.android.utils
|
||||||
|
|
||||||
|
import androidx.compose.animation.core.*
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.draw.scale
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
val dotSize = 20.dp
|
||||||
|
val delayUnit = 150
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DotsPulsing() {
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Dot(
|
||||||
|
scale: Float
|
||||||
|
) = Spacer(
|
||||||
|
Modifier
|
||||||
|
.size(dotSize)
|
||||||
|
.scale(scale)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colors.primary,
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val infiniteTransition = rememberInfiniteTransition()
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun animateScaleWithDelay(delay: Int) = infiniteTransition.animateFloat(
|
||||||
|
initialValue = 0f,
|
||||||
|
targetValue = 0f,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = keyframes {
|
||||||
|
durationMillis = delayUnit * 4
|
||||||
|
0f at delay with LinearEasing
|
||||||
|
1f at delay + delayUnit with LinearEasing
|
||||||
|
0f at delay + delayUnit * 2
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val scale1 by animateScaleWithDelay(0)
|
||||||
|
val scale2 by animateScaleWithDelay(delayUnit)
|
||||||
|
val scale3 by animateScaleWithDelay(delayUnit * 2)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
val spaceSize = 2.dp
|
||||||
|
|
||||||
|
Dot(scale1)
|
||||||
|
Spacer(Modifier.width(spaceSize))
|
||||||
|
Dot(scale2)
|
||||||
|
Spacer(Modifier.width(spaceSize))
|
||||||
|
Dot(scale3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DotsElastic() {
|
||||||
|
val minScale = 0.6f
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Dot(
|
||||||
|
scale: Float
|
||||||
|
) = Spacer(
|
||||||
|
Modifier
|
||||||
|
.size(dotSize)
|
||||||
|
.scale(scaleX = minScale, scaleY = scale)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colors.primary,
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val infiniteTransition = rememberInfiniteTransition()
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun animateScaleWithDelay(delay: Int) = infiniteTransition.animateFloat(
|
||||||
|
initialValue = minScale,
|
||||||
|
targetValue = minScale,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = keyframes {
|
||||||
|
durationMillis = delayUnit * 4
|
||||||
|
minScale at delay with LinearEasing
|
||||||
|
1f at delay + delayUnit with LinearEasing
|
||||||
|
minScale at delay + delayUnit * 2
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val scale1 by animateScaleWithDelay(0)
|
||||||
|
val scale2 by animateScaleWithDelay(delayUnit)
|
||||||
|
val scale3 by animateScaleWithDelay(delayUnit * 2)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
val spaceSize = 2.dp
|
||||||
|
|
||||||
|
Dot(scale1)
|
||||||
|
Spacer(Modifier.width(spaceSize))
|
||||||
|
Dot(scale2)
|
||||||
|
Spacer(Modifier.width(spaceSize))
|
||||||
|
Dot(scale3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DotsFlashing() {
|
||||||
|
val minAlpha = 0.1f
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Dot(
|
||||||
|
alpha: Float
|
||||||
|
) = Spacer(
|
||||||
|
Modifier
|
||||||
|
.size(dotSize)
|
||||||
|
.alpha(alpha)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colors.primary,
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val infiniteTransition = rememberInfiniteTransition()
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun animateAlphaWithDelay(delay: Int) = infiniteTransition.animateFloat(
|
||||||
|
initialValue = minAlpha,
|
||||||
|
targetValue = minAlpha,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = keyframes {
|
||||||
|
durationMillis = delayUnit * 4
|
||||||
|
minAlpha at delay with LinearEasing
|
||||||
|
1f at delay + delayUnit with LinearEasing
|
||||||
|
minAlpha at delay + delayUnit * 2
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val alpha1 by animateAlphaWithDelay(0)
|
||||||
|
val alpha2 by animateAlphaWithDelay(delayUnit)
|
||||||
|
val alpha3 by animateAlphaWithDelay(delayUnit * 2)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
val spaceSize = 2.dp
|
||||||
|
|
||||||
|
Dot(alpha1)
|
||||||
|
Spacer(Modifier.width(spaceSize))
|
||||||
|
Dot(alpha2)
|
||||||
|
Spacer(Modifier.width(spaceSize))
|
||||||
|
Dot(alpha3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DotsTyping() {
|
||||||
|
val maxOffset = 10f
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Dot(
|
||||||
|
offset: Float
|
||||||
|
) = Spacer(
|
||||||
|
Modifier
|
||||||
|
.size(dotSize)
|
||||||
|
.offset(y = -offset.dp)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colors.primary,
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val infiniteTransition = rememberInfiniteTransition()
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun animateOffsetWithDelay(delay: Int) = infiniteTransition.animateFloat(
|
||||||
|
initialValue = 0f,
|
||||||
|
targetValue = 0f,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = keyframes {
|
||||||
|
durationMillis = delayUnit * 4
|
||||||
|
0f at delay with LinearEasing
|
||||||
|
maxOffset at delay + delayUnit with LinearEasing
|
||||||
|
0f at delay + delayUnit * 2
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val offset1 by animateOffsetWithDelay(0)
|
||||||
|
val offset2 by animateOffsetWithDelay(delayUnit)
|
||||||
|
val offset3 by animateOffsetWithDelay(delayUnit * 2)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier.padding(top = maxOffset.dp)
|
||||||
|
) {
|
||||||
|
val spaceSize = 2.dp
|
||||||
|
|
||||||
|
Dot(offset1)
|
||||||
|
Spacer(Modifier.width(spaceSize))
|
||||||
|
Dot(offset2)
|
||||||
|
Spacer(Modifier.width(spaceSize))
|
||||||
|
Dot(offset3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DotsCollision() {
|
||||||
|
val maxOffset = 30f
|
||||||
|
val delayUnit = 500 // it's better to use longer delay for this animation
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Dot(
|
||||||
|
offset: Float
|
||||||
|
) = Spacer(
|
||||||
|
Modifier
|
||||||
|
.size(dotSize)
|
||||||
|
.offset(x = offset.dp)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colors.primary,
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val infiniteTransition = rememberInfiniteTransition()
|
||||||
|
|
||||||
|
val offsetLeft by infiniteTransition.animateFloat(
|
||||||
|
initialValue = 0f,
|
||||||
|
targetValue = 0f,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = keyframes {
|
||||||
|
durationMillis = delayUnit * 3
|
||||||
|
0f at 0 with LinearEasing
|
||||||
|
-maxOffset at delayUnit / 2 with LinearEasing
|
||||||
|
0f at delayUnit
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val offsetRight by infiniteTransition.animateFloat(
|
||||||
|
initialValue = 0f,
|
||||||
|
targetValue = 0f,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = keyframes {
|
||||||
|
durationMillis = delayUnit * 3
|
||||||
|
0f at delayUnit with LinearEasing
|
||||||
|
maxOffset at delayUnit + delayUnit / 2 with LinearEasing
|
||||||
|
0f at delayUnit * 2
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier.padding(horizontal = maxOffset.dp)
|
||||||
|
) {
|
||||||
|
val spaceSize = 2.dp
|
||||||
|
|
||||||
|
Dot(offsetLeft)
|
||||||
|
Spacer(Modifier.width(spaceSize))
|
||||||
|
Dot(0f)
|
||||||
|
Spacer(Modifier.width(spaceSize))
|
||||||
|
Dot(offsetRight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun DotsPreview() = MaterialTheme {
|
||||||
|
Column(modifier = Modifier.padding(4.dp)) {
|
||||||
|
val spaceSize = 16.dp
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Dots pulsing",
|
||||||
|
style = MaterialTheme.typography.h5
|
||||||
|
)
|
||||||
|
DotsPulsing()
|
||||||
|
|
||||||
|
Spacer(Modifier.height(spaceSize))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Dots elastic",
|
||||||
|
style = MaterialTheme.typography.h5
|
||||||
|
)
|
||||||
|
DotsElastic()
|
||||||
|
|
||||||
|
Spacer(Modifier.height(spaceSize))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Dots flashing",
|
||||||
|
style = MaterialTheme.typography.h5
|
||||||
|
)
|
||||||
|
DotsFlashing()
|
||||||
|
|
||||||
|
Spacer(Modifier.height(spaceSize))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Dots typing",
|
||||||
|
style = MaterialTheme.typography.h5
|
||||||
|
)
|
||||||
|
DotsTyping()
|
||||||
|
|
||||||
|
Spacer(Modifier.height(spaceSize))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Dots collision",
|
||||||
|
style = MaterialTheme.typography.h5
|
||||||
|
)
|
||||||
|
DotsCollision()
|
||||||
|
}
|
||||||
|
}
|
@ -6,5 +6,5 @@
|
|||||||
android:tint="?attr/colorControlNormal">
|
android:tint="?attr/colorControlNormal">
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white"
|
android:fillColor="@android:color/white"
|
||||||
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
android:pathData="M12,14c1.66,0 2.99,-1.34 2.99,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.3,11c0,3 -2.54,5.1 -5.3,5.1S6.7,14 6.7,11L5,11c0,3.41 2.72,6.23 6,6.72L11,21h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z"/>
|
||||||
</vector>
|
</vector>
|
Loading…
Reference in New Issue
Block a user