JetpackCompose — Weather App — random design — code snippet

This is just one of many in the series of a “Random design and its implementation in jetpack compose beta 08”.

The code and its design might come in handy sometime in the future, might as well share it with others.

Speaking of code, its not pretty, its just to play around. It’s definitely not something anybody wants to ship to production.

Design 1

/***
[LocationScreen] is a screen who displays weather info for a single location
@param[locationName] location for which to display weather info for
*/
@Composable
fun LocationScreen(navController: NavController, locationName: String = "Seoul"){
val sunnyColor = Color(0xFFFFF2B2)
val sunnyColorEnd = Color(0xFFECDA82)
val sunnyGradient = Brush.verticalGradient(
listOf(sunnyColor, sunnyColorEnd)
)

Surface(){
Scaffold(
modifier = Modifier.background(sunnyColor),
backgroundColor = Color.Transparent,
topBar = {
TopAppBar(
backgroundColor = Color.Transparent,
title = { Text("") },
modifier = Modifier.padding(0.dp),
elevation = 0.dp,
actions = {
IconButton(onClick = { /*TODO*/ }) {
Icon(Icons.Default.Search, null, tint = Color.Black)
}
}
)
}
) {
Column(modifier = Modifier.background(Color.White).fillMaxSize()) {
Column(
modifier = Modifier
.fillMaxWidth()
.background(sunnyGradient),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Seoul", fontWeight = FontWeight.Bold, fontSize = 28.sp)
Text("Sunday, 13. Junij", fontSize = 14.sp)
Spacer(Modifier.height(16.dp))


Text("20°", fontSize = 64.sp, fontWeight = FontWeight.Light)
Text("27° / 9°")
Text("Sunny", fontWeight = FontWeight.Bold)


val imgUrl =
"https://vreme.arso.gov.si/app/common/images/svg/weather/partCloudy_day.svg"
val imageLoader = ImageLoader.Builder(LocalContext.current)
.componentRegistry {
add(SvgDecoder(LocalContext.current))
}
.build()

CompositionLocalProvider(LocalImageLoader provides imageLoader) {
// This will automatically use the value of LocalImageLoader
Image(
painter = rememberCoilPainter(imgUrl),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.height(150.dp)
)
}

Row(){
CurrentForecastDetailItem(
detailText = "šibek",
detailValue = "9km/h",
icon = Icons.Default.Air,
iconBackgroundColor = Color(0xFFe4f4e5),
iconColor = Color(0xFF98d2a5))

CurrentForecastDetailItem(
detailText = "srednja",
detailValue = "50%",
icon = Icons.Default.Bloodtype,
iconBackgroundColor = Color(0xFFe0eff6),
iconColor = Color(0xFF7dc1e5)
)
}

Canvas(modifier = Modifier
.fillMaxWidth()
.height(50.dp), onDraw = {

val path3 = Path().apply {
moveTo(size.width * 0.5f, size.height)
quadraticBezierTo(
size.width * 0.5f,
0f,
size.width * 0.8f,
size.height * 0.1f
)
lineTo(size.width, size.height)
close()
}
drawPath(path3, sunnyColor.copy(alpha = 0.5f))

val path2 = Path().apply {
moveTo(0f, size.height)
quadraticBezierTo(
size.width * 0.1f,
0f,
size.width * 0.3f,
size.height * 0.1f
)
lineTo(size.width, size.height)
close()
}
drawPath(path2, sunnyColor.copy(alpha = 0.5f))
// drawPath(path2, Color.Red)

val path = Path().apply {
moveTo(0f, size.height)
quadraticBezierTo(size.width * 0.3f, 0f, size.width, size.height)
close()
}
drawPath(path, Color.White)
})


}

Row(modifier = Modifier
.padding(16.dp)
.horizontalScroll(rememberScrollState())
) {
Forecast1hCard()
Forecast1hCard()
Forecast1hCard()
Forecast1hCard()
Forecast1hCard()
}
}
}
}
}

@Composable
fun Forecast1hCard(){
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier
.padding(8.dp)
.border(1.dp, Color.LightGray)
.padding(8.dp)){
Text("12:00", fontSize = 14.sp)
Text("\uF00D", fontFamily = weatherFontFamily, fontSize = 24.sp)
Text("27° / 9°", fontSize = 14.sp)
}
}

