Compare commits

...

10 Commits

Author SHA1 Message Date
edf5531a54 button jalur evakuasi 2025-11-27 21:00:39 +07:00
HagaDalpintoGinting
f88e15d646 final Praktikum 2 2025-11-20 15:15:55 +07:00
HagaDalpintoGinting
5b8e28d6ee praktikum 2 2025-11-20 14:56:49 +07:00
HagaDalpintoGinting
ee739fd565 update 2025-11-13 15:53:05 +07:00
HagaDalpintoGinting
cebaf14306 Menyelesaikan merge conflict 2025-11-13 15:46:19 +07:00
HagaDalpintoGinting
179b2cf0ce update massage allert 2025-11-13 15:44:22 +07:00
HagaDalpintoGinting
55b7a311cc Praktek 1 2025-11-13 15:29:38 +07:00
HagaDalpintoGinting
024a147fbd first commit 2025-11-13 15:25:04 +07:00
HagaDalpintoGinting
82212b9cc7 praktik 1 2025-11-13 15:20:57 +07:00
59a5f2b68a first Commit 2025-11-13 15:08:10 +07:00
8 changed files with 276 additions and 35 deletions

View File

@ -9,6 +9,7 @@ Repository ini digunakan untuk praktikum perkuliahan pemrograman mobile.
- Arif Dwiyanto: arif.dwiyanto@ubharajaya.ac.id
## Mahasiswa
<<<<<<< HEAD
- 1. Dendi Yogia Pratama (202310715051)
- 2. Nuryuda Maulana (202310715038)
- 3. Haga Dalpinto Ginting (202310715176)
@ -26,8 +27,16 @@ Repository ini digunakan untuk praktikum perkuliahan pemrograman mobile.
- 15. Indris Alpasela (202310715200)
- 16. Raihan Ariq Muzakki (202310715297)
- 17. Dirson Ali Wardana (202310715246)
<<<<<<< HEAD
- 18. Dimas Hendri Pamungkas (202310715274)
- 19. Fadhlul Wafi (202310715188)
- 20. Muhammad Yusron Amrullah (202310715060)
- 21. Muhammad Fadillah (202310715213)
- 21. Hadi Guna Prakoso (202310715312)
- 21. Hadi Guna Prakoso (202310715312)
=======
=======
- Fadlan Rivaldi (202310715280)
- B
- C
>>>>>>> d4f073d (First Commit)
>>>>>>> 59a5f2b68a9a33028bb744220857c043749c6949

View File

