Compare commits

..

2 Commits

Author SHA1 Message Date
RafiFattan23
cf2a96c3cc Praktikum 2 beserta latihan 2025-11-20 14:32:43 +07:00
RafiFattan23
0baec72446 Praktikum 2 beserta latihan 2025-11-20 14:32:21 +07:00
5 changed files with 221 additions and 37 deletions

View File

@ -30,3 +30,6 @@ Repository ini digunakan untuk praktikum perkuliahan pemrograman mobile.
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,6 +22,11 @@
<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

@ -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")
}
}
}

View File

@ -1,18 +1,25 @@
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.layout.* import androidx.compose.foundation.border
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.material3.Button import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
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.res.painterResource import androidx.compose.ui.unit.sp
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -22,67 +29,189 @@ 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() { fun MyApp(onClose: () -> Unit, onOpenEvacuation: () -> Unit) {
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.Center, verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.Start
) { ) {
Text(text = message, Modifier.padding(bottom = 16.dp)) // Judul
Text(
text = "Terjadi Kondisi Darurat:",
fontSize = 26.sp,
fontWeight = FontWeight.Bold,
color = Color.Red,
modifier = Modifier.padding(bottom = 16.dp)
)
// Ganti Button dengan ImageButton versi Compose // Daftar kondisi
androidx.compose.foundation.Image( listOf(
painter = painterResource(id = R.drawable.red_button), "Kebakaran",
contentDescription = "Tombol merah", "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 modifier = Modifier
.size(145.dp, 365.dp) .fillMaxWidth()
.clickable { .height(100.dp)
sendNotification { response -> .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 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
// Fungsi untuk mengirimkan HTTP request // ===============================================================
fun sendNotification(onResult: (String) -> Unit) { fun sendNotification(report: String, onResult: (String) -> Unit) {
val client = OkHttpClient() val client = OkHttpClient()
val url = "https://ntfy.ubharajaya.ac.id/panic-button" // Ganti <your-topic> dengan topik Anda val url = "https://ntfy.ubharajaya.ac.id/panic-button"
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 requestBody = RequestBody.create("text/plain".toMediaType(), report)
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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 MiB