Skip to content

Commit e137566

Browse files
author
piotrprus
committed
Change the card design a bit
1 parent c1853ef commit e137566

File tree

7 files changed

+122
-90
lines changed

7 files changed

+122
-90
lines changed

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ dependencies {
5353
implementation("androidx.compose.ui:ui:${rootProject.extra["compose_version"]}")
5454
implementation("androidx.compose.material:material:${rootProject.extra["compose_version"]}")
5555
implementation("androidx.compose.ui:ui-tooling:${rootProject.extra["compose_version"]}")
56+
implementation("androidx.compose.runtime:runtime-livedata:${rootProject.extra["compose_version"]}")
5657
implementation("androidx.compose.material:material-icons-extended:${rootProject.extra["compose_version"]}")
5758
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.1")
5859
implementation("androidx.activity:activity-compose:1.3.0-beta01")

app/src/main/java/com/piotrprus/weathercard/MainActivity.kt

Lines changed: 102 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ package com.piotrprus.weathercard
33
import android.os.Bundle
44
import androidx.activity.ComponentActivity
55
import androidx.activity.compose.setContent
6+
import androidx.activity.viewModels
67
import androidx.compose.foundation.Canvas
8+
import androidx.compose.foundation.Image
9+
import androidx.compose.foundation.background
710
import androidx.compose.foundation.isSystemInDarkTheme
811
import androidx.compose.foundation.layout.*
912
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -12,119 +15,128 @@ import androidx.compose.material.icons.Icons
1215
import androidx.compose.material.icons.filled.Air
1316
import androidx.compose.material.icons.filled.Water
1417
import androidx.compose.material.icons.filled.WbSunny
15-
import androidx.compose.runtime.Composable
16-
import androidx.compose.runtime.mutableStateOf
17-
import androidx.compose.runtime.remember
18+
import androidx.compose.runtime.*
19+
import androidx.compose.runtime.livedata.observeAsState
1820
import androidx.compose.ui.Alignment
1921
import androidx.compose.ui.Modifier
2022
import androidx.compose.ui.geometry.Offset
2123
import androidx.compose.ui.graphics.Color
2224
import androidx.compose.ui.graphics.nativeCanvas
2325
import androidx.compose.ui.platform.LocalDensity
24-
import androidx.compose.ui.tooling.preview.Preview
26+
import androidx.compose.ui.res.painterResource
27+
import androidx.compose.ui.text.font.FontWeight
2528
import androidx.compose.ui.unit.dp
2629
import com.piotrprus.weathercard.ui.theme.WeatherCardTheme
2730

2831
class MainActivity : ComponentActivity() {
32+
private val forecastMockState = mutableStateListOf(
33+
WeatherItem(date = "Mon, 8:00 AM, Cloudy", temperature = 12, 30, 2, R.drawable.cloudy),
34+
WeatherItem(date = "Mon, 9:00 AM, Cloudy", temperature = 14, 60, 3, R.drawable.cloudy),
35+
WeatherItem(date = "Mon, 10:00 AM, Mostly cloudy", temperature = 15, 80, 5, R.drawable.rain),
36+
WeatherItem(date = "Mon, 11:00 AM, Mostly sunny", temperature = 15, 30, 2, R.drawable.sunny),
37+
WeatherItem(date = "Mon, 12:00 PM, Mostly sunny", temperature = 18, 20, 1, R.drawable.sunny),
38+
WeatherItem(date = "Mon, 1:00 PM, Sunny", temperature = 20, 0, 1, R.drawable.sunny),
39+
WeatherItem(date = "Mon, 2:00 PM, Sunny", temperature = 20, 0, 2, R.drawable.sunny),
40+
WeatherItem(date = "Mon, 3:00 PM, Sunny", temperature = 19, 0, 2, R.drawable.sunny),
41+
WeatherItem(date = "Mon, 4:00 PM, Sunny", temperature = 19, 0, 2, R.drawable.sunny),
42+
WeatherItem(date = "Mon, 5:00 PM, Sunny", temperature = 17, 0, 3, R.drawable.sunny),
43+
WeatherItem(date = "Mon, 6:00 PM, Heavy showers", temperature = 16, 80, 7, R.drawable.rain),
44+
WeatherItem(date = "Mon, 7:00 PM, Heavy showers", temperature = 15, 90, 9, R.drawable.rain),
45+
)
46+
47+
private val viewModel: MainViewModel by viewModels()
48+
2949
override fun onCreate(savedInstanceState: Bundle?) {
3050
super.onCreate(savedInstanceState)
3151
setContent {
3252
WeatherCardTheme {
3353
// A surface container using the 'background' color from the theme
3454
Surface(color = MaterialTheme.colors.background) {
35-
WeatherCard(
36-
WeatherItem(
37-
date = "MON 8:32PM",
38-
temperature = 21,
39-
precipitation = 2,
40-
windSpeed = 5
41-
)
42-
)
55+
val selectedValue: Int by viewModel.selected.observeAsState(initial = 0)
56+
WeatherCard(forecastMockState, selectedValue) {
57+
viewModel.onValueChanged(it)
58+
}
4359
}
4460
}
4561
}
4662
}
4763
}
4864

49-
@Preview
50-
@Composable
51-
fun PreviewWeatherCard() {
52-
WeatherCard(
53-
WeatherItem(
54-
date = "MON, 8.32PM",
55-
temperature = 21,
56-
precipitation = 2,
57-
windSpeed = 5
58-
)
59-
)
60-
}
61-
62-
6365
@Composable
64-
private fun WeatherCard(data: WeatherItem) {
66+
private fun WeatherCard(list: List<WeatherItem>, selectedValue: Int, onValueChange: (Int) -> Unit) {
67+
val item by remember(selectedValue, list) {
68+
derivedStateOf { list[selectedValue] }
69+
}
6570
Card(
6671
modifier = Modifier
6772
.fillMaxWidth()
68-
.padding(8.dp),
73+
.padding(12.dp),
6974
elevation = 4.dp,
7075
shape = RoundedCornerShape(12.dp),
7176
) {
7277
Column(modifier = Modifier.padding(12.dp)) {
73-
Text(text = "Hong Kong", style = MaterialTheme.typography.h4)
74-
Spacer(modifier = Modifier.height(8.dp))
75-
Text(text = data.date, style = MaterialTheme.typography.subtitle1)
76-
Spacer(modifier = Modifier.height(8.dp))
77-
Row(
78-
modifier = Modifier.fillMaxWidth(),
79-
horizontalArrangement = Arrangement.SpaceEvenly,
80-
verticalAlignment = Alignment.CenterVertically
81-
) {
82-
Row {
83-
Text(text = data.temperature.toString(), style = MaterialTheme.typography.h1)
84-
Text(
85-
modifier = Modifier.padding(top = 10.dp),
86-
text = "°C",
87-
style = MaterialTheme.typography.h3
88-
)
89-
}
90-
Icon(
91-
modifier = Modifier.size(60.dp),
92-
imageVector = Icons.Default.WbSunny,
93-
contentDescription = "Sun icon",
94-
tint = MaterialTheme.colors.onSurface
95-
)
96-
}
97-
Spacer(modifier = Modifier.height(8.dp))
98-
Row(
99-
modifier = Modifier.fillMaxWidth(),
100-
horizontalArrangement = Arrangement.SpaceEvenly
101-
) {
102-
Row(verticalAlignment = Alignment.CenterVertically) {
103-
Icon(imageVector = Icons.Default.Water, contentDescription = "Water icon")
104-
Spacer(modifier = Modifier.width(4.dp))
105-
Text(
106-
text = "${data.precipitation}% Precipitation",
107-
style = MaterialTheme.typography.subtitle2
108-
)
109-
}
110-
Row(verticalAlignment = Alignment.CenterVertically) {
111-
Icon(imageVector = Icons.Default.Air, contentDescription = "Air icon")
112-
Spacer(modifier = Modifier.width(4.dp))
113-
Text(
114-
text = "${data.windSpeed} km/h Winds",
115-
style = MaterialTheme.typography.subtitle2
116-
)
117-
}
118-
}
119-
ForecastSlider()
78+
MeasurementView(item)
79+
ForecastSlider(
80+
list.map { it.date },
81+
onValueChange = { onValueChange(it) },
82+
value = selectedValue.toFloat()
83+
)
84+
}
85+
}
86+
}
87+
88+
@Composable
89+
private fun MeasurementView(data: WeatherItem) {
90+
Text(text = "Hong Kong", style = MaterialTheme.typography.h5)
91+
Spacer(modifier = Modifier.height(8.dp))
92+
Text(text = data.date, style = MaterialTheme.typography.body2.copy(color = Color.Gray))
93+
Spacer(modifier = Modifier.height(8.dp))
94+
Row(
95+
modifier = Modifier.fillMaxWidth(),
96+
horizontalArrangement = Arrangement.SpaceEvenly,
97+
verticalAlignment = Alignment.CenterVertically
98+
) {
99+
Row {
100+
Text(text = data.temperature.toString(), style = MaterialTheme.typography.h1)
101+
Text(
102+
modifier = Modifier.padding(top = 10.dp),
103+
text = "°C",
104+
style = MaterialTheme.typography.h3
105+
)
106+
}
107+
Image(
108+
modifier = Modifier.size(100.dp),
109+
painter = painterResource(id = data.icon),
110+
contentDescription = "Weather icon"
111+
)
112+
}
113+
Spacer(modifier = Modifier.height(8.dp))
114+
Row(
115+
modifier = Modifier.fillMaxWidth(),
116+
horizontalArrangement = Arrangement.SpaceEvenly
117+
) {
118+
Row(verticalAlignment = Alignment.CenterVertically) {
119+
Icon(imageVector = Icons.Default.Water, contentDescription = "Water icon")
120+
Spacer(modifier = Modifier.width(4.dp))
121+
Text(
122+
text = "${data.precipitation}% Precipitation",
123+
style = MaterialTheme.typography.body2.copy(color = Color.Gray)
124+
)
125+
}
126+
Row(verticalAlignment = Alignment.CenterVertically) {
127+
Icon(imageVector = Icons.Default.Air, contentDescription = "Air icon")
128+
Spacer(modifier = Modifier.width(4.dp))
129+
Text(
130+
text = "${data.windSpeed} km/h Winds",
131+
style = MaterialTheme.typography.body2.copy(color = Color.Gray)
132+
)
120133
}
121134
}
122135
}
123136

124137
@Composable
125-
fun ForecastSlider() {
126-
val (sliderValue, setSliderValue) = remember { mutableStateOf(6f) }
127-
val steps = 11
138+
fun ForecastSlider(dates: List<String>, value: Float, onValueChange: (Int) -> Unit) {
139+
val (sliderValue, setSliderValue) = remember { mutableStateOf(value) }
128140
val drawPadding = with(LocalDensity.current) { 10.dp.toPx() }
129141
val textSize = with(LocalDensity.current) { 10.dp.toPx() }
130142
val lineHeightDp = 10.dp
@@ -147,17 +159,17 @@ fun ForecastSlider() {
147159
)
148160
) {
149161
val yStart = 0f
150-
val distance = (size.width.minus(2 * drawPadding)).div(steps + 1)
151-
(0..steps.plus(1)).forEach { step ->
162+
val distance = (size.width.minus(2 * drawPadding)).div(dates.size.minus(1))
163+
dates.forEachIndexed { index, step ->
152164
drawLine(
153165
color = Color.DarkGray,
154-
start = Offset(x = drawPadding + step.times(distance), y = yStart),
155-
end = Offset(x = drawPadding + step.times(distance), y = lineHeightPx)
166+
start = Offset(x = drawPadding + index.times(distance), y = yStart),
167+
end = Offset(x = drawPadding + index.times(distance), y = lineHeightPx)
156168
)
157-
if (step.rem(3) == 0) {
169+
if (index.rem(3) == 0) {
158170
this.drawContext.canvas.nativeCanvas.drawText(
159-
"12.30",
160-
drawPadding + step.times(distance),
171+
step,
172+
drawPadding + index.times(distance),
161173
size.height,
162174
textPaint
163175
)
@@ -167,17 +179,18 @@ fun ForecastSlider() {
167179
Slider(
168180
modifier = Modifier.fillMaxWidth(),
169181
value = sliderValue,
170-
valueRange = 0f..12f,
171-
steps = steps,
182+
valueRange = 0f..dates.size.minus(1).toFloat(),
183+
steps = dates.size.minus(2),
172184
colors = customSliderColors(),
173185
onValueChange = {
174186
setSliderValue(it)
187+
onValueChange(it.toInt())
175188
})
176189
}
177190
}
178191

179192
@Composable
180193
private fun customSliderColors(): SliderColors = SliderDefaults.colors(
181194
activeTickColor = Color.Transparent,
182-
inactiveTickColor = Color.Transparent
183-
)
195+
// inactiveTickColor = Color.Transparent
196+
)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.piotrprus.weathercard
2+
3+
import androidx.lifecycle.LiveData
4+
import androidx.lifecycle.MutableLiveData
5+
import androidx.lifecycle.ViewModel
6+
7+
class MainViewModel : ViewModel() {
8+
private val _selected = MutableLiveData(0)
9+
val selected: LiveData<Int> = _selected
10+
11+
fun onValueChanged(selected: Int) {
12+
_selected.value = selected
13+
}
14+
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package com.piotrprus.weathercard
22

3+
import androidx.annotation.DrawableRes
4+
35
data class WeatherItem(
46
val date: String,
57
val temperature: Int,
68
val precipitation: Int,
7-
val windSpeed: Int
9+
val windSpeed: Int,
10+
@DrawableRes
11+
val icon: Int
812
)

app/src/main/res/drawable/cloudy.png

1.59 KB
Loading

app/src/main/res/drawable/rain.png

2.63 KB
Loading

app/src/main/res/drawable/sunny.png

948 Bytes
Loading

0 commit comments

Comments
 (0)