diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 36c5893..471e362 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -69,4 +69,7 @@ dependencies { // AndroidX SplashScreen (required for installSplashScreen API) implementation("androidx.core:core-splashscreen:1.0.1") + + // Play Services Location for GPS (FusedLocationProviderClient) + implementation("com.google.android.gms:play-services-location:21.0.1") } \ No newline at end of file diff --git a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt index 2dd2213..822ffb8 100644 --- a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt +++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt @@ -1,21 +1,68 @@ package id.ac.ubharajaya.panicbutton +import android.Manifest import android.content.Intent +import android.content.pm.PackageManager import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.ContextCompat import androidx.lifecycle.ViewModelProvider import androidx.compose.material3.MaterialTheme +import com.google.android.gms.location.LocationServices +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch class MainActivity : ComponentActivity() { private lateinit var viewModel: MainViewModel + private val requestPermissionLauncher = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean -> + // result handled inline when requesting + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewModel = ViewModelProvider(this).get(MainViewModel::class.java) + + val fusedClient = LocationServices.getFusedLocationProviderClient(this) + val openEvacMaps = { startActivity(Intent(this, EvacuationMapsActivity::class.java)) } + + // onSendAlert will try to get location (if permission granted) and then call viewModel.sendAlert + val onSendAlert = { + // Check permission + val fineGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED + val coarseGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED + + if (!fineGranted && !coarseGranted) { + // Request fine location permission (preferred) + requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION) + // After permission flow, user will need to press the button again to actually send with location + viewModel.dialogMessage = "Izin lokasi dibutuhkan untuk menyertakan koordinat. Silakan tekan lagi setelah mengizinkan lokasi." + return@let + } + + // Try get last location asynchronously + CoroutineScope(Dispatchers.Main).launch { + try { + val loc = fusedClient.lastLocation.await() // need extension await - we'll handle fallback + if (loc != null) { + viewModel.sendAlert(loc.latitude, loc.longitude) + } else { + // fallback: send without coordinates + viewModel.sendAlert() + } + } catch (e: Exception) { + viewModel.sendAlert() + } + } + } + setContent { MaterialTheme { MainScreen(viewModel = viewModel, onOpenEvacMaps = openEvacMaps) diff --git a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainScreen.kt b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainScreen.kt index 13422c9..1608514 100644 --- a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainScreen.kt +++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainScreen.kt @@ -12,7 +12,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.foundation.shape.RoundedCornerShape import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -28,7 +28,7 @@ import androidx.compose.foundation.layout.IntrinsicSize @OptIn(ExperimentalMaterial3Api::class) @Composable -fun MainScreen(viewModel: MainViewModel, onOpenEvacMaps: () -> Unit) { +fun MainScreen(viewModel: MainViewModel, onOpenEvacMaps: () -> Unit, onSendAlert: () -> Unit) { Scaffold( modifier = Modifier.fillMaxSize(), bottomBar = { @@ -38,7 +38,7 @@ fun MainScreen(viewModel: MainViewModel, onOpenEvacMaps: () -> Unit) { .height(120.dp), contentAlignment = Alignment.TopCenter ) { - PanicButton(onClick = { viewModel.sendAlert() }, buttonSize = 130.dp, shadowSize = 160.dp) + PanicButton(onClick = { onSendAlert() }, buttonSize = 130.dp, shadowSize = 160.dp) } } ) { padding -> diff --git a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainViewModel.kt b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainViewModel.kt index 4aeebdb..de709a5 100644 --- a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainViewModel.kt +++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainViewModel.kt @@ -40,7 +40,8 @@ class MainViewModel : ViewModel() { } } - fun sendAlert() { + // latitude/longitude optional parameters + fun sendAlert(latitude: Double? = null, longitude: Double? = null) { val selectedOptions = options.filter { isChecked(it.label) }.map { it.label } if (selectedOptions.isEmpty()) { @@ -59,6 +60,12 @@ class MainViewModel : ViewModel() { if (otherNote.isNotBlank()) { bodyBuilder.append("\nCatatan: ${otherNote.trim()}") } + + // Append coordinates if available + if (latitude != null && longitude != null) { + bodyBuilder.append("\nLokasi: https://maps.google.com/?q=$latitude,$longitude") + } + val payload = bodyBuilder.toString() // Use NotificationSender utility to send the payload