@ -57,6 +57,9 @@ dependencies {
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation(libs.androidx.compose.ui.test.manifest)
implementation("com.squareup.okhttp3:okhttp:4.11.0")
implementation("androidx.compose.material3:material3:1.1.1")
//praktikum 1
implementation("com.squareup.okhttp3:okhttp:4.11.0")
implementation("androidx.compose.material3:material3:1.1.1")

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>
</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,18 +1,30 @@
package id.ac.ubharajaya.panicbutton
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
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.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import id.ac.ubharajaya.panicbutton.ui.theme.PanicButtonTheme
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
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
@ -21,32 +33,184 @@ import okhttp3.RequestBody
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
PanicButtonTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
MyApp()
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
fun MyApp() {
val context = LocalContext.current
var message by remember { mutableStateOf("Kirim laporan untuk mendapatkan notifikasi") }
var selectedConditions by remember { mutableStateOf(mutableSetOf<String>()) }
var additionalNotes by remember { mutableStateOf(TextFieldValue("")) }
// Map untuk mencocokkan teks UI dengan tag untuk API
val conditionToTagMap = mapOf(
"🔥 Kebakaran" to "fire",
"⛈️ Banjir" to "cloud_with_rain",
"🌊 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"
)
// Daftar kondisi untuk ditampilkan di UI
val conditions = conditionToTagMap.keys.toList()
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.verticalScroll(scrollState), // Membuat Column bisa di-scroll
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.Start
) {
// --- Bagian Judul ---
Text(
text = "Terjadi Kondisi Darurat",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
color = Color.Red,
modifier = Modifier.padding(bottom = 16.dp)
)
// --- Bagian Daftar Checkbox ---
// Perulangan ini HANYA untuk membuat baris Checkbox
conditions.forEach { condition ->
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable {
// Logika untuk menambah/menghapus dari set
val newSet = selectedConditions.toMutableSet()
if (newSet.contains(condition)) {
newSet.remove(condition)
} else {
newSet.add(condition)
}
selectedConditions = newSet
}
.padding(vertical = 4.dp)
) {
Checkbox(
checked = selectedConditions.contains(condition),
onCheckedChange = { isChecked ->
val newSet = selectedConditions.toMutableSet()
if (isChecked) {
newSet.add(condition)
} else {
newSet.remove(condition)
}
selectedConditions = newSet
}
)
Text(text = condition, modifier = Modifier.padding(start = 8.dp))
}
}
// --- Bagian Catatan Tambahan ---
Spacer(modifier = Modifier.height(16.dp))
Text(text = "Catatan tambahan:")
BasicTextField(
value = additionalNotes,
onValueChange = { additionalNotes = it },
modifier = Modifier
.fillMaxWidth()
.height(100.dp)
.padding(vertical = 8.dp)
.border(1.dp, Color.Gray),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done)
)
// --- Bagian Tombol Kirim Laporan ---
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = {
val notes = additionalNotes.text
// Ambil tag yang sesuai dari map, bukan teks dari UI
val tags = selectedConditions.mapNotNull { conditionToTagMap[it] }.joinToString(",")
val report = "Kondisi: ${selectedConditions.joinToString(", ")}\nCatatan: $notes"
// Panggilan ini sekarang berada di scope yang benar
sendNotification(report, tags) { response ->
message = response
}
},
colors = ButtonDefaults.buttonColors(containerColor = Color.Red),
modifier = Modifier.fillMaxWidth()
) {
Text(text = "Kirim Laporan", color = Color.White)
}
// --- Bagian Keterangan Evakuasi ---
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,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
// --- Bagian Hasil Request ---
Spacer(modifier = Modifier.height(16.dp))
Text(text = message, modifier = Modifier.padding(top = 16.dp))
// Spacer untuk mendorong tombol bawah ke dasar layar
Spacer(modifier = Modifier.weight(1f))
// --- Bagian Tombol Bawah ---
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Button(onClick = {
context.startActivity(Intent(context, JalurEvakuasiActivity::class.java))
}) {
Text(text = "Lihat Jalur Evakuasi")
}
Button(
onClick = { (context as? Activity)?.finish() },
colors = ButtonDefaults.buttonColors(containerColor = Color.Gray)
) {
Text(text = "Tutup", color = Color.White)
}
}
}
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
PanicButtonTheme {
Greeting("Android")
}
}
// Fungsi sendNotification (tidak perlu diubah)
fun sendNotification(report: String, tags: String, onResult: (String) -> Unit) {
// ... implementasi sudah benar
val client = OkHttpClient()
val url = "https://ntfy.ubharajaya.ac.id/panic-button"
val requestBody = RequestBody.create("text/plain".toMediaType(), report)
val request = Request.Builder()
.url(url)
.addHeader("Title", "Alert")
.addHeader("Priority", "urgent")
.addHeader("Tags", tags)
.post(requestBody)
.build()
Thread {
try {
val response = client.newCall(request).execute()
if (response.isSuccessful) {
onResult("Notifikasi berhasil dikirim!")
} else {
onResult("Gagal mengirim notifikasi: ${response.code}")
}
} catch (e: Exception) {
onResult("Error: ${e.message}")
}
}.start()
}

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>
</resources>
<string name="send_alert">Kirim Alert</string>
</resources>