@Composable
private fun CurrentForecastDetailItem(detailText: String, detailValue: String, icon: ImageVector, iconBackgroundColor: Color, iconColor: Color) {
Row(modifier = Modifier.padding(8.dp)){
Box(modifier = Modifier
.clip(RoundedCornerShape(10.dp))
.size(40.dp)
.background(color = iconBackgroundColor),
contentAlignment = Alignment.Center
) {
Icon(icon, contentDescription = null, tint = iconColor)
}

Spacer(modifier = Modifier.width(8.dp))

Column() {
Text(detailText, fontSize = 14.sp)
Text(detailValue, fontSize = 12.sp)
}
}
}

Design 2

/***
[LocationScreen] is a screen who displays weather info for a single location
@param[locationName] location for which to display weather info for
*/
@Composable
fun LocationScreen(navController: NavController, locationName: String = "Seoul"){
val sunnyColor = Color(0xFFffeb95)

Surface(){
Scaffold(
modifier = Modifier,
backgroundColor = sunnyColor,
topBar = {
TopAppBar(
title = { Text("") },
modifier = Modifier.padding(16.dp),
elevation = 0.dp,
actions = {
IconButton(onClick = { /*TODO*/ }) {
Icon(Icons.Default.Search, null)
}
}
)
}
) {
Column(modifier = Modifier.fillMaxSize().background(Color.White)) {

Box(modifier = Modifier.fillMaxWidth().height(300.dp)){
Canvas(modifier = Modifier.fillMaxSize(), onDraw = {
val path = Path().apply{
moveTo(x = 0f, y = 0f)
lineTo(x = 0f, y = size.height)
lineTo(x = size.width, y = size.height - 150f)
lineTo(x = size.width, y = 0f)
close()
}

drawPath(path = path, color = sunnyColor)
})
Column(modifier = Modifier.padding(16.dp)) {
Column() {
Text("Seoul", fontSize = 42.sp)
Text("Sunny", fontSize = 20.sp)
}
Spacer(Modifier.height(32.dp))

Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Text("\uF00D", fontFamily = weatherFontFamily, fontSize = 82.sp)

Column(horizontalAlignment = Alignment.Start) {
Text(buildAnnotatedString {
append("20")
withStyle(SpanStyle(baselineShift = BaselineShift.Superscript, fontSize = 16.sp)){
append("C")
}
}
, fontSize = 48.sp)

Row(){

Text("9C")
Icon(Icons.Default.KeyboardArrowDown, null, modifier = Modifier.size(14.dp))
Spacer(Modifier.width(8.dp))
Text("28C")
Icon(Icons.Default.KeyboardArrowUp, null, modifier = Modifier.size(14.dp))
}
}
}
}
}


Spacer(Modifier.height(16.dp))

Row(modifier = Modifier.padding(16.dp).horizontalScroll(rememberScrollState())) {
Forecast1hCard(true)
Forecast1hCard()
Forecast1hCard()
Forecast1hCard()
Forecast1hCard()
Forecast1hCard()
Forecast1hCard()
Forecast1hCard()
Forecast1hCard()
}
}
}
}
}

@Composable
fun Forecast1hCard(active: Boolean = false){
val roundShape = RoundedCornerShape(10)
val hourFormatter = DateTimeFormatter.ofPattern("HH:mm")

var modifier = Modifier
.clip(roundShape)
.border(BorderStroke(1.dp, Color(0xFFe8e9ec)), roundShape)

if(active){
modifier = modifier.background(
brush = Brush.verticalGradient(
colors = listOf(
Color(0xffa5c6fd),
Color(0xff5a95fb)
)
)
)
}

val textColor = Color.Black

Column(
modifier = modifier.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "12:00",
color = textColor,
fontSize = 14.sp,
fontWeight = FontWeight.Normal
)

Text("\uF00D", fontFamily = weatherFontFamily, fontSize = 24.sp)

Text(buildAnnotatedString {
append("20")
withStyle(SpanStyle(baselineShift = BaselineShift.Superscript, fontSize = 10.sp, fontWeight = FontWeight.Normal)){
append("c")
}
}
, fontWeight = FontWeight.Bold, color = textColor)

Text("9km/h", fontSize = 12.sp, color = textColor)
Text("40%", fontSize = 12.sp, color = textColor)
}
Spacer(modifier = Modifier.width(16.dp))
}

developer