linting changes
This commit is contained in:
		
							parent
							
								
									2f9109d0ae
								
							
						
					
					
						commit
						d88bb72378
					
				|  | @ -1,24 +0,0 @@ | ||||||
| package com.module.breeze |  | ||||||
| 
 |  | ||||||
| import androidx.test.platform.app.InstrumentationRegistry |  | ||||||
| import androidx.test.ext.junit.runners.AndroidJUnit4 |  | ||||||
| 
 |  | ||||||
| import org.junit.Test |  | ||||||
| import org.junit.runner.RunWith |  | ||||||
| 
 |  | ||||||
| import org.junit.Assert.* |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Instrumented test, which will execute on an Android device. |  | ||||||
|  * |  | ||||||
|  * See [testing documentation](http://d.android.com/tools/testing). |  | ||||||
|  */ |  | ||||||
| @RunWith(AndroidJUnit4::class) |  | ||||||
| class ExampleInstrumentedTest { |  | ||||||
|     @Test |  | ||||||
|     fun useAppContext() { |  | ||||||
|         // Context of the app under test. |  | ||||||
|         val appContext = InstrumentationRegistry.getInstrumentation().targetContext |  | ||||||
|         assertEquals("com.module.breeze", appContext.packageName) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -11,35 +11,36 @@ import androidx.core.content.ContextCompat | ||||||
| 
 | 
 | ||||||
| // AI | // AI | ||||||
| class GpsRepository(private val context: Context) : LocationListener { | class GpsRepository(private val context: Context) : LocationListener { | ||||||
|     private var locationManager: LocationManager? = null |   private var locationManager: LocationManager? = null | ||||||
|     private var onLocationChanged: ((Location) -> Unit)? = null |   private var onLocationChanged: ((Location) -> Unit)? = null | ||||||
| 
 | 
 | ||||||
|     fun startListening(onLocationChanged: (Location) -> Unit) { |   fun startListening(onLocationChanged: (Location) -> Unit) { | ||||||
|         this.onLocationChanged = onLocationChanged |     this.onLocationChanged = onLocationChanged | ||||||
|         locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager |     locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager | ||||||
| 
 | 
 | ||||||
|         if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) |     if (ContextCompat.checkSelfPermission( | ||||||
|             == |         context, | ||||||
|             PackageManager.PERMISSION_GRANTED |         Manifest.permission.ACCESS_FINE_LOCATION, | ||||||
|         ) { |       ) == PackageManager.PERMISSION_GRANTED | ||||||
|             locationManager?.requestLocationUpdates( |     ) { | ||||||
|                 LocationManager.GPS_PROVIDER, |       locationManager?.requestLocationUpdates( | ||||||
|                 1000L, |         LocationManager.GPS_PROVIDER, | ||||||
|                 1f, |         1000L, | ||||||
|                 this |         1f, | ||||||
|             ) |         this, | ||||||
|         } |       ) | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     fun stopListening() { |   fun stopListening() { | ||||||
|         locationManager?.removeUpdates(this) |     locationManager?.removeUpdates(this) | ||||||
|     } |   } | ||||||
| 
 | 
 | ||||||
|     override fun onLocationChanged(location: Location) { |   override fun onLocationChanged(location: Location) { | ||||||
|         onLocationChanged?.invoke(location) |     onLocationChanged?.invoke(location) | ||||||
|     } |   } | ||||||
| 
 | 
 | ||||||
|     override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {} |   override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {} | ||||||
|     override fun onProviderEnabled(provider: String) {} |   override fun onProviderEnabled(provider: String) {} | ||||||
|     override fun onProviderDisabled(provider: String) {} |   override fun onProviderDisabled(provider: String) {} | ||||||
| } | } | ||||||
|  | @ -1,12 +1,17 @@ | ||||||
| package com.module.breeze | package com.module.breeze | ||||||
| 
 | 
 | ||||||
|  | import android.Manifest | ||||||
| import android.content.Context | import android.content.Context | ||||||
| import android.content.Intent | import android.content.Intent | ||||||
|  | import android.content.pm.PackageManager | ||||||
|  | import android.location.Location | ||||||
| import android.os.Build | import android.os.Build | ||||||
| import android.os.Bundle | import android.os.Bundle | ||||||
| import androidx.activity.ComponentActivity | import androidx.activity.ComponentActivity | ||||||
|  | import androidx.activity.compose.rememberLauncherForActivityResult | ||||||
| import androidx.activity.compose.setContent | import androidx.activity.compose.setContent | ||||||
| import androidx.activity.enableEdgeToEdge | import androidx.activity.enableEdgeToEdge | ||||||
|  | import androidx.activity.result.contract.ActivityResultContracts | ||||||
| import androidx.annotation.RequiresApi | 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 | ||||||
|  | @ -31,6 +36,7 @@ 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.DisposableEffect | ||||||
| import androidx.compose.runtime.getValue | import androidx.compose.runtime.getValue | ||||||
| import androidx.compose.runtime.mutableStateOf | import androidx.compose.runtime.mutableStateOf | ||||||
| import androidx.compose.runtime.remember | import androidx.compose.runtime.remember | ||||||
|  | @ -45,247 +51,231 @@ import androidx.compose.ui.text.font.FontWeight | ||||||
| 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.compose.ui.unit.sp | ||||||
|  | import androidx.core.content.ContextCompat | ||||||
| import com.module.breeze.ui.theme.BreezeTheme | import com.module.breeze.ui.theme.BreezeTheme | ||||||
| import kotlinx.coroutines.runBlocking | import kotlinx.coroutines.runBlocking | ||||||
| import java.text.DecimalFormat | import java.text.DecimalFormat | ||||||
| import java.time.LocalDate | import java.time.LocalDate | ||||||
| import kotlin.math.roundToInt | import kotlin.math.roundToInt | ||||||
| import android.Manifest |  | ||||||
| import android.content.pm.PackageManager |  | ||||||
| import android.location.Location |  | ||||||
| import androidx.activity.compose.rememberLauncherForActivityResult |  | ||||||
| import androidx.activity.result.contract.ActivityResultContracts |  | ||||||
| import androidx.compose.foundation.layout.Column |  | ||||||
| import androidx.compose.material3.Button |  | ||||||
| import androidx.compose.material3.Text |  | ||||||
| import androidx.compose.runtime.DisposableEffect |  | ||||||
| import androidx.compose.runtime.getValue |  | ||||||
| import androidx.compose.runtime.mutableStateOf |  | ||||||
| import androidx.compose.runtime.remember |  | ||||||
| import androidx.compose.runtime.setValue |  | ||||||
| import androidx.compose.ui.platform.LocalContext |  | ||||||
| import androidx.core.content.ContextCompat |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| val fontSizeCurrentTemp = 48.sp | val fontSizeCurrentTemp = 48.sp | ||||||
| val fontSizeUpper = 16.sp | val fontSizeUpper = 16.sp | ||||||
| val fontSizeTitle = 22.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 numberFormat = DecimalFormat("00") | ||||||
| val apiKey = "8a6090c4308455152cd8c677b802883b" | val apiKey = "8a6090c4308455152cd8c677b802883b" | ||||||
| 
 | 
 | ||||||
| class MainActivity : ComponentActivity() { | class MainActivity : ComponentActivity() { | ||||||
|     override fun onCreate(savedInstanceState: Bundle?) { |   override fun onCreate(savedInstanceState: Bundle?) { | ||||||
|         super.onCreate(savedInstanceState) |     super.onCreate(savedInstanceState) | ||||||
|         enableEdgeToEdge() |     enableEdgeToEdge() | ||||||
|         setContent { |     setContent { | ||||||
|             BreezeTheme { |       BreezeTheme { | ||||||
|                 Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> |         Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> | ||||||
|                     WeatherInfo( |           WeatherInfo( | ||||||
|                         modifier = Modifier.padding(innerPadding) |             modifier = Modifier.padding(innerPadding), | ||||||
|                     ) |           ) | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     companion object { |   companion object { | ||||||
|         fun openSettings(ctx: Context) { |     fun openSettings(ctx: Context) { | ||||||
|             var intent = Intent(ctx, SettingsActivity::class.java) |       var intent = Intent(ctx, SettingsActivity::class.java) | ||||||
|             ctx.startActivity(intent) |       ctx.startActivity(intent) | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @RequiresApi(Build.VERSION_CODES.O) | @RequiresApi(Build.VERSION_CODES.O) | ||||||
| fun getTodaysLocation(ctx: Context): String { | fun getTodaysLocation(ctx: Context): String { | ||||||
|     var dayOfTheWeek = LocalDate.now().dayOfWeek.value - 1 |   var dayOfTheWeek = LocalDate.now().dayOfWeek.value - 1 | ||||||
|     var plz = "Loading ..." |   var plz = "Loading ..." | ||||||
|     runBlocking { |   runBlocking { | ||||||
|         plz = getLocations(ctx)[dayOfTheWeek] |     plz = getLocations(ctx)[dayOfTheWeek] | ||||||
|     } |   } | ||||||
|     return plz |   return plz | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @RequiresApi(Build.VERSION_CODES.O) | @RequiresApi(Build.VERSION_CODES.O) | ||||||
| fun fetchWeather(ctx: Context): ForecastSummary { | fun fetchWeather(ctx: Context): ForecastSummary { | ||||||
|     var todayPlz = getTodaysLocation(ctx) |   var todayPlz = getTodaysLocation(ctx) | ||||||
| 
 | 
 | ||||||
|     var data: ForecastSummary |   var data: ForecastSummary | ||||||
|     runBlocking { |   runBlocking { | ||||||
|         val forecastResponse = RetrofitClient.instance.getWeatherForecast("${todayPlz},ch", apiKey) |     val forecastResponse = RetrofitClient.instance.getWeatherForecast("$todayPlz,ch", apiKey) | ||||||
|         val todaysForecast = getTodaysForecast(forecastResponse) |     val todaysForecast = getTodaysForecast(forecastResponse) | ||||||
| 
 | 
 | ||||||
|         data = todaysForecast |     data = todaysForecast | ||||||
|         println("Today's Forecast for ${todayPlz}:") |   } | ||||||
|         println("Min Temperature: ${todaysForecast.minTemp}°C") |   return data | ||||||
|         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 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fun fetchCurrentTemp(ctx: Context, lat: Double, lon: Double): WeatherResponse { | fun fetchCurrentTemp(ctx: Context, lat: Double, lon: Double): WeatherResponse { | ||||||
|     var data: WeatherResponse |   var data: WeatherResponse | ||||||
|     runBlocking { |   runBlocking { | ||||||
|         data = RetrofitClient.instance.getCurrentWeather(lat, lon, apiKey) |     data = RetrofitClient.instance.getCurrentWeather(lat, lon, apiKey) | ||||||
|     } |   } | ||||||
|     return data |   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)) } |   var forecast by remember { mutableStateOf(ForecastSummary(0.0, 0.0, false, false, false)) } | ||||||
|     var currentTemp by remember { |   var currentTemp by remember { | ||||||
|         mutableStateOf( |     mutableStateOf( | ||||||
|             WeatherResponse(Main(0.0, 0.0, 0.0, 0.0, 0, 0), emptyList(), 0L) |       WeatherResponse(Main(0.0, 0.0, 0.0, 0.0, 0, 0), emptyList(), 0L), | ||||||
|         ) |  | ||||||
|     } |  | ||||||
|     val locationHelper = remember { GpsRepository(ctx) } |  | ||||||
| 
 |  | ||||||
|     var location by remember { mutableStateOf<Location?>(null) } |  | ||||||
| 
 |  | ||||||
|     val locationPermission = ContextCompat.checkSelfPermission( |  | ||||||
|         ctx, Manifest.permission.ACCESS_FINE_LOCATION |  | ||||||
|     ) |     ) | ||||||
|     var hasLocationPermission by remember { |   } | ||||||
|         mutableStateOf(locationPermission == PackageManager.PERMISSION_GRANTED) |   val locationHelper = remember { GpsRepository(ctx) } | ||||||
|  | 
 | ||||||
|  |   var location by remember { mutableStateOf<Location?>(null) } | ||||||
|  | 
 | ||||||
|  |   val locationPermission = ContextCompat.checkSelfPermission( | ||||||
|  |     ctx, | ||||||
|  |     Manifest.permission.ACCESS_FINE_LOCATION, | ||||||
|  |   ) | ||||||
|  |   var hasLocationPermission by remember { | ||||||
|  |     mutableStateOf(locationPermission == PackageManager.PERMISSION_GRANTED) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   val permissionLauncher = rememberLauncherForActivityResult( | ||||||
|  |     ActivityResultContracts.RequestPermission(), | ||||||
|  |   ) { isGranted -> hasLocationPermission = isGranted } | ||||||
|  | 
 | ||||||
|  |   DisposableEffect(key1 = locationHelper, key2 = hasLocationPermission) { | ||||||
|  |     if (hasLocationPermission) { | ||||||
|  |       locationHelper.startListening { newLocation -> | ||||||
|  |         location = newLocation | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     val permissionLauncher = rememberLauncherForActivityResult( |     onDispose { | ||||||
|         ActivityResultContracts.RequestPermission() |       locationHelper.stopListening() | ||||||
|     ) { isGranted -> hasLocationPermission = isGranted } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     DisposableEffect(key1 = locationHelper, key2 = hasLocationPermission) { |  | ||||||
|         if (hasLocationPermission) { |  | ||||||
|             locationHelper.startListening { newLocation -> |  | ||||||
|                 location = newLocation |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         onDispose { |  | ||||||
|             locationHelper.stopListening() |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||||
|         forecast = fetchWeather(ctx) |     forecast = fetchWeather(ctx) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Navigation( | ||||||
|  |     iconStyle.Settings, | ||||||
|  |     "Settings Icon", | ||||||
|  |     onClick = { MainActivity.openSettings(ctx) }, | ||||||
|  |   ) | ||||||
|  | 
 | ||||||
|  |   Column( | ||||||
|  |     modifier = Modifier.fillMaxSize(), | ||||||
|  |     verticalArrangement = Arrangement.Center, | ||||||
|  |     horizontalAlignment = Alignment.CenterHorizontally, | ||||||
|  |   ) { | ||||||
|  |     Row(verticalAlignment = Alignment.Bottom) { | ||||||
|  |       Icon( | ||||||
|  |         imageVector = iconStyle.Map, | ||||||
|  |         contentDescription = "Location Icon", | ||||||
|  |         modifier = Modifier | ||||||
|  |           .padding(end = 16.dp) | ||||||
|  |           .size(32.dp), | ||||||
|  |       ) | ||||||
|  |       Icon( | ||||||
|  |         imageVector = iconStyle.WaterDrop, | ||||||
|  |         contentDescription = "Rain Icon", | ||||||
|  |         modifier = Modifier.alpha(if (forecast.hasRain) 1F else 0.2F), | ||||||
|  |       ) | ||||||
|  |       Icon( | ||||||
|  |         imageVector = iconStyle.AcUnit, | ||||||
|  |         contentDescription = "Snow Icon", | ||||||
|  |         modifier = Modifier.alpha(if (forecast.hasSnow) 1F else 0.2F), | ||||||
|  |       ) | ||||||
|  | 
 | ||||||
|  |       Icon( | ||||||
|  |         imageVector = iconStyle.Air, | ||||||
|  |         contentDescription = "Wind Icon", | ||||||
|  |         modifier = Modifier.alpha(if (forecast.hasStrongWinds) 1F else 0.2F), | ||||||
|  |       ) | ||||||
|     } |     } | ||||||
| 
 |     Row { | ||||||
| 
 |       Icon( | ||||||
|     Navigation( |         imageVector = iconStyle.ArrowDownward, | ||||||
|         iconStyle.Settings, "Settings Icon", onClick = { MainActivity.openSettings(ctx) }) |         contentDescription = "Arrow down Icon", | ||||||
| 
 |       ) | ||||||
|     Column( |       Text( | ||||||
|         modifier = Modifier.fillMaxSize(), |         text = numberFormat.format(forecast.minTemp.roundToInt()) + "°", | ||||||
|         verticalArrangement = Arrangement.Center, |         fontSize = fontSizeUpper, | ||||||
|         horizontalAlignment = Alignment.CenterHorizontally, |         fontWeight = breezeFontWeight, | ||||||
|     ) { |       ) | ||||||
|         Row(verticalAlignment = Alignment.Bottom) { |       Icon( | ||||||
|             Icon( |         imageVector = iconStyle.ArrowUpward, | ||||||
|                 imageVector = iconStyle.Map, |         contentDescription = "Arrow up Icon", | ||||||
|                 contentDescription = "Location Icon", |       ) | ||||||
|                 modifier = Modifier |       Text( | ||||||
|                     .padding(end = 16.dp) |         text = numberFormat.format(forecast.maxTemp.roundToInt()) + "°", | ||||||
|                     .size(32.dp) |         fontSize = fontSizeUpper, | ||||||
|             ) |         fontWeight = breezeFontWeight, | ||||||
|             Icon( |       ) | ||||||
|                 imageVector = iconStyle.WaterDrop, |  | ||||||
|                 contentDescription = "Rain Icon", |  | ||||||
|                 modifier = Modifier.alpha(if (forecast.hasRain) 1F else 0.2F) |  | ||||||
|             ) |  | ||||||
|             Icon( |  | ||||||
|                 imageVector = iconStyle.AcUnit, |  | ||||||
|                 contentDescription = "Snow Icon", |  | ||||||
|                 modifier = Modifier.alpha(if (forecast.hasSnow) 1F else 0.2F) |  | ||||||
|             ) |  | ||||||
| 
 |  | ||||||
|             Icon( |  | ||||||
|                 imageVector = iconStyle.Air, |  | ||||||
|                 contentDescription = "Wind Icon", |  | ||||||
|                 modifier = Modifier.alpha(if (forecast.hasStrongWinds) 1F else 0.2F) |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|         Row { |  | ||||||
|             Icon( |  | ||||||
|                 imageVector = iconStyle.ArrowDownward, contentDescription = "Arrow down Icon" |  | ||||||
|             ) |  | ||||||
|             Text( |  | ||||||
|                 text = numberFormat.format(forecast.minTemp.roundToInt()) + "°", |  | ||||||
|                 fontSize = fontSizeUpper, |  | ||||||
|                 fontWeight = breezeFontWeight |  | ||||||
|             ) |  | ||||||
|             Icon( |  | ||||||
|                 imageVector = iconStyle.ArrowUpward, contentDescription = "Arrow up Icon" |  | ||||||
|             ) |  | ||||||
|             Text( |  | ||||||
|                 text = numberFormat.format(forecast.maxTemp.roundToInt()) + "°", |  | ||||||
|                 fontSize = fontSizeUpper, |  | ||||||
|                 fontWeight = breezeFontWeight |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|         if (hasLocationPermission) { |  | ||||||
|             location?.let { |  | ||||||
|                 currentTemp = fetchCurrentTemp(ctx, it.latitude, it.latitude) |  | ||||||
|             } |  | ||||||
|             Text( |  | ||||||
|                 text = numberFormat.format(currentTemp.main.temp.roundToInt()) + "°", |  | ||||||
|                 fontSize = fontSizeCurrentTemp, |  | ||||||
|                 fontWeight = breezeFontWeight, |  | ||||||
|             ) |  | ||||||
|         } else { |  | ||||||
|             Button( |  | ||||||
|                 onClick = { |  | ||||||
|                     permissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION) |  | ||||||
|                 }, |  | ||||||
|                 colors = ButtonDefaults.buttonColors( |  | ||||||
|                     containerColor = Color(0, 0, 0, 20), contentColor = textColor |  | ||||||
|                 ), |  | ||||||
|             ) { |  | ||||||
|                 Text( |  | ||||||
|                     text = "Grant Permission", |  | ||||||
|                     fontWeight = breezeFontWeight, |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |     if (hasLocationPermission) { | ||||||
|  |       location?.let { | ||||||
|  |         currentTemp = fetchCurrentTemp(ctx, it.latitude, it.latitude) | ||||||
|  |       } | ||||||
|  |       Text( | ||||||
|  |         text = numberFormat.format(currentTemp.main.temp.roundToInt()) + "°", | ||||||
|  |         fontSize = fontSizeCurrentTemp, | ||||||
|  |         fontWeight = breezeFontWeight, | ||||||
|  |       ) | ||||||
|  |     } else { | ||||||
|  |       Button( | ||||||
|  |         onClick = { | ||||||
|  |           permissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION) | ||||||
|  |         }, | ||||||
|  |         colors = ButtonDefaults.buttonColors( | ||||||
|  |           containerColor = Color(0, 0, 0, 20), | ||||||
|  |           contentColor = textColor, | ||||||
|  |         ), | ||||||
|  |       ) { | ||||||
|  |         Text( | ||||||
|  |           text = "Grant Permission", | ||||||
|  |           fontWeight = breezeFontWeight, | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Preview(showBackground = true) | @Preview(showBackground = true) | ||||||
| @Composable | @Composable | ||||||
| fun GreetingPreview() { | fun GreetingPreview() { | ||||||
|     BreezeTheme { |   BreezeTheme { | ||||||
|         WeatherInfo() |     WeatherInfo() | ||||||
|     } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| @Composable | @Composable | ||||||
| fun Navigation(icon: ImageVector, iconDescription: String, onClick: () -> Unit = {}) { | fun Navigation(icon: ImageVector, iconDescription: String, onClick: () -> Unit = {}) { | ||||||
|     Row( |   Row( | ||||||
|         horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth() |     horizontalArrangement = Arrangement.End, | ||||||
|  |     modifier = Modifier.fillMaxWidth(), | ||||||
|  |   ) { | ||||||
|  |     Button( | ||||||
|  |       onClick = onClick, | ||||||
|  |       colors = ButtonDefaults.buttonColors( | ||||||
|  |         containerColor = Color(255, 0, 0, 0), | ||||||
|  |         contentColor = textColor, | ||||||
|  |       ), | ||||||
|  |       shape = CircleShape, | ||||||
|  |       contentPadding = PaddingValues(0.dp), | ||||||
|  |       modifier = Modifier.padding(0.dp, 40.dp, 28.dp, 0.dp), | ||||||
|     ) { |     ) { | ||||||
|         Button( |       Icon( | ||||||
|             onClick = onClick, |         imageVector = icon, | ||||||
|             colors = ButtonDefaults.buttonColors( |         contentDescription = iconDescription, | ||||||
|                 containerColor = Color(255, 0, 0, 0), contentColor = textColor |         modifier = Modifier.size(40.dp), | ||||||
|             ), |       ) | ||||||
|             shape = CircleShape, |  | ||||||
|             contentPadding = PaddingValues(0.dp), |  | ||||||
|             modifier = Modifier.padding(0.dp, 40.dp, 28.dp, 0.dp) |  | ||||||
|         ) { |  | ||||||
|             Icon( |  | ||||||
|                 imageVector = icon, |  | ||||||
|                 contentDescription = iconDescription, |  | ||||||
|                 modifier = Modifier.size(40.dp) |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| package com.module.breeze | package com.module.breeze | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| import android.content.Context | import android.content.Context | ||||||
| import android.content.Intent | import android.content.Intent | ||||||
| import android.os.Bundle | import android.os.Bundle | ||||||
|  | @ -45,165 +44,161 @@ import kotlinx.serialization.encodeToString | ||||||
| import kotlinx.serialization.json.Json | import kotlinx.serialization.json.Json | ||||||
| 
 | 
 | ||||||
| var plzArrayStatus: List<String> = listOf( | var plzArrayStatus: List<String> = listOf( | ||||||
|     "Loading...", |   "Loading...", | ||||||
|     "Loading...", |   "Loading...", | ||||||
|     "Loading...", |   "Loading...", | ||||||
|     "Loading...", |   "Loading...", | ||||||
|     "Loading...", |   "Loading...", | ||||||
|     "Loading...", |   "Loading...", | ||||||
|     "Loading...", |   "Loading...", | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| // ### Start ChatGPT + Fixing | // ### Start ChatGPT + Fixing | ||||||
| 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 setLocations(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 getLocations(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 = getLocations(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") | ||||||
|     } |   } | ||||||
|     plzArrayStatus = arr |   plzArrayStatus = arr | ||||||
|     return arr[index] |   return arr[index] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 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 | ||||||
|     setLocations(ctx, arr) |   setLocations(ctx, arr) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| class SettingsActivity : ComponentActivity() { | class SettingsActivity : ComponentActivity() { | ||||||
|     override fun onCreate(savedInstanceState: Bundle?) { |   override fun onCreate(savedInstanceState: Bundle?) { | ||||||
|         super.onCreate(savedInstanceState) |     super.onCreate(savedInstanceState) | ||||||
|         enableEdgeToEdge() |     enableEdgeToEdge() | ||||||
|         setContent { |     setContent { | ||||||
|             BreezeTheme { |       BreezeTheme { | ||||||
|                 Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> |         Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> | ||||||
|                     Settings( |           Settings( | ||||||
|                         modifier = Modifier.padding(innerPadding) |             modifier = Modifier.padding(innerPadding), | ||||||
|                     ) |           ) | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     companion object { |   companion object { | ||||||
|         fun openHome(ctx: Context) { |     fun openHome(ctx: Context) { | ||||||
|             var intent = Intent(ctx, MainActivity::class.java) |       var intent = Intent(ctx, MainActivity::class.java) | ||||||
|             ctx.startActivity(intent) |       ctx.startActivity(intent) | ||||||
|         } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun Settings(modifier: Modifier = Modifier) { | fun Settings(modifier: Modifier = Modifier) { | ||||||
|     val ctx = LocalContext.current |   val ctx = LocalContext.current | ||||||
| 
 | 
 | ||||||
|     Navigation(iconStyle.Home, "Home Icon", onClick = { |   Navigation( | ||||||
|         SettingsActivity.openHome(ctx) |     iconStyle.Home, | ||||||
|     }) |     "Home Icon", | ||||||
|     Column( |     onClick = { SettingsActivity.openHome(ctx) }, | ||||||
|         modifier = Modifier.fillMaxSize(), |   ) | ||||||
|         verticalArrangement = Arrangement.Center, |   Column( | ||||||
|         horizontalAlignment = Alignment.CenterHorizontally |     modifier = Modifier.fillMaxSize(), | ||||||
|     ) |     verticalArrangement = Arrangement.Center, | ||||||
|     { |     horizontalAlignment = Alignment.CenterHorizontally, | ||||||
|         Row( |   ) { | ||||||
|             verticalAlignment = Alignment.CenterVertically, |     Row( | ||||||
|             modifier = Modifier.padding(16.dp) |       verticalAlignment = Alignment.CenterVertically, | ||||||
|         ) |       modifier = Modifier.padding(16.dp), | ||||||
|         { |     ) { | ||||||
|             Icon( |       Icon( | ||||||
|                 imageVector = iconStyle.Map, |         imageVector = iconStyle.Map, | ||||||
|                 contentDescription = "Configured Locations Icon", |         contentDescription = "Configured Locations Icon", | ||||||
|                 modifier = Modifier.size(40.dp) |         modifier = Modifier.size(40.dp), | ||||||
|             ) |       ) | ||||||
|             Text( |       Text( | ||||||
|                 text = "Configured Locations", |         text = "Configured Locations", | ||||||
|                 fontWeight = breezeFontWeight, |         fontWeight = breezeFontWeight, | ||||||
|                 fontSize = fontSizeTitle |         fontSize = fontSizeTitle, | ||||||
|             ) |       ) | ||||||
|         } |  | ||||||
|         ConfiguredLocationDay("Monday", 0, ctx) |  | ||||||
|         ConfiguredLocationDay("Tuesday", 1, ctx) |  | ||||||
|         ConfiguredLocationDay("Wednesday", 2, ctx) |  | ||||||
|         ConfiguredLocationDay("Thursday", 3, ctx) |  | ||||||
|         ConfiguredLocationDay("Friday", 4, ctx) |  | ||||||
|         ConfiguredLocationDay("Saturday", 5, ctx) |  | ||||||
|         ConfiguredLocationDay("Sunday", 6, ctx) |  | ||||||
|     } |     } | ||||||
|  |     ConfiguredLocationDay("Monday", 0, ctx) | ||||||
|  |     ConfiguredLocationDay("Tuesday", 1, ctx) | ||||||
|  |     ConfiguredLocationDay("Wednesday", 2, ctx) | ||||||
|  |     ConfiguredLocationDay("Thursday", 3, ctx) | ||||||
|  |     ConfiguredLocationDay("Friday", 4, ctx) | ||||||
|  |     ConfiguredLocationDay("Saturday", 5, ctx) | ||||||
|  |     ConfiguredLocationDay("Sunday", 6, ctx) | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Preview(showBackground = true) | @Preview(showBackground = true) | ||||||
| @Composable | @Composable | ||||||
| fun GreetingPreview2() { | fun GreetingPreview2() { | ||||||
|     BreezeTheme { |   BreezeTheme { | ||||||
|         Settings() |     Settings() | ||||||
|     } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun ConfiguredLocationDay(dayName: String = "day", index: Int, ctx: Context) { | fun ConfiguredLocationDay(dayName: String = "day", index: Int, ctx: Context) { | ||||||
|     var plz by remember { mutableStateOf("") } |   var plz by remember { mutableStateOf("") } | ||||||
|     var isLoadingGet by remember { mutableStateOf(false) } |   var isLoadingGet by remember { mutableStateOf(false) } | ||||||
|     var isLoadingSet by remember { mutableStateOf(false) } |   var isLoadingSet by remember { mutableStateOf(false) } | ||||||
| 
 | 
 | ||||||
|     LaunchedEffect(index) { |   LaunchedEffect(index) { | ||||||
|         isLoadingGet = true |     isLoadingGet = true | ||||||
|         plz = getPLZ(index, ctx) |     plz = getPLZ(index, ctx) | ||||||
|         isLoadingGet = false |     isLoadingGet = false | ||||||
|     } |   } | ||||||
| 
 | 
 | ||||||
|     LaunchedEffect(plz) { |   LaunchedEffect(plz) { | ||||||
|         if (plz.length == 4) { |     if (plz.length == 4) { | ||||||
|             isLoadingSet = true |       isLoadingSet = true | ||||||
|             setPLZ(index, plz, ctx) |       setPLZ(index, plz, ctx) | ||||||
|             isLoadingSet = false |       isLoadingSet = false | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     if (isLoadingSet || isLoadingGet) { |   if (isLoadingSet || isLoadingGet) { | ||||||
|         CircularProgressIndicator() |     CircularProgressIndicator() | ||||||
|     } else { |   } else { | ||||||
|         Row( |     Row( | ||||||
|             verticalAlignment = Alignment.CenterVertically, |       verticalAlignment = Alignment.CenterVertically, | ||||||
|             modifier = Modifier.padding(0.dp, 4.dp) |       modifier = Modifier.padding(0.dp, 4.dp), | ||||||
|         ) { |     ) { | ||||||
|             Text( |       Text( | ||||||
|                 text = dayName, |         text = dayName, | ||||||
|                 fontWeight = breezeFontWeight, |         fontWeight = breezeFontWeight, | ||||||
|                 modifier = Modifier.width(100.dp) |         modifier = Modifier.width(100.dp), | ||||||
|             ) |       ) | ||||||
|             TextField( |       TextField( | ||||||
|                 value = plz, |         value = plz, | ||||||
|                 onValueChange = { newPlz -> |         onValueChange = { newPlz -> | ||||||
|                     var cutNewPlz = newPlz |           var cutNewPlz = newPlz | ||||||
|                     if (newPlz.length > 4) { |           if (newPlz.length > 4) { | ||||||
|                         cutNewPlz = newPlz.substring(0, 4) |             cutNewPlz = newPlz.substring(0, 4) | ||||||
|                     } |           } | ||||||
|                     plz = cutNewPlz |           plz = cutNewPlz | ||||||
|                 }, |         }, | ||||||
|                 label = { Text("PLZ") }, |         label = { Text("PLZ") }, | ||||||
|                 keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), |         keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), | ||||||
|                 modifier = Modifier.width(110.dp) |         modifier = Modifier.width(110.dp), | ||||||
|             ) |       ) | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | @ -1,134 +1,129 @@ | ||||||
| package com.module.breeze | package com.module.breeze | ||||||
| 
 | 
 | ||||||
|  | import okhttp3.OkHttpClient | ||||||
|  | import okhttp3.logging.HttpLoggingInterceptor | ||||||
| import retrofit2.Retrofit | import retrofit2.Retrofit | ||||||
| import retrofit2.converter.gson.GsonConverterFactory | import retrofit2.converter.gson.GsonConverterFactory | ||||||
| import retrofit2.http.GET | import retrofit2.http.GET | ||||||
| import retrofit2.http.Query | import retrofit2.http.Query | ||||||
| import okhttp3.OkHttpClient |  | ||||||
| import okhttp3.logging.HttpLoggingInterceptor |  | ||||||
| import java.util.Date | import java.util.Date | ||||||
| 
 | 
 | ||||||
| // Whole File DeepSeek | // Whole File DeepSeek | ||||||
| // Data classes for API responses | // Data classes for API responses | ||||||
| data class WeatherResponse( | data class WeatherResponse( | ||||||
|     val main: Main, |   val main: Main, | ||||||
|     val weather: List<Weather>, |   val weather: List<Weather>, | ||||||
|     val dt: Long |   val dt: Long, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| data class Main( | data class Main( | ||||||
|     val temp: Double, |   val temp: Double, | ||||||
|     val feels_like: Double, |   val feels_like: Double, | ||||||
|     val temp_min: Double, |   val temp_min: Double, | ||||||
|     val temp_max: Double, |   val temp_max: Double, | ||||||
|     val pressure: Int, |   val pressure: Int, | ||||||
|     val humidity: Int |   val humidity: Int, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| data class Weather( | data class Weather( | ||||||
|     val id: Int, |   val id: Int, | ||||||
|     val main: String, |   val main: String, | ||||||
|     val description: String, |   val description: String, | ||||||
|     val icon: String |   val icon: String, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| data class ForecastResponse( | data class ForecastResponse( | ||||||
|     val list: List<Forecast> |   val list: List<Forecast>, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| data class Forecast( | data class Forecast( | ||||||
|     val dt: Long, |   val dt: Long, | ||||||
|     val main: Main, |   val main: Main, | ||||||
|     val weather: List<Weather>, |   val weather: List<Weather>, | ||||||
|     val wind: Wind, |   val wind: Wind, | ||||||
|     val rain: Rain?, |   val rain: Rain?, | ||||||
|     val snow: Snow? |   val snow: Snow?, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| data class Wind( | data class Wind( | ||||||
|     val speed: Double, |   val speed: Double, | ||||||
|     val deg: Int |   val deg: Int, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| data class Rain( | data class Rain( | ||||||
|     val `3h`: Double? |   val `3h`: Double?, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| data class Snow( | data class Snow( | ||||||
|     val `3h`: Double? |   val `3h`: Double?, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Retrofit API interface | // Retrofit API interface | ||||||
| interface WeatherApiService { | interface WeatherApiService { | ||||||
|     @GET("weather") |   @GET("weather") | ||||||
|     suspend fun getCurrentWeather( |   suspend fun getCurrentWeather( | ||||||
|         @Query("lat") lat: Double, |     @Query("lat") lat: Double, | ||||||
|         @Query("lon") lon: Double, |     @Query("lon") lon: Double, | ||||||
|         @Query("appid") apiKey: String, |     @Query("appid") apiKey: String, | ||||||
|         @Query("units") units: String = "metric" |     @Query("units") units: String = "metric", | ||||||
|     ): WeatherResponse |   ): WeatherResponse | ||||||
| 
 | 
 | ||||||
|     @GET("forecast") |   @GET("forecast") | ||||||
|     suspend fun getWeatherForecast( |   suspend fun getWeatherForecast( | ||||||
|         @Query("zip") zip: String, |     @Query("zip") zip: String, | ||||||
|         @Query("appid") apiKey: String, |     @Query("appid") apiKey: String, | ||||||
|         @Query("units") units: String = "metric" |     @Query("units") units: String = "metric", | ||||||
|     ): ForecastResponse |   ): ForecastResponse | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Retrofit client setup | // Retrofit client setup | ||||||
| object RetrofitClient { | object RetrofitClient { | ||||||
|     private const val BASE_URL = "https://api.openweathermap.org/data/2.5/" |   private const val BASE_URL = "https://api.openweathermap.org/data/2.5/" | ||||||
| 
 | 
 | ||||||
|     private val logging = HttpLoggingInterceptor().apply { |   private val logging = HttpLoggingInterceptor().apply { | ||||||
|         level = HttpLoggingInterceptor.Level.BODY |     level = HttpLoggingInterceptor.Level.BODY | ||||||
|     } |   } | ||||||
| 
 | 
 | ||||||
|     private val httpClient = OkHttpClient.Builder() |   private val httpClient = OkHttpClient.Builder().addInterceptor(logging).build() | ||||||
|         .addInterceptor(logging) |  | ||||||
|         .build() |  | ||||||
| 
 | 
 | ||||||
|     val instance: WeatherApiService by lazy { |   val instance: WeatherApiService by lazy { | ||||||
|         Retrofit.Builder() |     Retrofit.Builder().baseUrl(BASE_URL).client(httpClient) | ||||||
|             .baseUrl(BASE_URL) |       .addConverterFactory(GsonConverterFactory.create()).build() | ||||||
|             .client(httpClient) |       .create(WeatherApiService::class.java) | ||||||
|             .addConverterFactory(GsonConverterFactory.create()) |   } | ||||||
|             .build() |  | ||||||
|             .create(WeatherApiService::class.java) |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Helper function to filter today's forecast | // Helper function to filter today's forecast | ||||||
| fun getTodaysForecast(forecastResponse: ForecastResponse): ForecastSummary { | fun getTodaysForecast(forecastResponse: ForecastResponse): ForecastSummary { | ||||||
|     val today = Date().time / 1000 // Current timestamp in seconds |   val today = Date().time / 1000 // Current timestamp in seconds | ||||||
|     val tomorrow = today + 86400 // 24 hours later |   val tomorrow = today + 86400 // 24 hours later | ||||||
| 
 | 
 | ||||||
|     // Filter forecasts for today |   // Filter forecasts for today | ||||||
|     val todaysForecasts = forecastResponse.list.filter { it.dt in today..tomorrow } |   val todaysForecasts = forecastResponse.list.filter { it.dt in today..tomorrow } | ||||||
| 
 | 
 | ||||||
|     // Extract min and max temperatures |   // Extract min and max temperatures | ||||||
|     val minTemp = todaysForecasts.minOfOrNull { it.main.temp_min } ?: 0.0 |   val minTemp = todaysForecasts.minOfOrNull { it.main.temp_min } ?: 0.0 | ||||||
|     val maxTemp = todaysForecasts.maxOfOrNull { it.main.temp_max } ?: 0.0 |   val maxTemp = todaysForecasts.maxOfOrNull { it.main.temp_max } ?: 0.0 | ||||||
| 
 | 
 | ||||||
|     // Check for rain, snow, or strong winds |   // Check for rain, snow, or strong winds | ||||||
|     val hasRain = todaysForecasts.any { it.rain != null } |   val hasRain = todaysForecasts.any { it.rain != null } | ||||||
|     val hasSnow = todaysForecasts.any { it.snow != null } |   val hasSnow = todaysForecasts.any { it.snow != null } | ||||||
|     val hasStrongWinds = todaysForecasts.any { it.wind.speed > 10.0 } // Wind speed > 10 m/s |   val hasStrongWinds = todaysForecasts.any { it.wind.speed > 10.0 } // Wind speed > 10 m/s | ||||||
| 
 | 
 | ||||||
|     return ForecastSummary( |   return ForecastSummary( | ||||||
|         minTemp = minTemp, |     minTemp = minTemp, | ||||||
|         maxTemp = maxTemp, |     maxTemp = maxTemp, | ||||||
|         hasRain = hasRain, |     hasRain = hasRain, | ||||||
|         hasSnow = hasSnow, |     hasSnow = hasSnow, | ||||||
|         hasStrongWinds = hasStrongWinds |     hasStrongWinds = hasStrongWinds, | ||||||
|     ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Data class for today's forecast summary | // Data class for today's forecast summary | ||||||
| data class ForecastSummary( | data class ForecastSummary( | ||||||
|     val minTemp: Double, |   val minTemp: Double, | ||||||
|     val maxTemp: Double, |   val maxTemp: Double, | ||||||
|     val hasRain: Boolean, |   val hasRain: Boolean, | ||||||
|     val hasSnow: Boolean, |   val hasSnow: Boolean, | ||||||
|     val hasStrongWinds: Boolean |   val hasStrongWinds: Boolean, | ||||||
| ) | ) | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| package com.module.breeze.ui.theme | package com.module.breeze.ui.theme | ||||||
| 
 | 
 | ||||||
| import android.app.Activity |  | ||||||
| import android.os.Build | import android.os.Build | ||||||
| import androidx.compose.foundation.isSystemInDarkTheme | import androidx.compose.foundation.isSystemInDarkTheme | ||||||
| import androidx.compose.material3.MaterialTheme | import androidx.compose.material3.MaterialTheme | ||||||
|  | @ -12,47 +11,47 @@ import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.ui.platform.LocalContext | import androidx.compose.ui.platform.LocalContext | ||||||
| 
 | 
 | ||||||
| private val DarkColorScheme = darkColorScheme( | private val DarkColorScheme = darkColorScheme( | ||||||
|     primary = Purple80, |   primary = Purple80, | ||||||
|     secondary = PurpleGrey80, |   secondary = PurpleGrey80, | ||||||
|     tertiary = Pink80 |   tertiary = Pink80, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| private val LightColorScheme = lightColorScheme( | private val LightColorScheme = lightColorScheme( | ||||||
|     primary = Purple40, |   primary = Purple40, | ||||||
|     secondary = PurpleGrey40, |   secondary = PurpleGrey40, | ||||||
|     tertiary = Pink40 |   tertiary = Pink40, | ||||||
| 
 | 
 | ||||||
|     /* Other default colors to override |   /* Other default colors to override | ||||||
|     background = Color(0xFFFFFBFE), |   background = Color(0xFFFFFBFE), | ||||||
|     surface = Color(0xFFFFFBFE), |   surface = Color(0xFFFFFBFE), | ||||||
|     onPrimary = Color.White, |   onPrimary = Color.White, | ||||||
|     onSecondary = Color.White, |   onSecondary = Color.White, | ||||||
|     onTertiary = Color.White, |   onTertiary = Color.White, | ||||||
|     onBackground = Color(0xFF1C1B1F), |   onBackground = Color(0xFF1C1B1F), | ||||||
|     onSurface = Color(0xFF1C1B1F), |   onSurface = Color(0xFF1C1B1F), | ||||||
|     */ |   */ | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun BreezeTheme( | fun BreezeTheme( | ||||||
|     darkTheme: Boolean = isSystemInDarkTheme(), |   darkTheme: Boolean = isSystemInDarkTheme(), | ||||||
|     // Dynamic color is available on Android 12+ |   // Dynamic color is available on Android 12+ | ||||||
|     dynamicColor: Boolean = true, |   dynamicColor: Boolean = true, | ||||||
|     content: @Composable () -> Unit |   content: @Composable () -> Unit, | ||||||
| ) { | ) { | ||||||
|     val colorScheme = when { |   val colorScheme = when { | ||||||
|         dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { |     dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { | ||||||
|             val context = LocalContext.current |       val context = LocalContext.current | ||||||
|             if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) |       if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         darkTheme -> LightColorScheme |  | ||||||
|         else -> LightColorScheme |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     MaterialTheme( |     darkTheme -> LightColorScheme | ||||||
|         colorScheme = colorScheme, |     else -> LightColorScheme | ||||||
|         typography = Typography, |   } | ||||||
|         content = content | 
 | ||||||
|     ) |   MaterialTheme( | ||||||
|  |     colorScheme = colorScheme, | ||||||
|  |     typography = Typography, | ||||||
|  |     content = content, | ||||||
|  |   ) | ||||||
| } | } | ||||||
|  | @ -8,27 +8,27 @@ import androidx.compose.ui.unit.sp | ||||||
| 
 | 
 | ||||||
| // Set of Material typography styles to start with | // Set of Material typography styles to start with | ||||||
| val Typography = Typography( | val Typography = Typography( | ||||||
|     bodyLarge = TextStyle( |   bodyLarge = TextStyle( | ||||||
|         fontFamily = FontFamily.Default, |     fontFamily = FontFamily.Default, | ||||||
|         fontWeight = FontWeight.Normal, |     fontWeight = FontWeight.Normal, | ||||||
|         fontSize = 16.sp, |     fontSize = 16.sp, | ||||||
|         lineHeight = 24.sp, |     lineHeight = 24.sp, | ||||||
|         letterSpacing = 0.5.sp |     letterSpacing = 0.5.sp, | ||||||
|     ) |   ), | ||||||
|     /* Other default text styles to override |   /* Other default text styles to override | ||||||
|     titleLarge = TextStyle( |   titleLarge = TextStyle( | ||||||
|         fontFamily = FontFamily.Default, |       fontFamily = FontFamily.Default, | ||||||
|         fontWeight = FontWeight.Normal, |       fontWeight = FontWeight.Normal, | ||||||
|         fontSize = 22.sp, |       fontSize = 22.sp, | ||||||
|         lineHeight = 28.sp, |       lineHeight = 28.sp, | ||||||
|         letterSpacing = 0.sp |       letterSpacing = 0.sp | ||||||
|     ), |   ), | ||||||
|     labelSmall = TextStyle( |   labelSmall = TextStyle( | ||||||
|         fontFamily = FontFamily.Default, |       fontFamily = FontFamily.Default, | ||||||
|         fontWeight = FontWeight.Medium, |       fontWeight = FontWeight.Medium, | ||||||
|         fontSize = 11.sp, |       fontSize = 11.sp, | ||||||
|         lineHeight = 16.sp, |       lineHeight = 16.sp, | ||||||
|         letterSpacing = 0.5.sp |       letterSpacing = 0.5.sp | ||||||
|     ) |   ) | ||||||
|     */ |   */ | ||||||
| ) | ) | ||||||
|  | @ -1,17 +0,0 @@ | ||||||
| package com.module.breeze |  | ||||||
| 
 |  | ||||||
| import org.junit.Test |  | ||||||
| 
 |  | ||||||
| import org.junit.Assert.* |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Example local unit test, which will execute on the development machine (host). |  | ||||||
|  * |  | ||||||
|  * See [testing documentation](http://d.android.com/tools/testing). |  | ||||||
|  */ |  | ||||||
| class ExampleUnitTest { |  | ||||||
|     @Test |  | ||||||
|     fun addition_isCorrect() { |  | ||||||
|         assertEquals(4, 2 + 2) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
		Loading…
	
		Reference in New Issue