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