├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── gradle.xml ├── misc.xml └── vcs.xml ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── piotrprus │ │ └── weathercard │ │ └── WeatherCardTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── piotrprus │ │ │ └── weathercard │ │ │ ├── Consts.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MainViewModel.kt │ │ │ ├── WeatherItem.kt │ │ │ └── ui │ │ │ └── theme │ │ │ ├── Color.kt │ │ │ ├── Shape.kt │ │ │ ├── Theme.kt │ │ │ └── Type.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── cloudy.png │ │ ├── ic_launcher_background.xml │ │ ├── rain.png │ │ └── sunny.png │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ └── themes.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test │ ├── java │ └── com │ │ └── piotrprus │ │ └── weathercard │ │ └── WeatherCardRoboTest.kt │ └── resources │ └── com │ └── piotrprus │ └── weathercard │ └── robolectric.properties ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("kotlin-android") 4 | } 5 | 6 | android { 7 | compileSdk = 31 8 | 9 | defaultConfig { 10 | applicationId = "com.piotrprus.weathercard" 11 | minSdk = 23 12 | targetSdk = 31 13 | versionCode = 1 14 | versionName = "1.0" 15 | 16 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 17 | vectorDrawables { 18 | useSupportLibrary = true 19 | } 20 | } 21 | 22 | buildTypes { 23 | release { 24 | isMinifyEnabled = false 25 | proguardFiles( 26 | getDefaultProguardFile("proguard-android-optimize.txt"), 27 | "proguard-rules.pro" 28 | ) 29 | } 30 | } 31 | compileOptions { 32 | sourceCompatibility = JavaVersion.VERSION_1_8 33 | targetCompatibility = JavaVersion.VERSION_1_8 34 | } 35 | kotlinOptions { 36 | jvmTarget = "1.8" 37 | } 38 | buildFeatures { 39 | compose = true 40 | } 41 | composeOptions { 42 | kotlinCompilerExtensionVersion = rootProject.extra["compose_version"] as String 43 | } 44 | packagingOptions { 45 | resources { 46 | excludes += setOf("META-INF/{AL2.0,LGPL2.1}") 47 | } 48 | } 49 | testOptions { 50 | unitTests { 51 | isIncludeAndroidResources = true 52 | } 53 | } 54 | } 55 | 56 | dependencies { 57 | 58 | implementation("androidx.core:core-ktx:1.7.0") 59 | implementation("androidx.appcompat:appcompat:1.4.1") 60 | implementation("com.google.android.material:material:1.5.0") 61 | implementation("androidx.compose.ui:ui:${rootProject.extra["compose_version"]}") 62 | implementation("androidx.compose.material:material:${rootProject.extra["compose_version"]}") 63 | implementation("androidx.compose.ui:ui-tooling:${rootProject.extra["compose_version"]}") 64 | implementation("androidx.compose.runtime:runtime-livedata:${rootProject.extra["compose_version"]}") 65 | implementation("androidx.compose.material:material-icons-extended:${rootProject.extra["compose_version"]}") 66 | implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.1") 67 | implementation("androidx.activity:activity-compose:1.4.0") 68 | testImplementation("junit:junit:4.+") 69 | testImplementation("org.robolectric:robolectric:4.7.3") 70 | // Test rules and transitive dependencies: 71 | testImplementation("androidx.compose.ui:ui-test-junit4:${rootProject.extra["compose_version"]}") 72 | androidTestImplementation("androidx.compose.ui:ui-test-junit4:${rootProject.extra["compose_version"]}") 73 | // Needed for createComposeRule, but not createAndroidComposeRule: 74 | debugImplementation("androidx.compose.ui:ui-test-manifest:${rootProject.extra["compose_version"]}") 75 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/piotrprus/weathercard/WeatherCardTest.kt: -------------------------------------------------------------------------------- 1 | package com.piotrprus.weathercard 2 | 3 | import androidx.compose.runtime.mutableStateOf 4 | import androidx.compose.runtime.remember 5 | import androidx.compose.ui.test.* 6 | import androidx.compose.ui.test.junit4.createComposeRule 7 | import org.junit.Rule 8 | import org.junit.Test 9 | 10 | class WeatherCardTest { 11 | @get:Rule 12 | val composeTestRule = createComposeRule() 13 | 14 | @Test 15 | fun checkWeatherCardExists() { 16 | composeTestRule.setContent { 17 | val selected = remember { mutableStateOf(0) } 18 | WeatherCard(list = forecastMockState, selectedValue = selected.value, onValueChange = { selected.value = it }) 19 | } 20 | composeTestRule.onNodeWithTag(WEATHER_CARD_TAG).assertExists() 21 | } 22 | 23 | @Test 24 | fun checkFirstElementDataIsDisplayed() { 25 | composeTestRule.setContent { 26 | val selected = remember { mutableStateOf(0) } 27 | WeatherCard(list = forecastMockState, selectedValue = selected.value, onValueChange = { selected.value = it }) 28 | } 29 | composeTestRule.onNodeWithTag(TEMPERATURE_TAG).assertTextEquals(forecastMockState.first().temperature.toString()) 30 | composeTestRule.onNodeWithTag(DATE_TAG).assertTextEquals(forecastMockState.first().date) 31 | composeTestRule.onNodeWithTag(SLIDER_TAG).assertIsEnabled() 32 | } 33 | 34 | @Test 35 | fun changeSliderPositionAndAssertTheDisplayElement() { 36 | composeTestRule.setContent { 37 | val selected = remember { mutableStateOf(0) } 38 | WeatherCard(list = forecastMockState, selectedValue = selected.value, onValueChange = { selected.value = it }) 39 | } 40 | val rect = composeTestRule.onNodeWithTag(SLIDER_TAG).getBoundsInRoot() 41 | val widthPx = with(composeTestRule.density) { rect.right.minus(rect.left).toPx() } 42 | val distanceToPointThree = widthPx.div(forecastMockState.size).times(3) 43 | composeTestRule.onNodeWithTag(SLIDER_TAG).performTouchInput { swipeRight(0f, distanceToPointThree) } 44 | composeTestRule.onNodeWithTag(TEMPERATURE_TAG).assertTextEquals(forecastMockState[2].temperature.toString()) 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/piotrprus/weathercard/Consts.kt: -------------------------------------------------------------------------------- 1 | package com.piotrprus.weathercard 2 | 3 | import androidx.compose.runtime.mutableStateListOf 4 | 5 | val forecastMockState = mutableStateListOf( 6 | WeatherItem(date = "Mon, 8:00 AM, Cloudy", temperature = 12, 30, 2, R.drawable.cloudy), 7 | WeatherItem(date = "Mon, 9:00 AM, Cloudy", temperature = 14, 60, 3, R.drawable.cloudy), 8 | WeatherItem(date = "Mon, 10:00 AM, Mostly cloudy", temperature = 15, 80, 5, R.drawable.rain), 9 | WeatherItem(date = "Mon, 11:00 AM, Mostly sunny", temperature = 15, 30, 2, R.drawable.sunny), 10 | WeatherItem(date = "Mon, 12:00 PM, Mostly sunny", temperature = 18, 20, 1, R.drawable.sunny), 11 | WeatherItem(date = "Mon, 1:00 PM, Sunny", temperature = 20, 0, 1, R.drawable.sunny), 12 | WeatherItem(date = "Mon, 2:00 PM, Sunny", temperature = 20, 0, 2, R.drawable.sunny), 13 | WeatherItem(date = "Mon, 3:00 PM, Sunny", temperature = 19, 0, 2, R.drawable.sunny), 14 | WeatherItem(date = "Mon, 4:00 PM, Sunny", temperature = 19, 0, 2, R.drawable.sunny), 15 | WeatherItem(date = "Mon, 5:00 PM, Sunny", temperature = 17, 0, 3, R.drawable.sunny), 16 | WeatherItem(date = "Mon, 6:00 PM, Heavy showers", temperature = 16, 80, 7, R.drawable.rain), 17 | WeatherItem(date = "Mon, 7:00 PM, Heavy showers", temperature = 15, 90, 9, R.drawable.rain), 18 | ) 19 | 20 | const val WEATHER_CARD_TAG = "WeatherCardTag" 21 | const val TEMPERATURE_TAG = "TemperatureTag" 22 | const val DATE_TAG = "DateTag" 23 | const val SLIDER_TAG = "SliderTag" -------------------------------------------------------------------------------- /app/src/main/java/com/piotrprus/weathercard/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.piotrprus.weathercard 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.activity.viewModels 7 | import androidx.compose.foundation.Canvas 8 | import androidx.compose.foundation.Image 9 | import androidx.compose.foundation.isSystemInDarkTheme 10 | import androidx.compose.foundation.layout.* 11 | import androidx.compose.foundation.shape.RoundedCornerShape 12 | import androidx.compose.material.* 13 | import androidx.compose.material.icons.Icons 14 | import androidx.compose.material.icons.filled.Air 15 | import androidx.compose.material.icons.filled.Water 16 | import androidx.compose.runtime.* 17 | import androidx.compose.runtime.livedata.observeAsState 18 | import androidx.compose.ui.Alignment 19 | import androidx.compose.ui.Modifier 20 | import androidx.compose.ui.geometry.Offset 21 | import androidx.compose.ui.graphics.Color 22 | import androidx.compose.ui.graphics.nativeCanvas 23 | import androidx.compose.ui.platform.LocalDensity 24 | import androidx.compose.ui.platform.testTag 25 | import androidx.compose.ui.res.painterResource 26 | import androidx.compose.ui.unit.dp 27 | import com.piotrprus.weathercard.ui.theme.WeatherCardTheme 28 | 29 | class MainActivity : ComponentActivity() { 30 | 31 | private val viewModel: MainViewModel by viewModels() 32 | 33 | override fun onCreate(savedInstanceState: Bundle?) { 34 | super.onCreate(savedInstanceState) 35 | setContent { 36 | WeatherCardTheme { 37 | // A surface container using the 'background' color from the theme 38 | Surface(color = MaterialTheme.colors.background) { 39 | val selectedValue: Int by viewModel.selected.observeAsState(initial = 0) 40 | WeatherCard(forecastMockState, selectedValue) { 41 | viewModel.onValueChanged(it) 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | @Composable 50 | fun WeatherCard(list: List, selectedValue: Int, onValueChange: (Int) -> Unit) { 51 | val item by remember(selectedValue, list) { 52 | derivedStateOf { list[selectedValue] } 53 | } 54 | Card( 55 | modifier = Modifier 56 | .testTag(WEATHER_CARD_TAG) 57 | .fillMaxWidth() 58 | .padding(12.dp), 59 | elevation = 4.dp, 60 | shape = RoundedCornerShape(12.dp), 61 | ) { 62 | Column(modifier = Modifier.padding(12.dp)) { 63 | MeasurementView(item) 64 | ForecastSlider( 65 | list.map { it.date.split(",")[1] }, 66 | onValueChange = { onValueChange(it) }, 67 | value = selectedValue.toFloat() 68 | ) 69 | } 70 | } 71 | } 72 | 73 | @Composable 74 | private fun MeasurementView(data: WeatherItem) { 75 | Text(text = "Hong Kong", style = MaterialTheme.typography.h5) 76 | Spacer(modifier = Modifier.height(8.dp)) 77 | Text( 78 | modifier = Modifier.testTag(DATE_TAG), 79 | text = data.date, 80 | style = MaterialTheme.typography.body2.copy(color = Color.Gray) 81 | ) 82 | Spacer(modifier = Modifier.height(8.dp)) 83 | Row( 84 | modifier = Modifier.fillMaxWidth(), 85 | horizontalArrangement = Arrangement.SpaceEvenly, 86 | verticalAlignment = Alignment.CenterVertically 87 | ) { 88 | Row { 89 | Text( 90 | modifier = Modifier.testTag(TEMPERATURE_TAG), 91 | text = data.temperature.toString(), 92 | style = MaterialTheme.typography.h1 93 | ) 94 | Text( 95 | modifier = Modifier.padding(top = 10.dp), 96 | text = "°C", 97 | style = MaterialTheme.typography.h3 98 | ) 99 | } 100 | Image( 101 | modifier = Modifier.size(100.dp), 102 | painter = painterResource(id = data.icon), 103 | contentDescription = "Weather icon" 104 | ) 105 | } 106 | Spacer(modifier = Modifier.height(8.dp)) 107 | Row( 108 | modifier = Modifier.fillMaxWidth(), 109 | horizontalArrangement = Arrangement.SpaceEvenly 110 | ) { 111 | Row(verticalAlignment = Alignment.CenterVertically) { 112 | Icon(imageVector = Icons.Default.Water, contentDescription = "Water icon") 113 | Spacer(modifier = Modifier.width(4.dp)) 114 | Text( 115 | text = "${data.precipitation}% Precipitation", 116 | style = MaterialTheme.typography.body2.copy(color = Color.Gray) 117 | ) 118 | } 119 | Row(verticalAlignment = Alignment.CenterVertically) { 120 | Icon(imageVector = Icons.Default.Air, contentDescription = "Air icon") 121 | Spacer(modifier = Modifier.width(4.dp)) 122 | Text( 123 | text = "${data.windSpeed} km/h Winds", 124 | style = MaterialTheme.typography.body2.copy(color = Color.Gray) 125 | ) 126 | } 127 | } 128 | } 129 | 130 | @Composable 131 | fun ForecastSlider(dates: List, value: Float, onValueChange: (Int) -> Unit) { 132 | val (sliderValue, setSliderValue) = remember { mutableStateOf(value) } 133 | val drawPadding = with(LocalDensity.current) { 10.dp.toPx() } 134 | val textSize = with(LocalDensity.current) { 10.dp.toPx() } 135 | val lineHeightDp = 10.dp 136 | val lineHeightPx = with(LocalDensity.current) { lineHeightDp.toPx() } 137 | val canvasHeight = 50.dp 138 | val textPaint = android.graphics.Paint().apply { 139 | color = if (isSystemInDarkTheme()) 0xffffffff.toInt() else 0xffff47586B.toInt() 140 | textAlign = android.graphics.Paint.Align.CENTER 141 | this.textSize = textSize 142 | } 143 | Box(contentAlignment = Alignment.Center) { 144 | Canvas( 145 | modifier = Modifier 146 | .height(canvasHeight) 147 | .fillMaxWidth() 148 | .padding( 149 | top = canvasHeight 150 | .div(2) 151 | .minus(lineHeightDp.div(2)) 152 | ) 153 | ) { 154 | val yStart = 0f 155 | val distance = (size.width.minus(2 * drawPadding)).div(dates.size.minus(1)) 156 | dates.forEachIndexed { index, date -> 157 | drawLine( 158 | color = Color.DarkGray, 159 | start = Offset(x = drawPadding + index.times(distance), y = yStart), 160 | end = Offset(x = drawPadding + index.times(distance), y = lineHeightPx) 161 | ) 162 | if (index.rem(2) == 1) { 163 | this.drawContext.canvas.nativeCanvas.drawText( 164 | date, 165 | drawPadding + index.times(distance), 166 | size.height, 167 | textPaint 168 | ) 169 | } 170 | } 171 | } 172 | Slider( 173 | modifier = Modifier.testTag(SLIDER_TAG).fillMaxWidth(), 174 | value = sliderValue, 175 | valueRange = 0f..dates.size.minus(1).toFloat(), 176 | steps = dates.size.minus(2), 177 | colors = customSliderColors(), 178 | onValueChange = { 179 | setSliderValue(it) 180 | onValueChange(it.toInt()) 181 | }) 182 | } 183 | } 184 | 185 | @Composable 186 | private fun customSliderColors(): SliderColors = SliderDefaults.colors( 187 | activeTickColor = Color.Transparent, 188 | inactiveTickColor = Color.Transparent 189 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/piotrprus/weathercard/MainViewModel.kt: -------------------------------------------------------------------------------- 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 = _selected 10 | 11 | fun onValueChanged(selected: Int) { 12 | _selected.value = selected 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/piotrprus/weathercard/WeatherItem.kt: -------------------------------------------------------------------------------- 1 | package com.piotrprus.weathercard 2 | 3 | import androidx.annotation.DrawableRes 4 | 5 | data class WeatherItem( 6 | val date: String, 7 | val temperature: Int, 8 | val precipitation: Int, 9 | val windSpeed: Int, 10 | @DrawableRes 11 | val icon: Int 12 | ) 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/piotrprus/weathercard/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package com.piotrprus.weathercard.ui.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val Purple200 = Color(0xFFBB86FC) 6 | val Purple500 = Color(0xFF6200EE) 7 | val Purple700 = Color(0xFF3700B3) 8 | val Teal200 = Color(0xFF03DAC5) -------------------------------------------------------------------------------- /app/src/main/java/com/piotrprus/weathercard/ui/theme/Shape.kt: -------------------------------------------------------------------------------- 1 | package com.piotrprus.weathercard.ui.theme 2 | 3 | import androidx.compose.foundation.shape.RoundedCornerShape 4 | import androidx.compose.material.Shapes 5 | import androidx.compose.ui.unit.dp 6 | 7 | val Shapes = Shapes( 8 | small = RoundedCornerShape(4.dp), 9 | medium = RoundedCornerShape(4.dp), 10 | large = RoundedCornerShape(0.dp) 11 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/piotrprus/weathercard/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package com.piotrprus.weathercard.ui.theme 2 | 3 | import androidx.compose.foundation.isSystemInDarkTheme 4 | import androidx.compose.material.MaterialTheme 5 | import androidx.compose.material.darkColors 6 | import androidx.compose.material.lightColors 7 | import androidx.compose.runtime.Composable 8 | 9 | private val DarkColorPalette = darkColors( 10 | primary = Purple200, 11 | primaryVariant = Purple700, 12 | secondary = Teal200 13 | ) 14 | 15 | private val LightColorPalette = lightColors( 16 | primary = Purple500, 17 | primaryVariant = Purple700, 18 | secondary = Teal200 19 | 20 | /* Other default colors to override 21 | background = Color.White, 22 | surface = Color.White, 23 | onPrimary = Color.White, 24 | onSecondary = Color.Black, 25 | onBackground = Color.Black, 26 | onSurface = Color.Black, 27 | */ 28 | ) 29 | 30 | @Composable 31 | fun WeatherCardTheme( 32 | darkTheme: Boolean = isSystemInDarkTheme(), 33 | content: @Composable() () -> Unit 34 | ) { 35 | val colors = if (darkTheme) { 36 | DarkColorPalette 37 | } else { 38 | LightColorPalette 39 | } 40 | 41 | MaterialTheme( 42 | colors = colors, 43 | typography = Typography, 44 | shapes = Shapes, 45 | content = content 46 | ) 47 | } -------------------------------------------------------------------------------- /app/src/main/java/com/piotrprus/weathercard/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package com.piotrprus.weathercard.ui.theme 2 | 3 | import androidx.compose.material.Typography 4 | import androidx.compose.ui.text.TextStyle 5 | import androidx.compose.ui.text.font.FontFamily 6 | import androidx.compose.ui.text.font.FontWeight 7 | import androidx.compose.ui.unit.sp 8 | 9 | // Set of Material typography styles to start with 10 | val Typography = Typography( 11 | body1 = TextStyle( 12 | fontFamily = FontFamily.Default, 13 | fontWeight = FontWeight.Normal, 14 | fontSize = 16.sp 15 | ) 16 | /* Other default text styles to override 17 | button = TextStyle( 18 | fontFamily = FontFamily.Default, 19 | fontWeight = FontWeight.W500, 20 | fontSize = 14.sp 21 | ), 22 | caption = TextStyle( 23 | fontFamily = FontFamily.Default, 24 | fontWeight = FontWeight.Normal, 25 | fontSize = 12.sp 26 | ) 27 | */ 28 | ) -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/drawable/cloudy.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/drawable/rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/sunny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/drawable/sunny.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrPrus/ComposeWeatherCard/7919b4eddef76f9022ec2c6bcdd1f7116f8e56a4/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | WeatherCard 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 21 | 22 |