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