diff --git a/.idea/copilot.data.migration.agent.xml b/.idea/copilot.data.migration.agent.xml
new file mode 100644
index 0000000..40c729a
--- /dev/null
+++ b/.idea/copilot.data.migration.agent.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 12835ec..6256157 100644
--- a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt
+++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt
@@ -4,13 +4,14 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.tween
-import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
@@ -45,6 +46,11 @@ fun MyApp() {
// dialogMessage akan menampung hasil callback dari sendNotification; null = tidak tampil
var dialogMessage by remember { mutableStateOf(null) }
+ // Report options (checkbox-style)
+ val reportOptions = listOf("Kebakaran", "Banjir", "Gempa Bumi", "Huru Hara/Demostrasi", "Lainnya")
+ val checkedMap = remember { mutableStateMapOf().apply { reportOptions.forEach { put(it, false) } } }
+ var otherNote by remember { mutableStateOf("") }
+
// UI
Column(
modifier = Modifier
@@ -53,76 +59,157 @@ fun MyApp() {
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
- // tombol panic
- PanicButton(onClick = {
- // Kirim HTTP request saat tombol ditekan
- sendNotification { response ->
- // tampilkan dialog ketika ada respon
- dialogMessage = response
- }
- })
- }
+ // Checklist area similar to the wireframe
+ Surface(
+ tonalElevation = 2.dp,
+ shape = RoundedCornerShape(8.dp),
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 24.dp)
+ ) {
+ Column(modifier = Modifier.padding(12.dp)) {
+ Text(text = "Terjadi Kondisi Darurat", fontWeight = FontWeight.SemiBold)
+ Spacer(modifier = Modifier.height(8.dp))
- // Custom Dialog untuk menampilkan status kirim notifikasi — styled sesuai tema panic
- if (dialogMessage != null) {
- Dialog(onDismissRequest = { dialogMessage = null }) {
- Box(
- modifier = Modifier
- .fillMaxSize()
- .padding(24.dp),
- contentAlignment = Alignment.Center
- ) {
- Surface(
- shape = RoundedCornerShape(12.dp),
- color = Color.White,
- tonalElevation = 8.dp,
- modifier = Modifier.wrapContentWidth()
- ) {
- Column(
+ // Each option as a row with checkbox
+ reportOptions.forEach { option ->
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
- .padding(0.dp)
- .widthIn(min = 280.dp),
- horizontalAlignment = Alignment.CenterHorizontally
- ) {
- // header
- Box(
- modifier = Modifier
- .fillMaxWidth()
- .background(color = Color(0xFFB71C1C))
- .padding(vertical = 12.dp),
- contentAlignment = Alignment.Center
- ) {
- Text(
- text = "Notifikasi",
- color = Color.White,
- fontWeight = FontWeight.Bold,
- fontSize = 18.sp
+ .fillMaxWidth()
+ .padding(vertical = 4.dp)
+ .toggleable(
+ value = checkedMap[option] ?: false,
+ onValueChange = { checked -> checkedMap[option] = checked }
)
- }
-
- Spacer(modifier = Modifier.height(12.dp))
-
- // message
- Text(
- text = dialogMessage ?: "",
- color = Color.Black,
- modifier = Modifier.padding(horizontal = 16.dp)
+ ) {
+ Checkbox(
+ checked = checkedMap[option] ?: false,
+ onCheckedChange = { checked -> checkedMap[option] = checked }
)
+ Spacer(modifier = Modifier.width(8.dp))
+ Text(text = option)
+ }
+ }
- Spacer(modifier = Modifier.height(20.dp))
+ // Additional notes field — show always (wireframe shows a note field)
+ Spacer(modifier = Modifier.height(8.dp))
+ OutlinedTextField(
+ value = otherNote,
+ onValueChange = { otherNote = it },
+ label = { Text("Catatan tambahan (opsional)") },
+ placeholder = { Text("Catatan tambahan ...") },
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 8.dp)
+ )
- // action
- Box(
+ Spacer(modifier = Modifier.height(8.dp))
+
+ // small hint when Lainnya is checked but note empty
+ if ((checkedMap["Lainnya"] == true) && otherNote.isBlank()) {
+ Text(
+ text = "Catatan wajib jika Anda memilih 'Lainnya'",
+ color = Color(0xFFB71C1C),
+ style = MaterialTheme.typography.bodySmall,
+ modifier = Modifier.padding(top = 6.dp)
+ )
+ }
+ }
+ }
+
+ Spacer(modifier = Modifier.height(18.dp))
+
+ // Keep the existing nice PanicButton unchanged
+ PanicButton(onClick = {
+ // Validation: at least one option selected
+ val selected = reportOptions.filter { checkedMap[it] == true }
+ if (selected.isEmpty()) {
+ dialogMessage = "Pilih minimal satu jenis laporan sebelum mengirim."
+ return@PanicButton
+ }
+ if (selected.contains("Lainnya") && otherNote.isBlank()) {
+ dialogMessage = "Untuk opsi 'Lainnya', harap tambahkan catatan yang menjelaskan keadaan."
+ return@PanicButton
+ }
+
+ // build message: list selected options and the note
+ val message = buildString {
+ append("Jenis Laporan: ")
+ append(selected.joinToString(", "))
+ append("\n")
+ append("Keterangan: ")
+ if (selected.contains("Lainnya")) append(otherNote.trim()) else append("-")
+ append("\n")
+ append("Pengirim: Satrio Putra Wardani 202310715307")
+ }
+
+ sendNotification(message) { response -> dialogMessage = response }
+ })
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ // dialog hasil
+ if (dialogMessage != null) {
+ Dialog(onDismissRequest = { dialogMessage = null }) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(24.dp),
+ contentAlignment = Alignment.Center
+ ) {
+ Surface(
+ shape = RoundedCornerShape(12.dp),
+ color = Color.White,
+ tonalElevation = 8.dp,
+ modifier = Modifier.wrapContentWidth()
+ ) {
+ Column(
modifier = Modifier
- .fillMaxWidth()
- .padding(horizontal = 16.dp, vertical = 12.dp),
- contentAlignment = Alignment.Center
+ .padding(0.dp)
+ .widthIn(min = 280.dp),
+ horizontalAlignment = Alignment.CenterHorizontally
) {
- Button(
- onClick = { dialogMessage = null },
- colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFB71C1C))
+ // header
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(color = Color(0xFFB71C1C))
+ .padding(vertical = 12.dp),
+ contentAlignment = Alignment.Center
) {
- Text(text = "OK", color = Color.White)
+ Text(
+ text = "Notifikasi",
+ color = Color.White,
+ fontWeight = FontWeight.Bold,
+ fontSize = 18.sp
+ )
+ }
+
+ Spacer(modifier = Modifier.height(12.dp))
+
+ // message
+ Text(
+ text = dialogMessage ?: "",
+ color = Color.Black,
+ modifier = Modifier.padding(horizontal = 16.dp)
+ )
+
+ Spacer(modifier = Modifier.height(20.dp))
+
+ // action
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 12.dp),
+ contentAlignment = Alignment.Center
+ ) {
+ Button(
+ onClick = { dialogMessage = null },
+ colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFB71C1C))
+ ) {
+ Text(text = "OK", color = Color.White)
+ }
}
}
}
@@ -206,34 +293,18 @@ fun PanicButton(
)
}
}
-
- Spacer(modifier = Modifier.height(14.dp))
-
- // label with 3D-like chip
- Surface(
- color = panicColor.copy(alpha = 0.10f),
- shape = RoundedCornerShape(20.dp),
- tonalElevation = 0.dp
- ) {
- Text(
- text = "PANIC",
- color = panicColor,
- modifier = Modifier
- .padding(horizontal = 20.dp, vertical = 8.dp)
- )
- }
}
}
-// Fungsi untuk mengirimkan HTTP request
-fun sendNotification(onResult: (String) -> Unit) {
+// Fungsi untuk mengirimkan HTTP request (mengikuti format pesan yang lebih rapi)
+fun sendNotification(message: String, onResult: (String) -> Unit) {
val client = OkHttpClient()
val url = "https://ntfy.ubharajaya.ac.id/panic-button" // Ganti dengan topik Anda
- val requestBody = "Notifikasi dari Satrio Putra Wardani 202310715307".toRequestBody(
+ val requestBody = message.toRequestBody(
"text/plain".toMediaType()
)