diff --git a/.idea/copilot.data.migration.agent.xml b/.idea/copilot.data.migration.agent.xml
index 6a251c8..57556ac 100644
--- a/.idea/copilot.data.migration.agent.xml
+++ b/.idea/copilot.data.migration.agent.xml
@@ -10,9 +10,11 @@
+
+
@@ -22,11 +24,14 @@
+
+
+
@@ -36,12 +41,14 @@
+
+
@@ -57,6 +64,9 @@
+
+
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 6e1b3d2..88cd9da 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -50,6 +50,8 @@ dependencies {
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3)
+ // Foundation (for verticalScroll, rememberScrollState, etc.)
+ implementation("androidx.compose.foundation:foundation:1.5.0")
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2e0d78f..5094eae 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -22,6 +22,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/id/ac/ubharajaya/panicbutton/EvacuationMapDetailActivity.kt b/app/src/main/java/id/ac/ubharajaya/panicbutton/EvacuationMapDetailActivity.kt
new file mode 100644
index 0000000..fb77dff
--- /dev/null
+++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/EvacuationMapDetailActivity.kt
@@ -0,0 +1,34 @@
+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.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+
+class EvacuationMapDetailActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val which = intent.getStringExtra("which") ?: "selatan"
+ val resId = if (which == "selatan") R.drawable.lantai_1_selatan else R.drawable.lantai_1_utara
+ setContent {
+ MaterialTheme {
+ EvacuationMapDetailContent(resId)
+ }
+ }
+ }
+}
+
+@Composable
+fun EvacuationMapDetailContent(drawableResId: Int) {
+ Column(modifier = Modifier.fillMaxSize().padding(12.dp)) {
+ Text(text = "Detail Peta", modifier = Modifier.padding(bottom = 12.dp))
+ Image(painter = painterResource(id = drawableResId), contentDescription = "Map Detail", modifier = Modifier.fillMaxWidth().heightIn(max = 800.dp))
+ }
+}
diff --git a/app/src/main/java/id/ac/ubharajaya/panicbutton/EvacuationMapsActivity.kt b/app/src/main/java/id/ac/ubharajaya/panicbutton/EvacuationMapsActivity.kt
new file mode 100644
index 0000000..6ba6bee
--- /dev/null
+++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/EvacuationMapsActivity.kt
@@ -0,0 +1,68 @@
+package id.ac.ubharajaya.panicbutton
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.MaterialTheme
+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
+import androidx.compose.ui.unit.sp
+
+class EvacuationMapsActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ MaterialTheme {
+ EvacuationMapsContent(onSelect = { which ->
+ val intent = Intent(this, EvacuationMapDetailActivity::class.java)
+ intent.putExtra("which", which)
+ startActivity(intent)
+ })
+ }
+ }
+ }
+}
+
+@Composable
+fun EvacuationMapsContent(onSelect: (String) -> Unit) {
+ Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
+ Text(text = "Peta Jalur Evakuasi", style = MaterialTheme.typography.titleLarge, modifier = Modifier.padding(bottom = 12.dp))
+
+ // Selatan
+ Card(modifier = Modifier.fillMaxWidth().padding(bottom = 12.dp).clickable { onSelect("selatan") }, shape = RoundedCornerShape(12.dp), elevation = CardDefaults.cardElevation(defaultElevation = 6.dp)) {
+ Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(12.dp)) {
+ Image(painter = painterResource(id = R.drawable.lantai_1_selatan), contentDescription = "Selatan", modifier = Modifier.size(120.dp))
+ Spacer(modifier = Modifier.width(12.dp))
+ Column {
+ Text(text = "Jalur Evakuasi Selatan", fontSize = 18.sp)
+ Spacer(modifier = Modifier.height(6.dp))
+ Text(text = "Lihat detail jalur evakuasi lantai selatan.")
+ }
+ }
+ }
+
+ // Utara
+ Card(modifier = Modifier.fillMaxWidth().padding(bottom = 12.dp).clickable { onSelect("utara") }, shape = RoundedCornerShape(12.dp), elevation = CardDefaults.cardElevation(defaultElevation = 6.dp)) {
+ Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(12.dp)) {
+ Image(painter = painterResource(id = R.drawable.lantai_1_utara), contentDescription = "Utara", modifier = Modifier.size(120.dp))
+ Spacer(modifier = Modifier.width(12.dp))
+ Column {
+ Text(text = "Jalur Evakuasi Utara", fontSize = 18.sp)
+ Spacer(modifier = Modifier.height(6.dp))
+ Text(text = "Lihat detail jalur evakuasi lantai utara.")
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt
index 8eb8aad..61c2fba 100644
--- a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt
+++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt
@@ -1,51 +1,26 @@
package id.ac.ubharajaya.panicbutton
+import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
-import androidx.activity.viewModels
-import androidx.compose.runtime.Composable
-import androidx.navigation.NavType
-import androidx.navigation.compose.NavHost
-import androidx.navigation.compose.composable
-import androidx.navigation.compose.navArgument
-import androidx.navigation.compose.rememberNavController
-import id.ac.ubharajaya.panicbutton.ui.theme.PanicButtonTheme
+import androidx.lifecycle.ViewModelProvider
+import androidx.compose.material3.MaterialTheme
class MainActivity : ComponentActivity() {
- private val viewModel: MainViewModel by viewModels()
+ private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContent {
- PanicButtonTheme {
- AppNav(viewModel = viewModel)
- }
- }
- }
-}
+ viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
-@Composable
-fun AppNav(viewModel: MainViewModel) {
- val navController = rememberNavController()
- NavHost(navController = navController, startDestination = "main") {
- composable("main") {
- MainScreen(viewModel = viewModel, onOpenEvacMaps = { navController.navigate("evac_maps") })
+ val openEvacMaps = {
+ startActivity(Intent(this, EvacuationMapsActivity::class.java))
}
- composable("evac_maps") {
- EvacuationMapsScreen(navController = navController, onBack = { navController.popBackStack() })
- }
- composable(
- route = "evac_map/{resName}",
- arguments = listOf(navArgument("resName") { type = NavType.StringType })
- ) { backStackEntry ->
- val resName = backStackEntry.arguments?.getString("resName") ?: ""
- val resId = when (resName) {
- "selatan" -> R.drawable.lantai_1_selatan
- "utara" -> R.drawable.lantai_1_utara
- else -> 0
+ setContent {
+ MaterialTheme {
+ MainScreen(viewModel = viewModel, onOpenEvacMaps = openEvacMaps)
}
- EvacuationMapDetailScreen(drawableResId = resId, onBack = { navController.popBackStack() })
}
}
}
diff --git a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainScreen.kt b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainScreen.kt
index 3702785..13422c9 100644
--- a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainScreen.kt
+++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainScreen.kt
@@ -1,37 +1,37 @@
package id.ac.ubharajaya.panicbutton
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Warning
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.KeyboardArrowUp
-import androidx.compose.material.icons.filled.Warning
-import androidx.compose.material.icons.filled.Check
-import androidx.compose.material.icons.filled.Close
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
-import androidx.compose.ui.draw.shadow
-import androidx.compose.ui.graphics.Brush
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import androidx.compose.ui.layout.IntrinsicSize
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.ui.draw.shadow
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.foundation.layout.IntrinsicSize
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(viewModel: MainViewModel, onOpenEvacMaps: () -> Unit) {
-
Scaffold(
modifier = Modifier.fillMaxSize(),
bottomBar = {
- // wrap PanicButton in a Box so we can center it over the bottom bar
Box(
modifier = Modifier
.fillMaxWidth()
@@ -41,73 +41,65 @@ fun MainScreen(viewModel: MainViewModel, onOpenEvacMaps: () -> Unit) {
PanicButton(onClick = { viewModel.sendAlert() }, buttonSize = 130.dp, shadowSize = 160.dp)
}
}
- ) { paddingValues ->
-
+ ) { padding ->
Column(
modifier = Modifier
.fillMaxSize()
- .padding(paddingValues)
+ .padding(padding)
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
-
- // Emergency instruction text (darurat)
+ // Emergency instruction
Text(
- text = "JANGAN PANIK, SEGERA EVAKUASI DIRI ANDA KE TITIK KUMPUL",
+ text = "JANGAN PANIK, SEGERA EVAKUASI DIRI ANDA KE TITIK KUMPUL!!",
color = MaterialTheme.colorScheme.error,
- style = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.Bold),
+ style = MaterialTheme.typography.bodyLarge.copy(
+ fontWeight = FontWeight.Bold
+ ),
+ textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
- .padding(bottom = 12.dp),
+ .padding(bottom = 12.dp)
+ .background(
+ MaterialTheme.colorScheme.error.copy(alpha = 0.2f),
+ shape = RoundedCornerShape(8.dp)
+ )
+ .border(
+ width = 1.dp,
+ color = MaterialTheme.colorScheme.error,
+ shape = RoundedCornerShape(8.dp)
+ )
+ .padding(12.dp),
maxLines = 2,
)
- // Styled Emergency Condition Card
EmergencyConditionCard(viewModel)
- Spacer(Modifier.height(12.dp))
+ Spacer(modifier = Modifier.height(12.dp))
- // Button to open evacuation maps
Button(
onClick = onOpenEvacMaps,
modifier = Modifier
.fillMaxWidth(0.6f)
.height(48.dp),
- shape = RoundedCornerShape(12.dp),
- colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary)
+ shape = RoundedCornerShape(12.dp)
) {
- Text(text = "Lihat Peta Evakuasi", color = MaterialTheme.colorScheme.onPrimary)
+ Text(text = "Lihat Peta Evakuasi")
}
- // Tambahkan spacer di luar Card agar ada jarak dari bottom bar
- Spacer(Modifier.height(20.dp))
+ Spacer(modifier = Modifier.height(20.dp))
}
- // Dialog Feedback
+ // Dialog
val dialogMessage = viewModel.dialogMessage
if (!dialogMessage.isNullOrBlank()) {
AlertDialog(
onDismissRequest = { viewModel.clearDialog() },
confirmButton = {
- TextButton(onClick = { viewModel.clearDialog() }) {
- Text("OK")
- }
+ TextButton(onClick = { viewModel.clearDialog() }) { Text("OK") }
},
- title = {
- Text(
- "Notifikasi",
- style = MaterialTheme.typography.titleMedium.copy(
- fontWeight = FontWeight.Bold
- )
- )
- },
- text = {
- Text(
- dialogMessage,
- style = MaterialTheme.typography.bodyMedium
- )
- },
- containerColor = MaterialTheme.colorScheme.surface
+ title = { Text("🚨 Notifikasi", style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold)) },
+ text = { Text(dialogMessage ?: "") }
)
}
}
@@ -231,8 +223,8 @@ fun EmergencyConditionCard(viewModel: MainViewModel) {
)
// Show first 2 selected items as chips
- selectedItems.take(2).forEach { option ->
- SelectedChip(option = option, viewModel = viewModel)
+ selectedItems.take(2).forEach { opt ->
+ SelectedChip(option = opt, viewModel = viewModel)
}
if (selectedItems.size > 2) {
@@ -250,7 +242,7 @@ fun EmergencyConditionCard(viewModel: MainViewModel) {
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier
- .width(IntrinsicSize.Max)
+ .fillMaxWidth()
.background(
color = MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(16.dp)
@@ -263,12 +255,12 @@ fun EmergencyConditionCard(viewModel: MainViewModel) {
.heightIn(max = 280.dp)
.verticalScroll(rememberScrollState())
) {
- viewModel.options.forEach { option ->
+ viewModel.options.forEach { opt ->
EmergencyOptionItem(
- option = option,
- isChecked = viewModel.isChecked(option.label),
+ option = opt,
+ isChecked = viewModel.isChecked(opt.label),
onCheckedChange = { checked ->
- viewModel.setChecked(option.label, checked)
+ viewModel.setChecked(opt.label, checked)
}
)
}