Feat(UI): Style panic button

This commit is contained in:
Rakha adi 2025-11-19 20:46:01 +07:00
parent 9d34345d24
commit ba36f0447b

View File

@ -3,17 +3,32 @@ package id.ac.ubharajaya.panicbutton
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.foundation.shape.CircleShape
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.draw.scale
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@ -27,9 +42,8 @@ class MainActivity : ComponentActivity() {
@Composable
fun MyApp() {
// State untuk menampilkan hasil request
var message by remember { mutableStateOf("Klik tombol untuk mengirim notifikasi") }
// dialogMessage akan menampung hasil callback dari sendNotification; null = tidak tampil
var dialogMessage by remember { mutableStateOf<String?>(null) }
// UI
Column(
@ -39,14 +53,174 @@ fun MyApp() {
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = message, Modifier.padding(bottom = 16.dp))
Button(onClick = {
// tombol panic
PanicButton(onClick = {
// Kirim HTTP request saat tombol ditekan
sendNotification { response ->
message = response
// tampilkan dialog ketika ada respon
dialogMessage = response
}
}) {
Text(text = "Kirim Alert")
})
}
// Custom Dialog untuk menampilkan status kirim notifikasi — styled sesuai tema panic
if (dialogMessage != null) {
Dialog(onDismissRequest = { dialogMessage = null }) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
contentAlignment = Alignment.Center
) {
Surface(
shape = RoundedCornerShape(12.dp),
color = Color.White,
tonalElevation = 8.dp,
modifier = Modifier.wrapContentWidth()
) {
Column(
modifier = Modifier
.padding(0.dp)
.widthIn(min = 280.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
// header
Box(
modifier = Modifier
.fillMaxWidth()
.background(color = Color(0xFFB71C1C))
.padding(vertical = 12.dp),
contentAlignment = Alignment.Center
) {
Text(
text = "Notifikasi",
color = Color.White,
fontWeight = FontWeight.Bold,
fontSize = 18.sp
)
}
Spacer(modifier = Modifier.height(12.dp))
// message
Text(
text = dialogMessage ?: "",
color = Color.Black,
modifier = Modifier.padding(horizontal = 16.dp)
)
Spacer(modifier = Modifier.height(20.dp))
// action
Box(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp),
contentAlignment = Alignment.Center
) {
Button(
onClick = { dialogMessage = null },
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFB71C1C))
) {
Text(text = "OK", color = Color.White)
}
}
}
}
}
}
}
}
// New: 3D-styled PanicButton with press animation and glossy highlight
@Composable
fun PanicButton(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
// theme colors
val panicColor = Color(0xFFB71C1C)
val darkShade = Color(0xFF7F0F0F)
val lightAccent = Color(0xFFFF8A80)
// interaction for press-state
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
// animations: scale down and lower elevation when pressed
val scaleAnim by animateFloatAsState(targetValue = if (isPressed) 0.96f else 1f, animationSpec = tween(120))
val elevationAnim by animateDpAsState(targetValue = if (isPressed) 6.dp else 18.dp, animationSpec = tween(120))
// vertical gradient to simulate 3D lighting
val gradient = Brush.verticalGradient(listOf(lightAccent, panicColor, darkShade))
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = modifier
) {
Box(contentAlignment = Alignment.Center) {
// soft outer shadow (ground shadow)
Box(
modifier = Modifier
.size(210.dp)
.shadow(elevation = elevationAnim, shape = CircleShape)
.background(color = Color.Black.copy(alpha = 0.12f), shape = CircleShape)
)
// main 3D button
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(170.dp)
.scale(scaleAnim)
.shadow(elevation = elevationAnim, shape = CircleShape)
.background(brush = gradient, shape = CircleShape)
.clickable(indication = null, interactionSource = interactionSource) {
onClick()
}
) {
// glossy highlight (small white circle offset to top-left)
Box(
modifier = Modifier
.size(70.dp)
.offset(x = (-24).dp, y = (-28).dp)
.background(color = Color.White.copy(alpha = 0.16f), shape = CircleShape)
)
// central exclamation icon
Text(
text = "!",
color = Color.White,
fontSize = 72.sp,
fontWeight = FontWeight.ExtraBold
)
// subtle inner rim to enhance 3D edge
Box(
modifier = Modifier
.matchParentSize()
.padding(6.dp)
.background(color = Color.Transparent, shape = CircleShape)
)
}
}
Spacer(modifier = Modifier.height(14.dp))
// label with 3D-like chip
Surface(
color = panicColor.copy(alpha = 0.10f),
shape = RoundedCornerShape(20.dp),
tonalElevation = 0.dp
) {
Text(
text = "PANIC",
color = panicColor,
modifier = Modifier
.padding(horizontal = 20.dp, vertical = 8.dp)
)
}
}
}
@ -59,10 +233,8 @@ fun sendNotification(onResult: (String) -> Unit) {
val requestBody = RequestBody.create(
"text/plain".toMediaType(), // Mengirim plain text
"Notifikasi dari Satrio Putra Wardani 202310715307" // Pesan yang akan tampil
val requestBody = "Notifikasi dari Satrio Putra Wardani 202310715307".toRequestBody(
"text/plain".toMediaType()
)
@ -76,6 +248,7 @@ fun sendNotification(onResult: (String) -> Unit) {
// Eksekusi request di thread terpisah
Thread {
try {