Compare commits

..

No commits in common. "cf2a96c3ccfd60df7c47b4a2eb620f4bead08dd1" and "da5fb5c23505d53c665d0da6786a6320024b8d9a" have entirely different histories.

5 changed files with 38 additions and 222 deletions

View File

@ -29,7 +29,4 @@ Repository ini digunakan untuk praktikum perkuliahan pemrograman mobile.
# Kelompok 8 # Kelompok 8
1. Lalu Muhammad Anggana Subhan (202310715277) 1. Lalu Muhammad Anggana Subhan (202310715277)
2. Muhammad Rafly Al-Fathir (202310715043) 2. Muhammad Rafly Al-Fathir (202310715043)
3. Rafi Fattan Fitriardi (202310715002) 3. Rafi Fattan Fitriardi (202310715002)
Latihan Praktikum 1:
Mengganti logo tombol menjadi lingkar merah dengan menambahkan gambar red_button.jpg

View File

@ -22,11 +22,6 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".JalurEvakuasiActivity"
android:exported="false"/>
</application> </application>
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />

View File

@ -1,47 +0,0 @@
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")
}
}
}

View File

@ -1,25 +1,18 @@
package id.ac.ubharajaya.panicbutton package id.ac.ubharajaya.panicbutton
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.Image
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.clickable
import androidx.compose.material3.* import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.res.painterResource
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -29,189 +22,67 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
MyApp( MyApp()
onClose = { finish() },
onOpenEvacuation = {
startActivity(Intent(this, JalurEvakuasiActivity::class.java))
}
)
} }
} }
} }
// 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 -> ""
}
}
@Composable @Composable
fun MyApp(onClose: () -> Unit, onOpenEvacuation: () -> Unit) { fun MyApp() {
val focusManager = LocalFocusManager.current
var message by remember { mutableStateOf("Klik tombol untuk mengirim notifikasi") } var message by remember { mutableStateOf("Klik tombol untuk mengirim notifikasi") }
var selectedConditions by remember { mutableStateOf(mutableSetOf<String>()) }
var additionalNotes by remember { mutableStateOf(TextFieldValue("")) }
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(16.dp), .padding(16.dp),
verticalArrangement = Arrangement.Top, verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.Start horizontalAlignment = Alignment.CenterHorizontally
) { ) {
// Judul Text(text = message, Modifier.padding(bottom = 16.dp))
Text(
text = "Terjadi Kondisi Darurat:",
fontSize = 26.sp,
fontWeight = FontWeight.Bold,
color = Color.Red,
modifier = Modifier.padding(bottom = 16.dp)
)
// Daftar kondisi // Ganti Button dengan ImageButton versi Compose
listOf( androidx.compose.foundation.Image(
"Kebakaran", painter = painterResource(id = R.drawable.red_button),
"Banjir", contentDescription = "Tombol merah",
"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 modifier = Modifier
.fillMaxWidth() .size(145.dp, 365.dp)
.height(100.dp) .clickable {
.padding(8.dp) sendNotification { response ->
.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 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)
} }
} }
// ===============================================================
// 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)
// Fungsi untuk mengirimkan HTTP request
fun sendNotification(onResult: (String) -> Unit) {
val client = OkHttpClient()
val url = "https://ntfy.ubharajaya.ac.id/panic-button" // Ganti <your-topic> dengan topik Anda
val requestBody = RequestBody.create(
"text/plain".toMediaType(), // Mengirim plain text
"Notifikasi dari Kelompok 8 (Lalu Angga, M Rafly, Rafi Fattan)" // Pesan yang akan tampil
)
val request = Request.Builder() val request = Request.Builder()
.url(url) .url(url)
.addHeader("Title", "Alert") .addHeader("Title", "Alert")
.addHeader("Priority", "urgent") .addHeader("Priority", "urgent")
.addHeader("Tags", "alert warning,rotating_light")
.post(requestBody) .post(requestBody)
.build() .build()
// Eksekusi request di thread terpisah
Thread { Thread {
try { try {
val response = client.newCall(request).execute() val response = client.newCall(request).execute()
@ -224,4 +95,4 @@ fun sendNotification(report: String, onResult: (String) -> Unit) {
onResult("Error: ${e.message}") onResult("Error: ${e.message}")
} }
}.start() }.start()
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 MiB