praktikum 2

This commit is contained in:
HagaDalpintoGinting 2025-11-20 14:56:49 +07:00
parent ee739fd565
commit 5b8e28d6ee
6 changed files with 229 additions and 30 deletions

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
@ -10,7 +11,9 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.PanicButton">
android:theme="@style/Theme.PanicButton"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
@ -18,10 +21,17 @@
android:theme="@style/Theme.PanicButton">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".JalurEvakuasiActivity"
android:exported="false"
android:label="Jalur Evakuasi"
android:theme="@style/Theme.PanicButton" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@ -0,0 +1,54 @@
package id.ac.ubharajaya.panicbutton
import android.app.Activity
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.layout.ContentScale // <-- TAMBAHKAN IMPORT INI
import androidx.compose.ui.platform.LocalContext
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()
}
}
}
@Composable
fun JalurEvakuasiScreen() {
val context = LocalContext.current
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Image(
painter = painterResource(id = R.drawable.jalur_evakuasi),
contentDescription = "Denah Jalur Evakuasi",
modifier = Modifier
.fillMaxWidth()
.weight(1f),
contentScale = ContentScale.Fit
)
Button(
onClick = {
(context as? Activity)?.finish()
},
modifier = Modifier.padding(vertical = 16.dp)
) {
Text(text = "TUTUP")
}
}
}

View File

@ -1,20 +1,35 @@
package id.ac.ubharajaya.panicbutton
import android.app.Activity
import android.content.Intent // <-- TAMBAHKAN IMPORT INI
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
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.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.TextFieldValue
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)
@ -27,56 +42,175 @@ class MainActivity : ComponentActivity() {
@Composable
fun MyApp() {
// State untuk menampilkan hasil request
var message by remember { mutableStateOf("Klik tombol untuk mengirim notifikasi") }
val focusManager = LocalFocusManager.current
val context = LocalContext.current // Digunakan untuk tombol "Tutup" dan "Intent"
var message by remember { mutableStateOf("Kirim laporan untuk mendapatkan notifikasi") }
var selectedConditions by remember { mutableStateOf(mutableSetOf<String>()) }
var additionalNotes by remember { mutableStateOf(TextFieldValue("")) }
// PERMINTAAN 2: Buat Map untuk memetakan kondisi ke emoji tags
val conditionToTagMap = mapOf(
"Kebakaran" to "fire",
"Banjir" to "cloud_with_rain",
"Gempa Bumi" to "earth_asia",
"Huru hara/Demonstrasi" to "imp",
"Lainnya" to "grey_question"
)
// UI
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.Start
) {
Text(text = message, Modifier.padding(bottom = 16.dp))
Button(onClick = {
// Kirim HTTP request saat tombol ditekan
sendNotification { response ->
message = response
// PERMINTAAN 1: Judul diperbesar dan dibuat bold
Text(
text = "Terjadi Kondisi Darurat",
fontSize = 24.sp, // Ukuran font diperbesar
fontWeight = FontWeight.Bold, // Teks dibuat bold
color = Color.Red,
modifier = Modifier.padding(bottom = 16.dp)
)
// Pilihan checkbox (tidak ada perubahan)
listOf("Kebakaran", "Banjir", "Gempa Bumi", "Huru hara/Demonstrasi", "Lainnya").forEach { 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 = condition,
modifier = Modifier.padding(start = 8.dp)
)
}
}
// Catatan tambahan (tidak ada perubahan)
Spacer(modifier = Modifier.height(16.dp))
Text(text = "Catatan tambahan:")
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
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = {
// PERMINTAAN 2: Logika untuk mendapatkan tags dari kondisi yang dipilih
val notes = additionalNotes.text
val conditionsText = selectedConditions.joinToString(", ")
val report = "Kondisi: $conditionsText\nCatatan: $notes"
// Dapatkan tags dari kondisi yang dipilih menggunakan Map
val tags = selectedConditions.mapNotNull { conditionToTagMap[it] }.joinToString(",")
// Kirim report dan tags ke fungsi notifikasi
sendNotification(report, tags) { response ->
message = response
}
},
colors = ButtonDefaults.buttonColors(containerColor = Color.Red)
) {
Text(text = "Kirim Laporan", color = Color.White)
}
// PERMINTAAN 1: Keterangan dibuat bold
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "“JANGAN PANIK! SEGERA EVAKUASI\nDIRI ANDA KE TITIK KUMPUL”",
color = Color.Red,
fontSize = 15.sp,
fontWeight = FontWeight.Bold // Teks dibuat bold
)
// Hasil request (tidak ada perubahan)
Spacer(modifier = Modifier.height(16.dp))
Text(text = message, Modifier.padding(top = 16.dp))
// Spacer untuk mendorong tombol ke bagian bawah layar
Spacer(modifier = Modifier.weight(1f))
// PERMINTAAN 1: Tambahkan tombol Lihat Jalur Evakuasi dan Tutup
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween // Agar tombol merapat ke sisi
) {
Button(
onClick = {
// ▼▼▼ PERUBAHAN DI SINI ▼▼▼
// Membuat Intent untuk memulai JalurEvakuasiActivity
val intent = Intent(context, JalurEvakuasiActivity::class.java)
context.startActivity(intent)
// ▲▲▲ AKHIR DARI PERUBAHAN ▲▲▲
}
) {
Text(text = "Lihat Jalur Evakuasi")
}
Button(
onClick = {
// Logika untuk menutup aplikasi
(context as? Activity)?.finish()
},
colors = ButtonDefaults.buttonColors(containerColor = Color.Gray)
) {
Text(text = "Tutup", color = Color.White)
}
}) {
Text(text = "Kirim Alert")
}
}
}
// Fungsi untuk mengirimkan HTTP request
fun sendNotification(onResult: (String) -> Unit) {
// PERMINTAAN 2: Ubah fungsi `sendNotification` untuk menerima parameter tags
fun sendNotification(report: String, tags: String, onResult: (String) -> Unit) {
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 7 (Fadlan Rivaldi 202310715280,Indris Alpasela 202310715200, Haga Dalpinto Ginting 202310715176" // Pesan yang akan tampil
"text/plain".toMediaType(),
report
)
val request = Request.Builder()
.url(url)
.addHeader("Title", "Alert")
.addHeader("Priority", "urgent")
.addHeader("Tags", "alert warning,rotating_light")
.addHeader("Tags", tags) // Gunakan tags dinamis dari parameter
.post(requestBody)
.build()
// Eksekusi request di thread terpisah
Thread {
try {
val response = client.newCall(request).execute()

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -1,3 +1,4 @@
<resources>
<string name="app_name">Panic Button</string>
<string name="send_alert">Kirim Alert</string>
</resources>