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
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
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.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
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.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
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.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.notesai.util.Constants
@Composable
fun CategoryDialog(
@ -44,91 +29,128 @@ fun CategoryDialog(
var name by remember { mutableStateOf("") }
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(
onDismissRequest = onDismiss,
containerColor = Color(0xFF1E293B),
containerColor = Constants.AppColors.Surface,
shape = RoundedCornerShape(20.dp),
title = {
Text(
"Buat Kategori Baru",
color = Color.White,
fontWeight = FontWeight.Bold
color = Constants.AppColors.OnBackground,
fontWeight = FontWeight.Bold,
fontSize = 20.sp
)
},
text = {
Column {
Column(
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
// Input Nama
OutlinedTextField(
value = name,
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(),
colors = TextFieldDefaults.colors(
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
focusedContainerColor = Color(0xFF334155),
unfocusedContainerColor = Color(0xFF334155),
cursorColor = Color(0xFFA855F7),
focusedIndicatorColor = Color(0xFFA855F7),
unfocusedIndicatorColor = Color(0xFF64748B)
colors = OutlinedTextFieldDefaults.colors(
focusedTextColor = Constants.AppColors.OnBackground,
unfocusedTextColor = Constants.AppColors.OnSurface,
focusedContainerColor = Constants.AppColors.SurfaceVariant,
unfocusedContainerColor = Constants.AppColors.SurfaceVariant,
cursorColor = Constants.AppColors.Primary,
focusedBorderColor = Constants.AppColors.Primary,
unfocusedBorderColor = Color.Transparent
),
shape = RoundedCornerShape(12.dp)
shape = RoundedCornerShape(12.dp),
singleLine = true
)
Spacer(modifier = Modifier.height(20.dp))
Text(
"Pilih Gradient:",
style = MaterialTheme.typography.bodyMedium,
color = Color.White,
fontWeight = FontWeight.SemiBold
)
// Gradient Selector
Column(
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(
"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 ->
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
row.forEachIndexed { index, gradient ->
val globalIndex = gradients.indexOf(gradient)
Box(
modifier = Modifier
.weight(1f)
.aspectRatio(1f)
.clip(RoundedCornerShape(12.dp))
.background(
brush = Brush.linearGradient(
colors = listOf(
Color(gradient.first),
Color(gradient.second)
// Scale animation
val scale by animateFloatAsState(
targetValue = if (isSelected) 1.1f else 1f,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessMedium
),
label = "scale"
)
Box(
modifier = Modifier
.weight(1f)
.aspectRatio(1f)
.clip(RoundedCornerShape(12.dp))
.background(
brush = Brush.linearGradient(
colors = listOf(
Color(gradient.first),
Color(gradient.second)
)
)
)
)
.clickable { selectedGradient = globalIndex },
contentAlignment = Alignment.Center
) {
if (selectedGradient == globalIndex) {
Icon(
Icons.Default.Check,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(24.dp)
)
.clickable { selectedGradient = globalIndex }
.then(
if (isSelected) Modifier
else Modifier
),
contentAlignment = Alignment.Center
) {
// Check icon dengan animation
this@Row.AnimatedVisibility(
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(
onClick = {
if (name.isNotBlank()) {
val gradient = gradients[selectedGradient]
val gradient = Constants.AppColors.CategoryColors[selectedGradient]
onSave(name, gradient.first, gradient.second)
}
},
enabled = name.isNotBlank(),
colors = ButtonDefaults.buttonColors(
containerColor = Color.Transparent
containerColor = Constants.AppColors.Primary,
disabledContainerColor = Constants.AppColors.Primary.copy(alpha = 0.5f)
),
modifier = Modifier.background(
brush = Brush.linearGradient(
colors = listOf(Color(0xFF6366F1), Color(0xFFA855F7))
),
shape = RoundedCornerShape(8.dp)
)
shape = RoundedCornerShape(12.dp),
modifier = Modifier.height(48.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))
TextButton(
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
import androidx.compose.foundation.background
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.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
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.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
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 com.example.notesai.data.model.Note
import com.example.notesai.util.Constants
@Composable
fun NoteDialog(
@ -36,89 +23,189 @@ fun NoteDialog(
) {
var title by remember { mutableStateOf(note?.title ?: "") }
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(
onDismissRequest = onDismiss,
containerColor = Color(0xFF1E293B),
containerColor = Constants.AppColors.Surface,
shape = RoundedCornerShape(20.dp),
title = {
Text(
if (note == null) "Catatan Baru" else "Edit Catatan",
color = Color.White,
fontWeight = FontWeight.Bold
color = Constants.AppColors.OnBackground,
fontWeight = FontWeight.Bold,
fontSize = 20.sp
)
},
text = {
Column {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
// Title Input
OutlinedTextField(
value = title,
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(),
colors = TextFieldDefaults.colors(
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
focusedContainerColor = Color(0xFF334155),
unfocusedContainerColor = Color(0xFF334155),
cursorColor = Color(0xFFA855F7),
focusedIndicatorColor = Color(0xFFA855F7),
unfocusedIndicatorColor = Color(0xFF64748B)
colors = OutlinedTextFieldDefaults.colors(
focusedTextColor = Constants.AppColors.OnBackground,
unfocusedTextColor = Constants.AppColors.OnSurface,
focusedContainerColor = Constants.AppColors.SurfaceVariant,
unfocusedContainerColor = Constants.AppColors.SurfaceVariant,
cursorColor = Constants.AppColors.Primary,
focusedBorderColor = Constants.AppColors.Primary,
unfocusedBorderColor = Color.Transparent
),
shape = RoundedCornerShape(12.dp)
shape = RoundedCornerShape(12.dp),
singleLine = true
)
Spacer(modifier = Modifier.height(12.dp))
// Description Input
OutlinedTextField(
value = description,
onValueChange = { description = it },
label = { Text("Deskripsi", color = Color(0xFF94A3B8)) },
placeholder = { Text("Tambahkan deskripsi singkat...", color = Color(0xFF64748B)) },
label = {
Text(
"Deskripsi",
color = Constants.AppColors.OnSurfaceVariant
)
},
placeholder = {
Text(
"Tambahkan deskripsi singkat...",
color = Constants.AppColors.OnSurfaceTertiary,
fontSize = 14.sp
)
},
modifier = Modifier
.fillMaxWidth()
.height(120.dp),
maxLines = 5,
colors = TextFieldDefaults.colors(
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
focusedContainerColor = Color(0xFF334155),
unfocusedContainerColor = Color(0xFF334155),
cursorColor = Color(0xFFA855F7),
focusedIndicatorColor = Color(0xFFA855F7),
unfocusedIndicatorColor = Color(0xFF64748B)
.heightIn(min = 120.dp, max = 200.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedTextColor = Constants.AppColors.OnBackground,
unfocusedTextColor = Constants.AppColors.OnSurface,
focusedContainerColor = Constants.AppColors.SurfaceVariant,
unfocusedContainerColor = Constants.AppColors.SurfaceVariant,
cursorColor = Constants.AppColors.Primary,
focusedBorderColor = Constants.AppColors.Primary,
unfocusedBorderColor = Color.Transparent
),
shape = RoundedCornerShape(12.dp)
shape = RoundedCornerShape(12.dp),
maxLines = 8
)
}
},
confirmButton = {
Row {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
// Delete button (if editing)
if (onDelete != null) {
TextButton(onClick = onDelete) {
Text("Hapus", color = Color(0xFFEF4444), fontWeight = FontWeight.Bold)
IconButton(
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(
onClick = { if (title.isNotBlank()) onSave(title, description) },
onClick = {
if (title.isNotBlank()) {
onSave(title, description)
}
},
enabled = title.isNotBlank(),
colors = ButtonDefaults.buttonColors(
containerColor = Color.Transparent
containerColor = Constants.AppColors.Primary,
disabledContainerColor = Constants.AppColors.Primary.copy(alpha = 0.5f)
),
modifier = Modifier.background(
brush = Brush.linearGradient(
colors = listOf(Color(0xFF6366F1), Color(0xFFA855F7))
),
shape = RoundedCornerShape(8.dp)
)
shape = RoundedCornerShape(12.dp),
modifier = Modifier.height(48.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))
}
}
)
}