Feat(UI): Style panic button
This commit is contained in:
parent
9d34345d24
commit
ba36f0447b
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user