diff --git a/.idea/misc.xml b/.idea/misc.xml index 74dd639..b2c751a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 804be05..ad41a53 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,8 @@ xmlns:tools="http://schemas.android.com/tools"> + + 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) {} +} \ No newline at end of file diff --git a/app/src/main/java/com/module/breeze/MainActivity.kt b/app/src/main/java/com/module/breeze/MainActivity.kt index e9ae634..0385079 100644 --- a/app/src/main/java/com/module/breeze/MainActivity.kt +++ b/app/src/main/java/com/module/breeze/MainActivity.kt @@ -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(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) ) } }