From 49b9553118330aa0cc28d62b6a9486e9f32fcc9b Mon Sep 17 00:00:00 2001 From: lorenzhohermuth Date: Sun, 23 Mar 2025 19:46:55 +0100 Subject: [PATCH] Access Max Mix temps and Forecast for rain snow and wind --- .idea/deploymentTargetSelector.xml | 8 ++ app/build.gradle.kts | 5 + app/src/main/AndroidManifest.xml | 2 + .../java/com/module/breeze/MainActivity.kt | 79 +++++++---- .../com/module/breeze/SettingsActivity.kt | 11 +- .../com/module/breeze/WheatherRepository.kt | 134 ++++++++++++++++++ 6 files changed, 206 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/com/module/breeze/WheatherRepository.kt diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index b268ef3..99486d0 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -4,6 +4,14 @@ diff --git a/app/build.gradle.kts b/app/build.gradle.kts index eea99f0..4132139 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -66,4 +66,9 @@ dependencies { implementation("androidx.datastore:datastore:1.0.0") 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") + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5a8640b..804be05 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + = Build.VERSION_CODES.O) { + forecast = fetchWeather(ctx) + } Navigation( iconStyle.Settings, @@ -121,18 +146,18 @@ fun WeatherInfo(modifier: Modifier = Modifier) { Icon( imageVector = iconStyle.WaterDrop, contentDescription = "Rain Icon", - modifier = Modifier.alpha(if (displayRain) 1F else 0.2F) + modifier = Modifier.alpha(if (forecast.hasRain) 1F else 0.2F) ) Icon( imageVector = iconStyle.AcUnit, contentDescription = "Snow Icon", - modifier = Modifier.alpha(if (displaySnow) 1F else 0.2F) + modifier = Modifier.alpha(if (forecast.hasSnow) 1F else 0.2F) ) Icon( imageVector = iconStyle.Air, contentDescription = "Wind Icon", - modifier = Modifier.alpha(if (displayWind) 1F else 0.2F) + modifier = Modifier.alpha(if (forecast.hasStrongWinds) 1F else 0.2F) ) } Row { @@ -141,7 +166,7 @@ fun WeatherInfo(modifier: Modifier = Modifier) { contentDescription = "Arrow down Icon" ) Text( - text = "18°", + text = numberFormat.format(forecast.minTemp.roundToInt()), fontSize = fontSizeUpper, fontWeight = breezeFontWeight ) @@ -150,7 +175,7 @@ fun WeatherInfo(modifier: Modifier = Modifier) { contentDescription = "Arrow up Icon" ) Text( - text = "23°", + text = numberFormat.format(forecast.maxTemp.roundToInt()), fontSize = fontSizeUpper, fontWeight = breezeFontWeight ) diff --git a/app/src/main/java/com/module/breeze/SettingsActivity.kt b/app/src/main/java/com/module/breeze/SettingsActivity.kt index 54e3599..db91969 100644 --- a/app/src/main/java/com/module/breeze/SettingsActivity.kt +++ b/app/src/main/java/com/module/breeze/SettingsActivity.kt @@ -34,7 +34,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit @@ -60,20 +59,20 @@ var plzArrayStatus: List = listOf( val SHARED_PLZ_KEY = stringPreferencesKey("shared-plz") val Context.dataStore: DataStore by preferencesDataStore(name = "settings") -suspend fun saveArray(context: Context, array: List) { +suspend fun setLocations(context: Context, array: List) { context.dataStore.edit { preferences -> preferences[SHARED_PLZ_KEY] = Json.encodeToString(array) } } -suspend fun getArray(context: Context): List { +suspend fun getLocations(context: Context): List { val preferences = context.dataStore.data.first() return preferences[SHARED_PLZ_KEY]?.let { Json.decodeFromString(it) } ?: emptyList() } // ### End ChatGPT suspend fun getPLZ(index: Int, ctx: Context): String { - var arr = getArray(ctx) + var arr = getLocations(ctx) if (arr.isEmpty() || arr.size != 7) { 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) { var arr = plzArrayStatus.toMutableList() arr[index] = value - saveArray(ctx, arr) + setLocations(ctx, arr) } @@ -139,7 +138,7 @@ fun Settings(modifier: Modifier = Modifier) { Text( text = "Configured Locations", fontWeight = breezeFontWeight, - fontSize = 22.sp + fontSize = fontSizeTitle ) } ConfiguredLocationDay("Monday", 0, ctx) diff --git a/app/src/main/java/com/module/breeze/WheatherRepository.kt b/app/src/main/java/com/module/breeze/WheatherRepository.kt new file mode 100644 index 0000000..7831128 --- /dev/null +++ b/app/src/main/java/com/module/breeze/WheatherRepository.kt @@ -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, + 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 +) + +data class Forecast( + val dt: Long, + val main: Main, + val weather: List, + 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 +) \ No newline at end of file