Mengubah Tag sesuai Kiriman User dan Menambahkan Activity baru untuk Jalur Evakuasi

This commit is contained in:
202310715297 RAIHAN ARIQ MUZAKKI 2025-11-20 15:38:38 +07:00
parent e855ff870c
commit 48d1205ba8
5 changed files with 215 additions and 25 deletions

View File

@ -50,6 +50,7 @@ dependencies {
implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3) implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.foundation)
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)

View File

@ -17,16 +17,19 @@
android:theme="@style/Theme.PanicButton"> android:theme="@style/Theme.PanicButton">
<activity <activity
android:name="com.example.panicbutton.MainActivity" android:name="id.ac.ubharajaya.panicbutton.MainActivity"
android:exported="true" android:exported="true"
android:label="@string/app_name" android:label="@string/app_name"
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" />
</application> </application>
</manifest> </manifest>

View File

@ -0,0 +1,62 @@
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.material3.ButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
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
) {
Text(
text = "Jalur Evakuasi",
fontSize = 20.sp,
)
Spacer(modifier = Modifier.height(16.dp))
// Menampilkan gambar denah
Image(
painter = painterResource(id = R.drawable.jalur_evakuasi),
contentDescription = "Denah Jalur Evakuasi",
modifier = Modifier
.fillMaxWidth()
.height(450.dp)
)
Spacer(modifier = Modifier.height(20.dp))
// Tombol Close
Button(
onClick = { onClose() },
colors = ButtonDefaults.buttonColors(containerColor = Color.Red)
) {
Text(text = "Close", color = Color.White)
}
}
}

View File

@ -1,18 +1,33 @@
package com.example.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.material3.Button import androidx.compose.foundation.rememberScrollState
import androidx.compose.material3.Text import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
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.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
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 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
import java.util.concurrent.locks.Condition
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@ -27,55 +42,162 @@ 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") } var message by remember { mutableStateOf("Klik tombol untuk mengirim notifikasi") }
var selectedConditions by remember { mutableStateOf(mutableSetOf<String>()) }
var additionalNotes by remember { mutableStateOf(TextFieldValue("")) }
// Agar bisa Scroll
val scrollState = rememberScrollState()
val context = LocalContext.current
// UI
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.verticalScroll(scrollState)
.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)) Text(
Button(onClick = { text = "Terjadi Kondisi Darurat",
// Kirim HTTP request saat tombol ditekan fontSize = 20.sp,
sendNotification { response -> color = Color.Red,
message = response modifier = Modifier.padding(bottom = 16.dp)
)
listOf(
"Kebakaran", "Banjir", "Tsunami", "Gunung Meletus",
"Gempa Bumi", "Huru hara", "Binatang Buas",
"Radiasi Nuklir", "Biohazard"
).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)
)
} }
}) { }
Text(text = "Kirim Alert")
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)
)
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = {
val notes = additionalNotes.text
val conditions = selectedConditions.joinToString(", ")
val report = "Kondisi: $conditions\nCatatan: $notes"
sendNotification(conditions, report) { response ->
message = response
}
},
colors = ButtonDefaults.buttonColors(containerColor = Color.Red)
) {
Text(text = "Kirim Laporan", 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(16.dp))
Text(text = message, Modifier.padding(top = 16.dp))
Button(
onClick = {
val intent = Intent(context, JalurEvakuasiActivity::class.java)
context.startActivity(intent)
},
colors = ButtonDefaults.buttonColors(containerColor = Color.Green)
) {
Text(text = "Lihat Jalur Evakuasi", color = Color.White)
} }
} }
} }
// Fungsi untuk mengirimkan HTTP request // Fungsi untuk mengirimkan HTTP request
fun sendNotification(onResult: (String) -> Unit) { fun sendNotification(condition: String, 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"
// Mapping kondisi → emoji/tag
val requestBody = RequestBody.create( val tagMapping = mapOf(
"text/plain".toMediaType(), // Mengirim plain text "Kebakaran" to "fire",
"Notifikasi dari Kelompok 1 (Raihan, Dendi, Fazri)!" // Pesan yang akan tampil "Banjir" to "ocean",
"Tsunami" to "ocean",
"Gunung Meletus" to "volcano",
"Gempa Bumi" to "earth_asia",
"Huru hara" to "imp",
"Binatang Buas" to "snake",
"Radiasi Nuklir" to "radioactive",
"Biohazard" to "biohazard"
) )
// Bersihkan kondisi: trim + filter
val selectedList = condition
.split(",")
.map { it.trim() }
.filter { it.isNotEmpty() }
// Format ulang kondisi
val cleanConditionText = selectedList.joinToString(", ")
// Ambil emoji untuk masing-masing kondisi
val emojiTags = selectedList.mapNotNull { tagMapping[it] }
// Tambahkan default tag: alert + warning
val finalTags = listOf("Alert", "Warning") + emojiTags
val finalReport = "Kondisi: $cleanConditionText\nCatatan: ${report.substringAfter("Catatan:")}"
val requestBody = RequestBody.create(
"text/plain".toMediaType(),
finalReport
)
val request = Request.Builder() val request = Request.Builder()
.url(url) .url(url)
.addHeader("Title", "Radioactive") .addHeader("Title", "Alert")
.addHeader("Priority", "urgent") .addHeader("Priority", "urgent")
.addHeader("Tags", "alert warning,rotating_light") .addHeader("Tags", finalTags.joinToString(","))
.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()

View File

@ -8,6 +8,7 @@ espressoCore = "3.7.0"
lifecycleRuntimeKtx = "2.9.4" lifecycleRuntimeKtx = "2.9.4"
activityCompose = "1.11.0" activityCompose = "1.11.0"
composeBom = "2024.09.00" composeBom = "2024.09.00"
foundation = "1.9.4"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@ -24,6 +25,7 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u
androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "foundation" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }