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"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application <application
android:allowBackup="true" android:allowBackup="true"
@ -10,7 +11,9 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.PanicButton"> android:theme="@style/Theme.PanicButton"
tools:targetApi="31">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
@ -18,10 +21,17 @@
android:theme="@style/Theme.PanicButton"> android:theme="@style/Theme.PanicButton">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<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"
android:label="Jalur Evakuasi"
android:theme="@style/Theme.PanicButton" />
</application> </application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest> </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 package id.ac.ubharajaya.panicbutton
import android.app.Activity
import android.content.Intent // <-- TAMBAHKAN IMPORT INI
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.material3.Button import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material3.Text import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
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.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.dp
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
import okhttp3.RequestBody import okhttp3.RequestBody
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -27,56 +42,175 @@ class MainActivity : ComponentActivity() {
@Composable @Composable
fun MyApp() { fun MyApp() {
// State untuk menampilkan hasil request val focusManager = LocalFocusManager.current
var message by remember { mutableStateOf("Klik tombol untuk mengirim notifikasi") } 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( 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)) // PERMINTAAN 1: Judul diperbesar dan dibuat bold
Button(onClick = { Text(
// Kirim HTTP request saat tombol ditekan text = "Terjadi Kondisi Darurat",
sendNotification { response -> fontSize = 24.sp, // Ukuran font diperbesar
message = response 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 // PERMINTAAN 2: Ubah fungsi `sendNotification` untuk menerima parameter tags
fun sendNotification(onResult: (String) -> Unit) { fun sendNotification(report: String, tags: 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( val requestBody = RequestBody.create(
"text/plain".toMediaType(), // Mengirim plain text "text/plain".toMediaType(),
"Notifikasi dari Kelompok 7 (Fadlan Rivaldi 202310715280,Indris Alpasela 202310715200, Haga Dalpinto Ginting 202310715176" // Pesan yang akan tampil 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") .addHeader("Tags", tags) // Gunakan tags dinamis dari parameter
.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: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

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