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 ec5244b..12835ec 100644 --- a/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt +++ b/app/src/main/java/id/ac/ubharajaya/panicbutton/MainActivity.kt @@ -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(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 {