Menyesuaikan Desain NoteDialog.kt dan CategoryDialog.kt

This commit is contained in:
202310715082 FAZRI ABDURRAHMAN 2025-12-17 21:47:56 +07:00
parent 900bf8b7ff
commit 8c3994e317
2 changed files with 282 additions and 163 deletions

View File

@ -1,33 +1,16 @@
// File: presentation/dialogs/CategoryDialog.kt
package com.example.notesai.presentation.dialogs package com.example.notesai.presentation.dialogs
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.AlertDialog import androidx.compose.material3.*
import androidx.compose.material3.Button import androidx.compose.runtime.*
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -35,6 +18,8 @@ import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.notesai.util.Constants
@Composable @Composable
fun CategoryDialog( fun CategoryDialog(
@ -44,91 +29,128 @@ fun CategoryDialog(
var name by remember { mutableStateOf("") } var name by remember { mutableStateOf("") }
var selectedGradient by remember { mutableStateOf(0) } var selectedGradient by remember { mutableStateOf(0) }
val gradients = listOf(
Pair(0xFF6366F1L, 0xFFA855F7L),
Pair(0xFFEC4899L, 0xFFF59E0BL),
Pair(0xFF8B5CF6L, 0xFFEC4899L),
Pair(0xFF06B6D4L, 0xFF3B82F6L),
Pair(0xFF10B981L, 0xFF059669L),
Pair(0xFFF59E0BL, 0xFFEF4444L),
Pair(0xFF6366F1L, 0xFF8B5CF6L),
Pair(0xFFEF4444L, 0xFFDC2626L)
)
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
containerColor = Color(0xFF1E293B), containerColor = Constants.AppColors.Surface,
shape = RoundedCornerShape(20.dp),
title = { title = {
Text( Text(
"Buat Kategori Baru", "Buat Kategori Baru",
color = Color.White, color = Constants.AppColors.OnBackground,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold,
fontSize = 20.sp
) )
}, },
text = { text = {
Column { Column(
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
// Input Nama
OutlinedTextField( OutlinedTextField(
value = name, value = name,
onValueChange = { name = it }, onValueChange = { name = it },
label = { Text("Nama Kategori", color = Color(0xFF94A3B8)) }, label = {
Text(
"Nama Kategori",
color = Constants.AppColors.OnSurfaceVariant
)
},
placeholder = {
Text(
"Contoh: Pekerjaan, Personal",
color = Constants.AppColors.OnSurfaceTertiary,
fontSize = 14.sp
)
},
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = TextFieldDefaults.colors( colors = OutlinedTextFieldDefaults.colors(
focusedTextColor = Color.White, focusedTextColor = Constants.AppColors.OnBackground,
unfocusedTextColor = Color.White, unfocusedTextColor = Constants.AppColors.OnSurface,
focusedContainerColor = Color(0xFF334155), focusedContainerColor = Constants.AppColors.SurfaceVariant,
unfocusedContainerColor = Color(0xFF334155), unfocusedContainerColor = Constants.AppColors.SurfaceVariant,
cursorColor = Color(0xFFA855F7), cursorColor = Constants.AppColors.Primary,
focusedIndicatorColor = Color(0xFFA855F7), focusedBorderColor = Constants.AppColors.Primary,
unfocusedIndicatorColor = Color(0xFF64748B) unfocusedBorderColor = Color.Transparent
), ),
shape = RoundedCornerShape(12.dp) shape = RoundedCornerShape(12.dp),
singleLine = true
) )
Spacer(modifier = Modifier.height(20.dp)) // Gradient Selector
Text( Column(
"Pilih Gradient:", verticalArrangement = Arrangement.spacedBy(12.dp)
style = MaterialTheme.typography.bodyMedium, ) {
color = Color.White, Text(
fontWeight = FontWeight.SemiBold "Pilih Warna:",
) style = MaterialTheme.typography.bodyMedium,
color = Constants.AppColors.OnSurface,
fontWeight = FontWeight.SemiBold,
fontSize = 14.sp
)
Spacer(modifier = Modifier.height(12.dp)) Constants.AppColors.CategoryColors.chunked(4).forEach { row ->
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
row.forEach { gradient ->
val globalIndex = Constants.AppColors.CategoryColors.indexOf(gradient)
val isSelected = selectedGradient == globalIndex
gradients.chunked(4).forEach { row -> // Scale animation
Row( val scale by animateFloatAsState(
modifier = Modifier.fillMaxWidth(), targetValue = if (isSelected) 1.1f else 1f,
horizontalArrangement = Arrangement.spacedBy(8.dp) animationSpec = spring(
) { dampingRatio = Spring.DampingRatioMediumBouncy,
row.forEachIndexed { index, gradient -> stiffness = Spring.StiffnessMedium
val globalIndex = gradients.indexOf(gradient) ),
Box( label = "scale"
modifier = Modifier )
.weight(1f)
.aspectRatio(1f) Box(
.clip(RoundedCornerShape(12.dp)) modifier = Modifier
.background( .weight(1f)
brush = Brush.linearGradient( .aspectRatio(1f)
colors = listOf( .clip(RoundedCornerShape(12.dp))
Color(gradient.first), .background(
Color(gradient.second) brush = Brush.linearGradient(
colors = listOf(
Color(gradient.first),
Color(gradient.second)
)
) )
) )
) .clickable { selectedGradient = globalIndex }
.clickable { selectedGradient = globalIndex }, .then(
contentAlignment = Alignment.Center if (isSelected) Modifier
) { else Modifier
if (selectedGradient == globalIndex) { ),
Icon( contentAlignment = Alignment.Center
Icons.Default.Check, ) {
contentDescription = null, // Check icon dengan animation
tint = Color.White, this@Row.AnimatedVisibility(
modifier = Modifier.size(24.dp) visible = isSelected,
) enter = scaleIn() + fadeIn(),
exit = scaleOut() + fadeOut()
) {
Surface(
color = Color.White.copy(alpha = 0.9f),
shape = RoundedCornerShape(8.dp)
) {
Icon(
Icons.Default.Check,
contentDescription = null,
tint = Color(gradient.first),
modifier = Modifier
.padding(6.dp)
.size(20.dp)
)
}
}
} }
} }
} }
} }
Spacer(modifier = Modifier.height(8.dp))
} }
} }
}, },
@ -136,27 +158,37 @@ fun CategoryDialog(
Button( Button(
onClick = { onClick = {
if (name.isNotBlank()) { if (name.isNotBlank()) {
val gradient = gradients[selectedGradient] val gradient = Constants.AppColors.CategoryColors[selectedGradient]
onSave(name, gradient.first, gradient.second) onSave(name, gradient.first, gradient.second)
} }
}, },
enabled = name.isNotBlank(), enabled = name.isNotBlank(),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = Color.Transparent containerColor = Constants.AppColors.Primary,
disabledContainerColor = Constants.AppColors.Primary.copy(alpha = 0.5f)
), ),
modifier = Modifier.background( shape = RoundedCornerShape(12.dp),
brush = Brush.linearGradient( modifier = Modifier.height(48.dp)
colors = listOf(Color(0xFF6366F1), Color(0xFFA855F7))
),
shape = RoundedCornerShape(8.dp)
)
) { ) {
Text("Simpan", color = Color.White, fontWeight = FontWeight.Bold) Text(
"Simpan",
color = Color.White,
fontWeight = FontWeight.Bold,
fontSize = 15.sp
)
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = onDismiss) { TextButton(
Text("Batal", color = Color(0xFF94A3B8)) onClick = onDismiss,
shape = RoundedCornerShape(12.dp),
modifier = Modifier.height(48.dp)
) {
Text(
"Batal",
color = Constants.AppColors.OnSurfaceVariant,
fontSize = 15.sp
)
} }
} }
) )

