Access Max Mix temps and Forecast for rain snow and wind
This commit is contained in:
parent
2c7dc727d3
commit
49b9553118
|
@ -4,6 +4,14 @@
|
||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
|
<DropdownSelection timestamp="2025-03-23T17:25:15.945565980Z">
|
||||||
|
<Target type="DEFAULT_BOOT">
|
||||||
|
<handle>
|
||||||
|
<DeviceId pluginId="LocalEmulator" identifier="path=/home/lorenz/.android/avd/Medium_Phone_API_35.avd" />
|
||||||
|
</handle>
|
||||||
|
</Target>
|
||||||
|
</DropdownSelection>
|
||||||
|
<DialogSelection />
|
||||||
</SelectionState>
|
</SelectionState>
|
||||||
</selectionStates>
|
</selectionStates>
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -66,4 +66,9 @@ dependencies {
|
||||||
implementation("androidx.datastore:datastore:1.0.0")
|
implementation("androidx.datastore:datastore:1.0.0")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1") // For JSON serialization
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1") // For JSON serialization
|
||||||
|
|
||||||
|
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||||
|
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||||
|
implementation("com.squareup.okhttp3:logging-interceptor:4.9.1")
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
|
|
|
@ -2,11 +2,12 @@ package com.module.breeze
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.CalendarContract
|
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
@ -15,7 +16,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.AcUnit
|
import androidx.compose.material.icons.outlined.AcUnit
|
||||||
|
@ -25,31 +25,20 @@ import androidx.compose.material.icons.outlined.ArrowUpward
|
||||||
import androidx.compose.material.icons.outlined.Map
|
import androidx.compose.material.icons.outlined.Map
|
||||||
import androidx.compose.material.icons.outlined.Settings
|
import androidx.compose.material.icons.outlined.Settings
|
||||||
import androidx.compose.material.icons.outlined.WaterDrop
|
import androidx.compose.material.icons.outlined.WaterDrop
|
||||||
import androidx.compose.material.icons.rounded.AcUnit
|
|
||||||
import androidx.compose.material.icons.rounded.Air
|
|
||||||
import androidx.compose.material.icons.rounded.ArrowDownward
|
|
||||||
import androidx.compose.material.icons.rounded.ArrowDropDown
|
|
||||||
import androidx.compose.material.icons.rounded.ArrowUpward
|
|
||||||
import androidx.compose.material.icons.rounded.KeyboardArrowDown
|
|
||||||
import androidx.compose.material.icons.rounded.KeyboardArrowUp
|
|
||||||
import androidx.compose.material.icons.rounded.LocationOn
|
|
||||||
import androidx.compose.material.icons.rounded.Map
|
|
||||||
import androidx.compose.material.icons.rounded.Settings
|
|
||||||
import androidx.compose.material.icons.rounded.WaterDrop
|
|
||||||
import androidx.compose.material.icons.sharp.KeyboardArrowDown
|
|
||||||
import androidx.compose.material.icons.twotone.AccountCircle
|
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ButtonColors
|
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.RectangleShape
|
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
@ -57,14 +46,20 @@ 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
|
||||||
import com.module.breeze.ui.theme.BreezeTheme
|
import com.module.breeze.ui.theme.BreezeTheme
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import java.text.DecimalFormat
|
||||||
|
import java.time.LocalDate
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
val fontSizeCurrentTemp = 48.sp
|
val fontSizeCurrentTemp = 48.sp
|
||||||
val fontSizeUpper = 16.sp
|
val fontSizeUpper = 16.sp
|
||||||
val fontSizeTitle = 24.sp
|
val fontSizeTitle = 22.sp
|
||||||
val breezeFontWeight = FontWeight.Bold
|
val breezeFontWeight = FontWeight.Bold
|
||||||
val iconStyle = Icons.Outlined;
|
val iconStyle = Icons.Outlined;
|
||||||
val textColor = Color(0, 0, 0)
|
val textColor = Color(0, 0, 0)
|
||||||
|
val numberFormat = DecimalFormat("00")
|
||||||
|
val apiKey = "8a6090c4308455152cd8c677b802883b"
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
@ -89,14 +84,44 @@ class MainActivity : ComponentActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
fun getTodaysLocation(ctx: Context): String {
|
||||||
|
var dayOfTheWeek = LocalDate.now().dayOfWeek.value - 1
|
||||||
|
var plz = "Loading ..."
|
||||||
|
runBlocking {
|
||||||
|
plz = getLocations(ctx)[dayOfTheWeek]
|
||||||
|
}
|
||||||
|
return plz
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
fun fetchWeather(ctx: Context): ForecastSummary {
|
||||||
|
var todayPlz = getTodaysLocation(ctx)
|
||||||
|
|
||||||
|
var data: ForecastSummary
|
||||||
|
runBlocking {
|
||||||
|
val forecastResponse = RetrofitClient.instance.getWeatherForecast("${todayPlz},ch", apiKey)
|
||||||
|
val todaysForecast = getTodaysForecast(forecastResponse)
|
||||||
|
|
||||||
|
data = todaysForecast
|
||||||
|
println("Today's Forecast for ${todayPlz}:")
|
||||||
|
println("Min Temperature: ${todaysForecast.minTemp}°C")
|
||||||
|
println("Max Temperature: ${todaysForecast.maxTemp}°C")
|
||||||
|
println("Rain: ${if (todaysForecast.hasRain) "Yes" else "No"}")
|
||||||
|
println("Snow: ${if (todaysForecast.hasSnow) "Yes" else "No"}")
|
||||||
|
println("Strong Winds: ${if (todaysForecast.hasStrongWinds) "Yes" else "No"}")
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WeatherInfo(modifier: Modifier = Modifier) {
|
fun WeatherInfo(modifier: Modifier = Modifier) {
|
||||||
val ctx = LocalContext.current
|
val ctx = LocalContext.current
|
||||||
|
var forecast by remember { mutableStateOf(ForecastSummary(0.0, 0.0, false, false, false)) }
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
var displayRain = false;
|
forecast = fetchWeather(ctx)
|
||||||
var displaySnow = false;
|
}
|
||||||
var displayWind = false;
|
|
||||||
|
|
||||||
Navigation(
|
Navigation(
|
||||||
iconStyle.Settings,
|
iconStyle.Settings,
|
||||||
|
@ -121,18 +146,18 @@ fun WeatherInfo(modifier: Modifier = Modifier) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = iconStyle.WaterDrop,
|
imageVector = iconStyle.WaterDrop,
|
||||||
contentDescription = "Rain Icon",
|
contentDescription = "Rain Icon",
|
||||||
modifier = Modifier.alpha(if (displayRain) 1F else 0.2F)
|
modifier = Modifier.alpha(if (forecast.hasRain) 1F else 0.2F)
|
||||||
)
|
)
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = iconStyle.AcUnit,
|
imageVector = iconStyle.AcUnit,
|
||||||
contentDescription = "Snow Icon",
|
contentDescription = "Snow Icon",
|
||||||
modifier = Modifier.alpha(if (displaySnow) 1F else 0.2F)
|
modifier = Modifier.alpha(if (forecast.hasSnow) 1F else 0.2F)
|
||||||
)
|
)
|
||||||
|
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = iconStyle.Air,
|
imageVector = iconStyle.Air,
|
||||||
contentDescription = "Wind Icon",
|
contentDescription = "Wind Icon",
|
||||||
modifier = Modifier.alpha(if (displayWind) 1F else 0.2F)
|
modifier = Modifier.alpha(if (forecast.hasStrongWinds) 1F else 0.2F)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Row {
|
Row {
|
||||||
|
@ -141,7 +166,7 @@ fun WeatherInfo(modifier: Modifier = Modifier) {
|
||||||
contentDescription = "Arrow down Icon"
|
contentDescription = "Arrow down Icon"
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "18°",
|
text = numberFormat.format(forecast.minTemp.roundToInt()),
|
||||||
fontSize = fontSizeUpper,
|
fontSize = fontSizeUpper,
|
||||||
fontWeight = breezeFontWeight
|
fontWeight = breezeFontWeight
|
||||||
)
|
)
|
||||||
|
@ -150,7 +175,7 @@ fun WeatherInfo(modifier: Modifier = Modifier) {
|
||||||
contentDescription = "Arrow up Icon"
|
contentDescription = "Arrow up Icon"
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "23°",
|
text = numberFormat.format(forecast.maxTemp.roundToInt()),
|
||||||
fontSize = fontSizeUpper,
|
fontSize = fontSizeUpper,
|
||||||
fontWeight = breezeFontWeight
|
fontWeight = breezeFontWeight
|
||||||
)
|
)
|
||||||
|
|
|
@ -34,7 +34,6 @@ import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
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.datastore.core.DataStore
|
import androidx.datastore.core.DataStore
|
||||||
import androidx.datastore.preferences.core.Preferences
|
import androidx.datastore.preferences.core.Preferences
|
||||||
import androidx.datastore.preferences.core.edit
|
import androidx.datastore.preferences.core.edit
|
||||||
|
@ -60,20 +59,20 @@ var plzArrayStatus: List<String> = listOf(
|
||||||
val SHARED_PLZ_KEY = stringPreferencesKey("shared-plz")
|
val SHARED_PLZ_KEY = stringPreferencesKey("shared-plz")
|
||||||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||||
|
|
||||||
suspend fun saveArray(context: Context, array: List<String>) {
|
suspend fun setLocations(context: Context, array: List<String>) {
|
||||||
context.dataStore.edit { preferences ->
|
context.dataStore.edit { preferences ->
|
||||||
preferences[SHARED_PLZ_KEY] = Json.encodeToString(array)
|
preferences[SHARED_PLZ_KEY] = Json.encodeToString(array)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getArray(context: Context): List<String> {
|
suspend fun getLocations(context: Context): List<String> {
|
||||||
val preferences = context.dataStore.data.first()
|
val preferences = context.dataStore.data.first()
|
||||||
return preferences[SHARED_PLZ_KEY]?.let { Json.decodeFromString(it) } ?: emptyList()
|
return preferences[SHARED_PLZ_KEY]?.let { Json.decodeFromString(it) } ?: emptyList()
|
||||||
}
|
}
|
||||||
// ### End ChatGPT
|
// ### End ChatGPT
|
||||||
|
|
||||||
suspend fun getPLZ(index: Int, ctx: Context): String {
|
suspend fun getPLZ(index: Int, ctx: Context): String {
|
||||||
var arr = getArray(ctx)
|
var arr = getLocations(ctx)
|
||||||
if (arr.isEmpty() || arr.size != 7) {
|
if (arr.isEmpty() || arr.size != 7) {
|
||||||
arr = listOf("8005", "8005", "8005", "8400", "8400", "8500", "8500")
|
arr = listOf("8005", "8005", "8005", "8400", "8400", "8500", "8500")
|
||||||
}
|
}
|
||||||
|
@ -84,7 +83,7 @@ suspend fun getPLZ(index: Int, ctx: Context): String {
|
||||||
suspend fun setPLZ(index: Int, value: String, ctx: Context) {
|
suspend fun setPLZ(index: Int, value: String, ctx: Context) {
|
||||||
var arr = plzArrayStatus.toMutableList()
|
var arr = plzArrayStatus.toMutableList()
|
||||||
arr[index] = value
|
arr[index] = value
|
||||||
saveArray(ctx, arr)
|
setLocations(ctx, arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,7 +138,7 @@ fun Settings(modifier: Modifier = Modifier) {
|
||||||
Text(
|
Text(
|
||||||
text = "Configured Locations",
|
text = "Configured Locations",
|
||||||
fontWeight = breezeFontWeight,
|
fontWeight = breezeFontWeight,
|
||||||
fontSize = 22.sp
|
fontSize = fontSizeTitle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ConfiguredLocationDay("Monday", 0, ctx)
|
ConfiguredLocationDay("Monday", 0, ctx)
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
package com.module.breeze
|
||||||
|
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Query
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
// Whole File DeepSeek
|
||||||
|
// Data classes for API responses
|
||||||
|
data class WeatherResponse(
|
||||||
|
val main: Main,
|
||||||
|
val weather: List<Weather>,
|
||||||
|
val dt: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Main(
|
||||||
|
val temp: Double,
|
||||||
|
val feels_like: Double,
|
||||||
|
val temp_min: Double,
|
||||||
|
val temp_max: Double,
|
||||||
|
val pressure: Int,
|
||||||
|
val humidity: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Weather(
|
||||||
|
val id: Int,
|
||||||
|
val main: String,
|
||||||
|
val description: String,
|
||||||
|
val icon: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class ForecastResponse(
|
||||||
|
val list: List<Forecast>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Forecast(
|
||||||
|
val dt: Long,
|
||||||
|
val main: Main,
|
||||||
|
val weather: List<Weather>,
|
||||||
|
val wind: Wind,
|
||||||
|
val rain: Rain?,
|
||||||
|
val snow: Snow?
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Wind(
|
||||||
|
val speed: Double,
|
||||||
|
val deg: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Rain(
|
||||||
|
val `3h`: Double?
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Snow(
|
||||||
|
val `3h`: Double?
|
||||||
|
)
|
||||||
|
|
||||||
|
// Retrofit API interface
|
||||||
|
interface WeatherApiService {
|
||||||
|
@GET("weather")
|
||||||
|
suspend fun getCurrentWeather(
|
||||||
|
@Query("lat") lat: Double,
|
||||||
|
@Query("lon") lon: Double,
|
||||||
|
@Query("appid") apiKey: String,
|
||||||
|
@Query("units") units: String = "metric"
|
||||||
|
): WeatherResponse
|
||||||
|
|
||||||
|
@GET("forecast")
|
||||||
|
suspend fun getWeatherForecast(
|
||||||
|
@Query("zip") zip: String,
|
||||||
|
@Query("appid") apiKey: String,
|
||||||
|
@Query("units") units: String = "metric"
|
||||||
|
): ForecastResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrofit client setup
|
||||||
|
object RetrofitClient {
|
||||||
|
private const val BASE_URL = "https://api.openweathermap.org/data/2.5/"
|
||||||
|
|
||||||
|
private val logging = HttpLoggingInterceptor().apply {
|
||||||
|
level = HttpLoggingInterceptor.Level.BODY
|
||||||
|
}
|
||||||
|
|
||||||
|
private val httpClient = OkHttpClient.Builder()
|
||||||
|
.addInterceptor(logging)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val instance: WeatherApiService by lazy {
|
||||||
|
Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL)
|
||||||
|
.client(httpClient)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.build()
|
||||||
|
.create(WeatherApiService::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to filter today's forecast
|
||||||
|
fun getTodaysForecast(forecastResponse: ForecastResponse): ForecastSummary {
|
||||||
|
val today = Date().time / 1000 // Current timestamp in seconds
|
||||||
|
val tomorrow = today + 86400 // 24 hours later
|
||||||
|
|
||||||
|
// Filter forecasts for today
|
||||||
|
val todaysForecasts = forecastResponse.list.filter { it.dt in today..tomorrow }
|
||||||
|
|
||||||
|
// Extract min and max temperatures
|
||||||
|
val minTemp = todaysForecasts.minOfOrNull { it.main.temp_min } ?: 0.0
|
||||||
|
val maxTemp = todaysForecasts.maxOfOrNull { it.main.temp_max } ?: 0.0
|
||||||
|
|
||||||
|
// Check for rain, snow, or strong winds
|
||||||
|
val hasRain = todaysForecasts.any { it.rain != null }
|
||||||
|
val hasSnow = todaysForecasts.any { it.snow != null }
|
||||||
|
val hasStrongWinds = todaysForecasts.any { it.wind.speed > 10.0 } // Wind speed > 10 m/s
|
||||||
|
|
||||||
|
return ForecastSummary(
|
||||||
|
minTemp = minTemp,
|
||||||
|
maxTemp = maxTemp,
|
||||||
|
hasRain = hasRain,
|
||||||
|
hasSnow = hasSnow,
|
||||||
|
hasStrongWinds = hasStrongWinds
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data class for today's forecast summary
|
||||||
|
data class ForecastSummary(
|
||||||
|
val minTemp: Double,
|
||||||
|
val maxTemp: Double,
|
||||||
|
val hasRain: Boolean,
|
||||||
|
val hasSnow: Boolean,
|
||||||
|
val hasStrongWinds: Boolean
|
||||||
|
)
|
Loading…
Reference in New Issue