Added GPS and Current Weather

This commit is contained in:
Lorenz Hohermuth 2025-03-24 22:01:01 +01:00
parent 49b9553118
commit b93c2f65d7
4 changed files with 139 additions and 28 deletions

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">

View File

@ -3,6 +3,8 @@
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"

View File

@ -0,0 +1,45 @@
package com.module.breeze
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
import androidx.core.content.ContextCompat
// AI
class GpsRepository(private val context: Context) : LocationListener {
private var locationManager: LocationManager? = null
private var onLocationChanged: ((Location) -> Unit)? = null
fun startListening(onLocationChanged: (Location) -> Unit) {
this.onLocationChanged = onLocationChanged
locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
==
PackageManager.PERMISSION_GRANTED
) {
locationManager?.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
1000L,
1f,
this
)
}
}
fun stopListening() {
locationManager?.removeUpdates(this)
}
override fun onLocationChanged(location: Location) {
onLocationChanged?.invoke(location)
}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
override fun onProviderEnabled(provider: String) {}
override fun onProviderDisabled(provider: String) {}
}

View File

@ -50,6 +50,21 @@ import kotlinx.coroutines.runBlocking
import java.text.DecimalFormat
import java.time.LocalDate
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
@ -114,28 +129,66 @@ fun fetchWeather(ctx: Context): ForecastSummary {
return data
}
fun fetchCurrentTemp(ctx: Context, lat: Double, lon: Double): WeatherResponse {
var data: WeatherResponse
runBlocking {
data = RetrofitClient.instance.getCurrentWeather(lat, lon, apiKey)
}
return data
}
@Composable
fun WeatherInfo(modifier: Modifier = Modifier) {
val ctx = LocalContext.current
var forecast by remember { mutableStateOf(ForecastSummary(0.0, 0.0, false, false, false)) }
var currentTemp by remember {
mutableStateOf(
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 permissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { 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) {
forecast = fetchWeather(ctx)
}
Navigation(
iconStyle.Settings,
"Settings Icon",
onClick = { MainActivity.openSettings(ctx) }
)
iconStyle.Settings, "Settings Icon", onClick = { MainActivity.openSettings(ctx) })
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Row(verticalAlignment = Alignment.Bottom)
{
Row(verticalAlignment = Alignment.Bottom) {
Icon(
imageVector = iconStyle.Map,
contentDescription = "Location Icon",
@ -162,29 +215,46 @@ fun WeatherInfo(modifier: Modifier = Modifier) {
}
Row {
Icon(
imageVector = iconStyle.ArrowDownward,
contentDescription = "Arrow down Icon"
imageVector = iconStyle.ArrowDownward, contentDescription = "Arrow down Icon"
)
Text(
text = numberFormat.format(forecast.minTemp.roundToInt()),
text = numberFormat.format(forecast.minTemp.roundToInt()) + "°",
fontSize = fontSizeUpper,
fontWeight = breezeFontWeight
)
Icon(
imageVector = iconStyle.ArrowUpward,
contentDescription = "Arrow up Icon"
imageVector = iconStyle.ArrowUpward, contentDescription = "Arrow up Icon"
)
Text(
text = numberFormat.format(forecast.maxTemp.roundToInt()),
text = numberFormat.format(forecast.maxTemp.roundToInt()) + "°",
fontSize = fontSizeUpper,
fontWeight = breezeFontWeight
)
}
Text(
text = "15°",
fontSize = fontSizeCurrentTemp,
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 = "Grand Permission",
fontWeight = breezeFontWeight,
)
}
}
}
}
@ -200,26 +270,21 @@ fun GreetingPreview() {
@Composable
fun Navigation(icon: ImageVector, iconDescription: String, onClick: () -> Unit = {}) {
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
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)
modifier = Modifier.padding(0.dp, 40.dp, 28.dp, 0.dp)
) {
Icon(
imageVector = icon,
contentDescription = iconDescription,
modifier = Modifier
.size(40.dp)
modifier = Modifier.size(40.dp)
)
}
}