diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index bb02648..c728902 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -50,6 +50,8 @@ dependencies {
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3)
+ implementation("com.squareup.okhttp3:okhttp:4.11.0")
+
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1421c65..6e146bf 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -22,6 +22,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/id/ac/ubharajaya/panicbutton/JalurEvakuasiActivity.kt b/app/src/main/java/id/ac/ubharajaya/panicbutton/JalurEvakuasiActivity.kt
new file mode 100644
index 0000000..0a41d2d
--- /dev/null
+++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/JalurEvakuasiActivity.kt
@@ -0,0 +1,47 @@
+package id.ac.ubharajaya.panicbutton
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+
+class JalurEvakuasiActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContent {
+ JalurEvakuasiScreen(onClose = { finish() })
+ }
+ }
+}
+
+@Composable
+fun JalurEvakuasiScreen(onClose: () -> Unit) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+
+ Image(
+ painter = painterResource(id = R.drawable.evakuasi),
+ contentDescription = "Jalur Evakuasi",
+ modifier = Modifier.fillMaxWidth()
+ )
+
+ Spacer(modifier = Modifier.height(20.dp))
+
+ Button(onClick = onClose) {
+ Text("Close")
+ }
+ }
+}
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 dabdc85..cb95295 100644
--- a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt
+++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt
@@ -1,47 +1,227 @@
package id.ac.ubharajaya.panicbutton
+import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
-import androidx.activity.enableEdgeToEdge
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.text.BasicTextField
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.*
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.tooling.preview.Preview
-import id.ac.ubharajaya.panicbutton.ui.theme.PanicButtonTheme
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- enableEdgeToEdge()
setContent {
- PanicButtonTheme {
- Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
- Greeting(
- name = "Android",
- modifier = Modifier.padding(innerPadding)
- )
+ MyApp(
+ onClose = { finish() },
+ onOpenEvacuation = {
+ startActivity(Intent(this, JalurEvakuasiActivity::class.java))
}
- }
+ )
}
}
}
-@Composable
-fun Greeting(name: String, modifier: Modifier = Modifier) {
- Text(
- text = "Hello $name!",
- modifier = modifier
- )
+// Emoji untuk tiap kondisi
+fun getEmoji(condition: String): String {
+ return when (condition) {
+ "Kebakaran" -> "🔥"
+ "Banjir" -> "⛈️"
+ "Tsunami" -> "🌊"
+ "Gunung Meletus" -> "🌋"
+ "Gempa Bumi" -> "🌏"
+ "Huru Hara/Demonstrasi" -> "👿"
+ "Binatang Buas" -> "🐍"
+ "Radiasi Nuklir" -> "☢️"
+ "Biohazard" -> "☣️"
+ else -> ""
+ }
}
-@Preview(showBackground = true)
@Composable
-fun GreetingPreview() {
- PanicButtonTheme {
- Greeting("Android")
+fun MyApp(onClose: () -> Unit, onOpenEvacuation: () -> Unit) {
+ val focusManager = LocalFocusManager.current
+ var message by remember { mutableStateOf("Klik tombol untuk mengirim notifikasi") }
+ var selectedConditions by remember { mutableStateOf(mutableSetOf()) }
+ var additionalNotes by remember { mutableStateOf(TextFieldValue("")) }
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(16.dp),
+ verticalArrangement = Arrangement.Top,
+ horizontalAlignment = Alignment.Start
+ ) {
+ // Judul
+ Text(
+ text = "Terjadi Kondisi Darurat:",
+ fontSize = 26.sp,
+ fontWeight = FontWeight.Bold,
+ color = Color.Red,
+ modifier = Modifier.padding(bottom = 16.dp)
+ )
+
+ // Daftar kondisi
+ listOf(
+ "Kebakaran",
+ "Banjir",
+ "Tsunami",
+ "Gunung Meletus",
+ "Gempa Bumi",
+ "Huru Hara/Demonstrasi",
+ "Binatang Buas",
+ "Radiasi Nuklir",
+ "Biohazard",
+ "Lainnya"
+ ).forEach { condition ->
+ val emoji = getEmoji(condition)
+
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable {
+ focusManager.clearFocus()
+ selectedConditions = selectedConditions.toMutableSet().apply {
+ if (contains(condition)) remove(condition) else add(condition)
+ }
+ }
+ .padding(vertical = 4.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Checkbox(
+ checked = selectedConditions.contains(condition),
+ onCheckedChange = { isChecked ->
+ focusManager.clearFocus()
+ selectedConditions = selectedConditions.toMutableSet().apply {
+ if (isChecked) add(condition) else remove(condition)
+ }
+ }
+ )
+ Text(
+ text = "$emoji $condition",
+ modifier = Modifier.padding(start = 8.dp)
+ )
+ }
+ }
+
+ // Catatan tambahan
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(text = "Catatan tambahan:", fontWeight = FontWeight.Bold)
+
+ BasicTextField(
+ value = additionalNotes,
+ onValueChange = { additionalNotes = it },
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(100.dp)
+ .padding(8.dp)
+ .border(1.dp, Color.Gray),
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done)
+ )
+
+ // ================================================
+ // Tombol Kirim + Lihat Jalur Evakuasi (Berdampingan)
+ // ================================================
+ Spacer(modifier = Modifier.height(16.dp))
+
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+
+ // Tombol Kirim Laporan
+ Button(
+ onClick = {
+ val notes = additionalNotes.text
+ val conditions = selectedConditions.joinToString(", ") {
+ "${getEmoji(it)} $it"
+ }
+ val report = "Kondisi: $conditions\nCatatan: $notes"
+
+ sendNotification(report) { response ->
+ message = response
+ }
+ },
+ modifier = Modifier.weight(1f),
+ colors = ButtonDefaults.buttonColors(containerColor = Color.Red)
+ ) {
+ Text(text = "Kirim Laporan", color = Color.White)
+ }
+
+ Spacer(modifier = Modifier.width(12.dp))
+
+ // Tombol Jalur Evakuasi
+ Button(
+ onClick = onOpenEvacuation,
+ modifier = Modifier.weight(1f),
+ colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF0080FF))
+ ) {
+ Text(text = "Lihat Jalur Evakuasi", color = Color.White)
+ }
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ text = "“JANGAN PANIK! SEGERA EVAKUASI\nDIRI ANDA KE TITIK KUMPUL”",
+ color = Color.Red,
+ fontSize = 15.sp
+ )
+
+ Spacer(modifier = Modifier.height(20.dp))
+
+ // Tombol Tutup (opsional)
+ Button(onClick = onClose) {
+ Text("Tutup")
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(text = message)
}
-}
\ No newline at end of file
+}
+
+// ===============================================================
+// Fungsi Kirim Notifikasi ke Server ntfy.ubharajaya.ac.id
+// ===============================================================
+fun sendNotification(report: String, onResult: (String) -> Unit) {
+ val client = OkHttpClient()
+ val url = "https://ntfy.ubharajaya.ac.id/panic-button"
+
+ val requestBody = RequestBody.create("text/plain".toMediaType(), report)
+
+ val request = Request.Builder()
+ .url(url)
+ .addHeader("Title", "Alert")
+ .addHeader("Priority", "urgent")
+ .post(requestBody)
+ .build()
+
+ Thread {
+ try {
+ val response = client.newCall(request).execute()
+ if (response.isSuccessful) {
+ onResult("Notifikasi berhasil dikirim!")
+ } else {
+ onResult("Gagal mengirim notifikasi: ${response.code}")
+ }
+ } catch (e: Exception) {
+ onResult("Error: ${e.message}")
+ }
+ }.start()
+}
diff --git a/app/src/main/res/drawable/evakuasi.png b/app/src/main/res/drawable/evakuasi.png
new file mode 100644
index 0000000..9a7688a
Binary files /dev/null and b/app/src/main/res/drawable/evakuasi.png differ
diff --git a/app/src/main/res/drawable/red_button.png b/app/src/main/res/drawable/red_button.png
new file mode 100644
index 0000000..5124fcd
Binary files /dev/null and b/app/src/main/res/drawable/red_button.png differ