View File

@ -1,31 +1,18 @@
package com.example.notesai.presentation.dialogs package com.example.notesai.presentation.dialogs
import androidx.compose.foundation.background import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog import androidx.compose.material.icons.Icons
import androidx.compose.material3.Button import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.*
import androidx.compose.material3.OutlinedTextField import androidx.compose.runtime.*
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.notesai.data.model.Note import com.example.notesai.data.model.Note
import com.example.notesai.util.Constants
@Composable @Composable
fun NoteDialog( fun NoteDialog(
@ -36,89 +23,189 @@ fun NoteDialog(
) { ) {
var title by remember { mutableStateOf(note?.title ?: "") } var title by remember { mutableStateOf(note?.title ?: "") }
var description by remember { mutableStateOf(note?.description ?: "") } var description by remember { mutableStateOf(note?.description ?: "") }
var showDeleteConfirm by remember { mutableStateOf(false) }
// Delete confirmation dialog
if (showDeleteConfirm) {
AlertDialog(
onDismissRequest = { showDeleteConfirm = false },
containerColor = Constants.AppColors.Surface,
shape = RoundedCornerShape(20.dp),
title = {
Text(
"Hapus Catatan?",
color = Constants.AppColors.OnBackground,
fontWeight = FontWeight.Bold
)
},
text = {
Text(
"Catatan ini akan dipindahkan ke sampah.",
color = Constants.AppColors.OnSurfaceVariant
)
},
confirmButton = {
Button(
onClick = {
onDelete?.invoke()
showDeleteConfirm = false
},
colors = ButtonDefaults.buttonColors(
containerColor = Constants.AppColors.Error
),
shape = RoundedCornerShape(12.dp)
) {
Text("Hapus", color = Color.White, fontWeight = FontWeight.Bold)
}
},
dismissButton = {
TextButton(
onClick = { showDeleteConfirm = false },
shape = RoundedCornerShape(12.dp)
) {
Text("Batal", color = Constants.AppColors.OnSurfaceVariant)
}
}
)
}
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
containerColor = Color(0xFF1E293B), containerColor = Constants.AppColors.Surface,
shape = RoundedCornerShape(20.dp),
title = { title = {
Text( Text(
if (note == null) "Catatan Baru" else "Edit Catatan", if (note == null) "Catatan Baru" else "Edit Catatan",
color = Color.White, color = Constants.AppColors.OnBackground,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold,
fontSize = 20.sp
) )
}, },
text = { text = {
Column { Column(
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
// Title Input
OutlinedTextField( OutlinedTextField(
value = title, value = title,
onValueChange = { title = it }, onValueChange = { title = it },
label = { Text("Judul", color = Color(0xFF94A3B8)) }, label = {
Text(
"Judul",
color = Constants.AppColors.OnSurfaceVariant
)
},
placeholder = {
Text(
"Masukkan judul catatan",
color = Constants.AppColors.OnSurfaceTertiary,
fontSize = 14.sp
)
},
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = TextFieldDefaults.colors( colors = OutlinedTextFieldDefaults.colors(
focusedTextColor = Color.White, focusedTextColor = Constants.AppColors.OnBackground,
unfocusedTextColor = Color.White, unfocusedTextColor = Constants.AppColors.OnSurface,
focusedContainerColor = Color(0xFF334155), focusedContainerColor = Constants.AppColors.SurfaceVariant,
unfocusedContainerColor = Color(0xFF334155), unfocusedContainerColor = Constants.AppColors.SurfaceVariant,
cursorColor = Color(0xFFA855F7), cursorColor = Constants.AppColors.Primary,
focusedIndicatorColor = Color(0xFFA855F7), focusedBorderColor = Constants.AppColors.Primary,
unfocusedIndicatorColor = Color(0xFF64748B) unfocusedBorderColor = Color.Transparent
), ),
shape = RoundedCornerShape(12.dp) shape = RoundedCornerShape(12.dp),
singleLine = true
) )
Spacer(modifier = Modifier.height(12.dp)) // Description Input
OutlinedTextField( OutlinedTextField(
value = description, value = description,
onValueChange = { description = it }, onValueChange = { description = it },
label = { Text("Deskripsi", color = Color(0xFF94A3B8)) }, label = {
placeholder = { Text("Tambahkan deskripsi singkat...", color = Color(0xFF64748B)) }, Text(
"Deskripsi",
color = Constants.AppColors.OnSurfaceVariant
)
},
placeholder = {
Text(
"Tambahkan deskripsi singkat...",
color = Constants.AppColors.OnSurfaceTertiary,
fontSize = 14.sp
)
},
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(120.dp), .heightIn(min = 120.dp, max = 200.dp),
maxLines = 5, colors = OutlinedTextFieldDefaults.colors(
colors = TextFieldDefaults.colors( focusedTextColor = Constants.AppColors.OnBackground,
focusedTextColor = Color.White, unfocusedTextColor = Constants.AppColors.OnSurface,
unfocusedTextColor = Color.White, focusedContainerColor = Constants.AppColors.SurfaceVariant,
focusedContainerColor = Color(0xFF334155), unfocusedContainerColor = Constants.AppColors.SurfaceVariant,
unfocusedContainerColor = Color(0xFF334155), cursorColor = Constants.AppColors.Primary,
cursorColor = Color(0xFFA855F7), focusedBorderColor = Constants.AppColors.Primary,
focusedIndicatorColor = Color(0xFFA855F7), unfocusedBorderColor = Color.Transparent
unfocusedIndicatorColor = Color(0xFF64748B)
), ),
shape = RoundedCornerShape(12.dp) shape = RoundedCornerShape(12.dp),
maxLines = 8
) )
} }
}, },
confirmButton = { confirmButton = {
Row { Row(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
// Delete button (if editing)
if (onDelete != null) { if (onDelete != null) {
TextButton(onClick = onDelete) { IconButton(
Text("Hapus", color = Color(0xFFEF4444), fontWeight = FontWeight.Bold) onClick = { showDeleteConfirm = true },
modifier = Modifier.size(48.dp)
) {
Icon(
Icons.Default.Delete,
contentDescription = "Hapus",
tint = Constants.AppColors.Error
)
} }
Spacer(modifier = Modifier.width(8.dp))
} }
Spacer(modifier = Modifier.weight(1f))
// Cancel button
TextButton(
onClick = onDismiss,
shape = RoundedCornerShape(12.dp),
modifier = Modifier.height(48.dp)
) {
Text(
"Batal",
color = Constants.AppColors.OnSurfaceVariant,
fontSize = 15.sp
)
}
// Save button
Button( Button(
onClick = { if (title.isNotBlank()) onSave(title, description) }, onClick = {
if (title.isNotBlank()) {
onSave(title, description)
}
},
enabled = title.isNotBlank(), enabled = title.isNotBlank(),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = Color.Transparent containerColor = Constants.AppColors.Primary,
disabledContainerColor = Constants.AppColors.Primary.copy(alpha = 0.5f)
), ),
modifier = Modifier.background( shape = RoundedCornerShape(12.dp),
brush = Brush.linearGradient( modifier = Modifier.height(48.dp)
colors = listOf(Color(0xFF6366F1), Color(0xFFA855F7))
),
shape = RoundedCornerShape(8.dp)
)
) { ) {
Text("Simpan", color = Color.White, fontWeight = FontWeight.Bold) Text(
"Simpan",
color = Color.White,
fontWeight = FontWeight.Bold,
fontSize = 15.sp
)
} }
} }
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text("Batal", color = Color(0xFF94A3B8))
}
} }
) )
} }