feat(ui): add checklist report types and 3D panic button; include notes/validation and formatted notification
This commit is contained in:
parent
ba36f0447b
commit
97d37a43ad
29
.idea/copilot.data.migration.agent.xml
generated
Normal file
29
.idea/copilot.data.migration.agent.xml
generated
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AgentMigrationStateService">
|
||||
<option name="pendingSessionIds">
|
||||
<option value="bf5061b4-a1e9-4600-a273-ea8e51b2ce89" />
|
||||
</option>
|
||||
<option name="pendingTurns">
|
||||
<map>
|
||||
<entry key="bf5061b4-a1e9-4600-a273-ea8e51b2ce89">
|
||||
<value>
|
||||
<set>
|
||||
<option value="6dffb37e-ecb0-4c89-8cbe-e38ed347c397" />
|
||||
<option value="f607f271-4885-4c4e-91da-e2caf2abd67a" />
|
||||
<option value="39a0d9c4-a68f-4050-bb14-eda17dc695db" />
|
||||
<option value="94d90579-6a6d-44a9-8b93-de694c0c38ef" />
|
||||
</set>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<pendingWorkingSetItems>
|
||||
<entry key="bf5061b4-a1e9-4600-a273-ea8e51b2ce89">
|
||||
<set>
|
||||
<option value="file://$PROJECT_DIR$/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt" />
|
||||
</set>
|
||||
</entry>
|
||||
</pendingWorkingSetItems>
|
||||
</component>
|
||||
</project>
|
||||
@ -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<String?>(null) }
|
||||
|
||||
// Report options (checkbox-style)
|
||||
val reportOptions = listOf("Kebakaran", "Banjir", "Gempa Bumi", "Huru Hara/Demostrasi", "Lainnya")
|
||||
val checkedMap = remember { mutableStateMapOf<String, Boolean>().apply { reportOptions.forEach { put(it, false) } } }
|
||||
var otherNote by remember { mutableStateOf("") }
|
||||
|
||||
// UI
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@ -53,17 +59,97 @@ 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))
|
||||
|
||||
// Each option as a row with checkbox
|
||||
reportOptions.forEach { option ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp)
|
||||
.toggleable(
|
||||
value = checkedMap[option] ?: false,
|
||||
onValueChange = { checked -> checkedMap[option] = checked }
|
||||
)
|
||||
) {
|
||||
Checkbox(
|
||||
checked = checkedMap[option] ?: false,
|
||||
onCheckedChange = { checked -> checkedMap[option] = checked }
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(text = option)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Custom Dialog untuk menampilkan status kirim notifikasi — styled sesuai tema panic
|
||||
// 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)
|
||||
)
|
||||
|
||||
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(
|
||||
@ -130,6 +216,7 @@ fun MyApp() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 <your-topic> dengan topik Anda
|
||||
|
||||
|
||||
|
||||
val requestBody = "Notifikasi dari Satrio Putra Wardani 202310715307".toRequestBody(
|
||||
val requestBody = message.toRequestBody(
|
||||
"text/plain".toMediaType()
|
||||
)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user