Menyesuaikan Tampilan Drawer Menu dan Halaman Catatan Berbintang

This commit is contained in:
202310715297 RAIHAN ARIQ MUZAKKI 2025-12-11 15:47:41 +07:00
parent 9c699767e9
commit f2da1792b1

View File

@ -9,6 +9,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@ -50,7 +51,10 @@ import com.google.ai.client.generativeai.type.generationConfig
import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material.icons.outlined.StarBorder
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.zIndex
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
// Data Classes // Data Classes
@ -127,7 +131,7 @@ fun NotesApp() {
var showFullScreenNote by remember { mutableStateOf(false) } var showFullScreenNote by remember { mutableStateOf(false) }
var fullScreenNote by remember { mutableStateOf<Note?>(null) } var fullScreenNote by remember { mutableStateOf<Note?>(null) }
// Load data dari DataStore - dengan error handling // Load data dari DataStore
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
try { try {
dataStoreManager.categoriesFlow.collect { loadedCategories -> dataStoreManager.categoriesFlow.collect { loadedCategories ->
@ -172,268 +176,292 @@ fun NotesApp() {
} }
} }
Scaffold( Box(modifier = Modifier.fillMaxSize()) {
topBar = { Scaffold(
if (!showFullScreenNote) { topBar = {
ModernTopBar( if (!showFullScreenNote) {
title = when(currentScreen) { ModernTopBar(
"main" -> if (selectedCategory != null) selectedCategory!!.name else "AI Notes" title = when(currentScreen) {
"ai" -> "AI Helper" "main" -> if (selectedCategory != null) selectedCategory!!.name else "AI Notes"
"archive" -> "Arsip" "ai" -> "AI Helper"
"trash" -> "Sampah" "starred" -> "Berbintang"
else -> "AI Notes" "archive" -> "Arsip"
}, "trash" -> "Sampah"
showBackButton = (selectedCategory != null && currentScreen == "main") || currentScreen == "ai", else -> "AI Notes"
onBackClick = { },
if (currentScreen == "ai") { showBackButton = (selectedCategory != null && currentScreen == "main") || currentScreen == "ai" || currentScreen == "starred",
currentScreen = "main" onBackClick = {
} else { if (currentScreen == "ai" || currentScreen == "starred") {
selectedCategory = null currentScreen = "main"
} } else {
}, selectedCategory = null
onMenuClick = { drawerState = !drawerState }, }
onSearchClick = { showSearch = !showSearch }, },
searchQuery = searchQuery, onMenuClick = { drawerState = !drawerState },
onSearchQueryChange = { searchQuery = it }, onSearchClick = { showSearch = !showSearch },
showSearch = showSearch && currentScreen == "main" searchQuery = searchQuery,
) onSearchQueryChange = { searchQuery = it },
} showSearch = showSearch && currentScreen == "main"
}, )
floatingActionButton = { }
AnimatedVisibility( },
visible = currentScreen == "main" && !showFullScreenNote, floatingActionButton = {
enter = scaleIn() + fadeIn(), AnimatedVisibility(
exit = scaleOut() + fadeOut() visible = currentScreen == "main" && !showFullScreenNote,
) { enter = scaleIn() + fadeIn(),
FloatingActionButton( exit = scaleOut() + fadeOut()
onClick = {
if (selectedCategory != null) {
editingNote = null
showNoteDialog = true
} else {
showCategoryDialog = true
}
},
containerColor = Color.Transparent,
modifier = Modifier
.shadow(8.dp, CircleShape)
.background(
brush = Brush.linearGradient(
colors = listOf(Color(0xFF6366F1), Color(0xFFA855F7))
),
shape = CircleShape
)
) { ) {
Icon( FloatingActionButton(
Icons.Default.Add, onClick = {
contentDescription = if (selectedCategory != null) "Tambah Catatan" else "Tambah Kategori", if (selectedCategory != null) {
tint = Color.White editingNote = null
showNoteDialog = true
} else {
showCategoryDialog = true
}
},
containerColor = Color.Transparent,
modifier = Modifier
.shadow(8.dp, CircleShape)
.background(
brush = Brush.linearGradient(
colors = listOf(Color(0xFF6366F1), Color(0xFFA855F7))
),
shape = CircleShape
)
) {
Icon(
Icons.Default.Add,
contentDescription = if (selectedCategory != null) "Tambah Catatan" else "Tambah Kategori",
tint = Color.White
)
}
}
},
bottomBar = {
if (!showFullScreenNote) {
ModernBottomBar(
currentScreen = currentScreen,
onHomeClick = {
currentScreen = "main"
selectedCategory = null
},
onAIClick = { currentScreen = "ai" }
) )
} }
} }
}, ) { padding ->
bottomBar = { Box(modifier = Modifier.fillMaxSize()) {
if (!showFullScreenNote) { if (showFullScreenNote && fullScreenNote != null) {
ModernBottomBar( EditableFullScreenNoteView(
currentScreen = currentScreen, note = fullScreenNote!!,
onHomeClick = { onBack = {
currentScreen = "main" showFullScreenNote = false
selectedCategory = null fullScreenNote = null
}, },
onAIClick = { currentScreen = "ai" } onSave = { title, content ->
) notes = notes.map {
} if (it.id == fullScreenNote!!.id) it.copy(
} title = title,
) { padding -> content = content,
Box(modifier = Modifier.fillMaxSize()) { timestamp = System.currentTimeMillis()
if (showFullScreenNote && fullScreenNote != null) { )
EditableFullScreenNoteView( else it
note = fullScreenNote!!, }
onBack = { fullScreenNote = fullScreenNote!!.copy(title = title, content = content)
showFullScreenNote = false },
fullScreenNote = null onArchive = {
}, notes = notes.map {
onSave = { title, content -> if (it.id == fullScreenNote!!.id) it.copy(isArchived = true)
notes = notes.map { else it
if (it.id == fullScreenNote!!.id) it.copy( }
title = title, showFullScreenNote = false
content = content, fullScreenNote = null
timestamp = System.currentTimeMillis() },
onDelete = {
notes = notes.map {
if (it.id == fullScreenNote!!.id) it.copy(isDeleted = true)
else it
}
showFullScreenNote = false
fullScreenNote = null
},
onPinToggle = {
notes = notes.map {
if (it.id == fullScreenNote!!.id) it.copy(isPinned = !it.isPinned)
else it
}
fullScreenNote = fullScreenNote!!.copy(isPinned = !fullScreenNote!!.isPinned)
}
)
} else {
Column(
modifier = Modifier
.padding(padding)
.fillMaxSize()
) {
when (currentScreen) {
"main" -> MainScreen(
categories = categories,
notes = notes,
selectedCategory = selectedCategory,
searchQuery = searchQuery,
onCategoryClick = { selectedCategory = it },
onNoteClick = { note ->
fullScreenNote = note
showFullScreenNote = true
},
onNoteLongClick = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isArchived = true)
else it
}
},
onPinToggle = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isPinned = !it.isPinned)
else it
}
},
onCategoryLongClick = { category ->
categories = categories.filter { it.id != category.id }
notes = notes.filter { it.categoryId != category.id }
}
)
"starred" -> StarredNotesScreen(
notes = notes,
categories = categories,
onNoteClick = { note ->
fullScreenNote = note
showFullScreenNote = true
},
onMenuClick = { drawerState = true },
onBack = { currentScreen = "main" },
onUnpin = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isPinned = false)
else it
}
}
)
"ai" -> AIHelperScreen(
categories = categories,
notes = notes.filter { !it.isDeleted }
)
"archive" -> ArchiveScreen(
notes = notes.filter { it.isArchived && !it.isDeleted },
categories = categories,
onRestore = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isArchived = false)
else it
}
},
onDelete = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isDeleted = true)
else it
}
}
)
"trash" -> TrashScreen(
notes = notes.filter { it.isDeleted },
categories = categories,
onRestore = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isDeleted = false, isArchived = false)
else it
}
},
onDeletePermanent = { note ->
notes = notes.filter { it.id != note.id }
}
) )
else it
} }
fullScreenNote = fullScreenNote!!.copy(title = title, content = content)
},
onArchive = {
notes = notes.map {
if (it.id == fullScreenNote!!.id) it.copy(isArchived = true)
else it
}
showFullScreenNote = false
fullScreenNote = null
},
onDelete = {
notes = notes.map {
if (it.id == fullScreenNote!!.id) it.copy(isDeleted = true)
else it
}
showFullScreenNote = false
fullScreenNote = null
},
onPinToggle = {
notes = notes.map {
if (it.id == fullScreenNote!!.id) it.copy(isPinned = !it.isPinned)
else it
}
fullScreenNote = fullScreenNote!!.copy(isPinned = !fullScreenNote!!.isPinned)
}
)
} else {
Column(
modifier = Modifier
.padding(padding)
.fillMaxSize()
) {
when (currentScreen) {
"main" -> MainScreen(
categories = categories,
notes = notes,
selectedCategory = selectedCategory,
searchQuery = searchQuery,
onCategoryClick = { selectedCategory = it },
onNoteClick = { note ->
fullScreenNote = note
showFullScreenNote = true
},
onNoteLongClick = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isArchived = true)
else it
}
},
onPinToggle = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isPinned = !it.isPinned)
else it
}
},
onCategoryLongClick = { category ->
categories = categories.filter { it.id != category.id }
notes = notes.filter { it.categoryId != category.id }
}
)
"ai" -> AIHelperScreen(
categories = categories,
notes = notes.filter { !it.isDeleted }
)
"archive" -> ArchiveScreen(
notes = notes.filter { it.isArchived && !it.isDeleted },
categories = categories,
onRestore = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isArchived = false)
else it
}
},
onDelete = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isDeleted = true)
else it
}
}
)
"trash" -> TrashScreen(
notes = notes.filter { it.isDeleted },
categories = categories,
onRestore = { note ->
notes = notes.map {
if (it.id == note.id) it.copy(isDeleted = false, isArchived = false)
else it
}
},
onDeletePermanent = { note ->
notes = notes.filter { it.id != note.id }
}
)
} }
} }
}
// Drawer with Animation // Dialogs
AnimatedVisibility( if (showCategoryDialog) {
visible = drawerState, CategoryDialog(
enter = fadeIn() + slideInHorizontally(), onDismiss = { showCategoryDialog = false },
exit = fadeOut() + slideOutHorizontally() onSave = { name, gradientStart, gradientEnd ->
) { categories = categories + Category(
DrawerMenu( name = name,
currentScreen = currentScreen, gradientStart = gradientStart,
onDismiss = { drawerState = false }, gradientEnd = gradientEnd
onItemClick = { screen ->
currentScreen = screen
selectedCategory = null
drawerState = false
showSearch = false
searchQuery = ""
}
)
}
// Dialogs
if (showCategoryDialog) {
CategoryDialog(
onDismiss = { showCategoryDialog = false },
onSave = { name, gradientStart, gradientEnd ->
categories = categories + Category(
name = name,
gradientStart = gradientStart,
gradientEnd = gradientEnd
)
showCategoryDialog = false
}
)
}
if (showNoteDialog && selectedCategory != null) {
NoteDialog(
note = editingNote,
onDismiss = {
showNoteDialog = false
editingNote = null
},
onSave = { title, content ->
if (editingNote != null) {
notes = notes.map {
if (it.id == editingNote!!.id)
it.copy(
title = title,
content = content,
timestamp = System.currentTimeMillis()
)
else it
}
} else {
notes = notes + Note(
categoryId = selectedCategory!!.id,
title = title,
content = content
) )
showCategoryDialog = false
} }
showNoteDialog = false )
editingNote = null }
},
onDelete = if (editingNote != null) { if (showNoteDialog && selectedCategory != null) {
{ NoteDialog(
notes = notes.map { note = editingNote,
if (it.id == editingNote!!.id) it.copy(isDeleted = true) onDismiss = {
else it showNoteDialog = false
editingNote = null
},
onSave = { title, content ->
if (editingNote != null) {
notes = notes.map {
if (it.id == editingNote!!.id)
it.copy(
title = title,
content = content,
timestamp = System.currentTimeMillis()
)
else it
}
} else {
notes = notes + Note(
categoryId = selectedCategory!!.id,
title = title,
content = content
)
} }
showNoteDialog = false showNoteDialog = false
editingNote = null editingNote = null
} },
} else null onDelete = if (editingNote != null) {
) {
notes = notes.map {
if (it.id == editingNote!!.id) it.copy(isDeleted = true)
else it
}
showNoteDialog = false
editingNote = null
}
} else null
)
}
} }
} }
// Drawer with Animation - DI LUAR SCAFFOLD agar di atas semua
AnimatedVisibility(
visible = drawerState,
enter = fadeIn() + slideInHorizontally(
initialOffsetX = { -it }
),
exit = fadeOut() + slideOutHorizontally(
targetOffsetX = { -it }
),
modifier = Modifier.zIndex(100f) // Z-index tinggi
) {
DrawerMenu(
currentScreen = currentScreen,
onDismiss = { drawerState = false },
onItemClick = { screen ->
currentScreen = screen
selectedCategory = null
drawerState = false
showSearch = false
searchQuery = ""
}
)
}
} }
} }
@ -549,7 +577,7 @@ fun EditableFullScreenNoteView(
onPinToggle() onPinToggle()
}) { }) {
Icon( Icon(
if (note.isPinned) Icons.Default.Star else Icons.Default.Add, if (note.isPinned) Icons.Filled.Star else Icons.Outlined.StarBorder,
contentDescription = "Pin Catatan", contentDescription = "Pin Catatan",
tint = if (note.isPinned) Color(0xFFFBBF24) else MaterialTheme.colorScheme.onSurface tint = if (note.isPinned) Color(0xFFFBBF24) else MaterialTheme.colorScheme.onSurface
) )
@ -950,19 +978,22 @@ fun NoteCard(
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.Top verticalAlignment = Alignment.Top
) { ) {
// Judul
Text( Text(
note.title, note.title,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = Color.White, color = Color.White,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f),
maxLines = 2,
overflow = TextOverflow.Ellipsis
) )
IconButton( IconButton(
onClick = onPinClick, onClick = onPinClick,
modifier = Modifier.size(24.dp) modifier = Modifier.size(24.dp)
) { ) {
Icon( Icon(
if (note.isPinned) Icons.Default.Star else Icons.Default.Add, if (note.isPinned) Icons.Filled.Star else Icons.Outlined.StarBorder,
contentDescription = "Pin", contentDescription = "Pin",
tint = if (note.isPinned) Color(0xFFFBBF24) else Color.Gray, tint = if (note.isPinned) Color(0xFFFBBF24) else Color.Gray,
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
@ -970,18 +1001,37 @@ fun NoteCard(
} }
} }
// Deskripsi
if (note.content.isNotEmpty()) { if (note.content.isNotEmpty()) {
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(12.dp))
Text(
text = "Deskripsi",
style = MaterialTheme.typography.labelSmall,
color = Color(0xFF94A3B8),
fontWeight = FontWeight.SemiBold
)
Spacer(modifier = Modifier.height(4.dp))
Text( Text(
note.content, note.content,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
maxLines = 6, maxLines = 4,
overflow = TextOverflow.Ellipsis,
color = Color(0xFFCBD5E1), color = Color(0xFFCBD5E1),
lineHeight = 20.sp lineHeight = 20.sp
) )
} }
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
// Divider
Divider(
color = Color(0xFF334155),
thickness = 1.dp
)
Spacer(modifier = Modifier.height(8.dp))
// Timestamp
Text( Text(
dateFormat.format(Date(note.timestamp)), dateFormat.format(Date(note.timestamp)),
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
@ -1000,20 +1050,32 @@ fun DrawerMenu(
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(Color.Black.copy(alpha = 0.6f)) .statusBarsPadding() // Padding untuk status bar
.clickable(onClick = onDismiss) .background(Color.Black.copy(alpha = 0.5f))
.clickable(
onClick = onDismiss,
indication = null,
interactionSource = remember { MutableInteractionSource() }
)
) { ) {
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxHeight() .fillMaxHeight()
.width(280.dp) .width(250.dp)
.clickable(enabled = false) {}, .align(Alignment.CenterStart)
shape = RoundedCornerShape(0.dp), .clickable(
onClick = {},
indication = null,
interactionSource = remember { MutableInteractionSource() }
),
shape = RoundedCornerShape(topEnd = 0.dp, bottomEnd = 0.dp),
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = Color(0xFF1E293B) containerColor = Color(0xFF1E293B)
) ),
elevation = CardDefaults.cardElevation(defaultElevation = 16.dp)
) { ) {
Column(modifier = Modifier.fillMaxSize()) { Column(modifier = Modifier.fillMaxSize()) {
// Header Drawer dengan tombol close
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -1022,38 +1084,69 @@ fun DrawerMenu(
colors = listOf(Color(0xFF6366F1), Color(0xFFA855F7)) colors = listOf(Color(0xFF6366F1), Color(0xFFA855F7))
) )
) )
.padding(32.dp) .padding(24.dp)
) { ) {
Column { Row(
Icon( modifier = Modifier.fillMaxWidth(),
Icons.Default.Create, horizontalArrangement = Arrangement.SpaceBetween,
contentDescription = null, verticalAlignment = Alignment.CenterVertically
tint = Color.White, ) {
modifier = Modifier.size(40.dp) Column {
) Icon(
Spacer(modifier = Modifier.height(12.dp)) Icons.Default.Create,
Text( contentDescription = null,
"AI Notes", tint = Color.White,
style = MaterialTheme.typography.headlineMedium, modifier = Modifier.size(36.dp)
color = Color.White, )
fontWeight = FontWeight.Bold Spacer(modifier = Modifier.height(12.dp))
) Text(
Text( "AI Notes",
"Smart & Modern", style = MaterialTheme.typography.headlineMedium,
style = MaterialTheme.typography.bodyMedium, color = Color.White,
color = Color.White.copy(0.8f) fontWeight = FontWeight.Bold
) )
Text(
"Smart & Modern",
style = MaterialTheme.typography.bodyMedium,
color = Color.White.copy(0.8f)
)
}
// // Tombol Close
// IconButton(
// onClick = onDismiss,
// modifier = Modifier
// .size(40.dp)
// .background(
// Color.White.copy(alpha = 0.2f),
// shape = CircleShape
// )
// ) {
// Icon(
// Icons.Default.Close,
// contentDescription = "Tutup Menu",
// tint = Color.White,
// modifier = Modifier.size(24.dp)
// )
// }
} }
} }
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
// Menu Items
MenuItem( MenuItem(
icon = Icons.Default.Home, icon = Icons.Default.Home,
text = "Beranda", text = "Beranda",
isSelected = currentScreen == "main" isSelected = currentScreen == "main"
) { onItemClick("main") } ) { onItemClick("main") }
MenuItem(
icon = Icons.Default.Star,
text = "Berbintang",
isSelected = currentScreen == "starred"
) { onItemClick("starred") }
MenuItem( MenuItem(
icon = Icons.Default.Archive, icon = Icons.Default.Archive,
text = "Arsip", text = "Arsip",
@ -1065,6 +1158,21 @@ fun DrawerMenu(
text = "Sampah", text = "Sampah",
isSelected = currentScreen == "trash" isSelected = currentScreen == "trash"
) { onItemClick("trash") } ) { onItemClick("trash") }
Spacer(modifier = Modifier.weight(1f))
// Footer
Divider(
color = Color.White.copy(alpha = 0.1f),
modifier = Modifier.padding(horizontal = 16.dp)
)
Text(
text = "Version 1.0.0",
style = MaterialTheme.typography.bodySmall,
color = Color.White.copy(alpha = 0.5f),
modifier = Modifier.padding(16.dp)
)
} }
} }
} }
@ -1795,10 +1903,11 @@ fun ChatBubble(
horizontalArrangement = if (message.isUser) Arrangement.End else Arrangement.Start horizontalArrangement = if (message.isUser) Arrangement.End else Arrangement.Start
) { ) {
if (!message.isUser) { if (!message.isUser) {
// Ganti ikon bintang dengan ikon robot/sparkles
Icon( Icon(
Icons.Default.Star, Icons.Default.AutoAwesome, // Atau bisa diganti dengan ikon lain seperti AutoAwesome
contentDescription = null, contentDescription = null,
tint = Color(0xFFFBBF24), tint = Color(0xFF6366F1), // Warna ungu/biru untuk AI
modifier = Modifier modifier = Modifier
.size(32.dp) .size(32.dp)
.padding(end = 8.dp) .padding(end = 8.dp)
@ -2168,6 +2277,136 @@ fun TrashNoteCard(
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun StarredNotesScreen(
notes: List<Note>,
categories: List<Category>,
onNoteClick: (Note) -> Unit,
onMenuClick: () -> Unit,
onBack: () -> Unit,
onUnpin: (Note) -> Unit
) {
val starredNotes = notes.filter { it.isPinned && !it.isArchived && !it.isDeleted }
if (starredNotes.isEmpty()) {
EmptyState(
icon = Icons.Default.Star,
message = "Belum ada catatan berbintang",
subtitle = "Catatan yang ditandai berbintang akan muncul di sini"
)
} else {
LazyColumn(
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
items(starredNotes) { note ->
val category = categories.find { it.id == note.categoryId }
StarredNoteCard(
note = note,
categoryName = category?.name ?: "Unknown",
onClick = { onNoteClick(note) },
onUnpin = { onUnpin(note) }
)
}
}
}
}
@Composable
fun StarredNoteCard(
note: Note,
categoryName: String,
onClick: () -> Unit,
onUnpin: () -> Unit
) {
Card(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onClick),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(
containerColor = Color(0xFF1E293B)
),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.Top
) {
Column(modifier = Modifier.weight(1f)) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Icon(
Icons.Default.Star,
contentDescription = null,
tint = Color(0xFFFBBF24),
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
note.title,
fontWeight = FontWeight.Bold,
color = Color.White,
style = MaterialTheme.typography.titleMedium
)
}
Spacer(modifier = Modifier.height(4.dp))
Text(
categoryName,
color = Color(0xFF64748B),
style = MaterialTheme.typography.bodySmall
)
}
}
if (note.content.isNotEmpty()) {
Spacer(modifier = Modifier.height(8.dp))
Text(
note.content,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
color = Color(0xFF94A3B8),
style = MaterialTheme.typography.bodyMedium
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 12.dp),
horizontalArrangement = Arrangement.End
) {
TextButton(onClick = onClick) {
Icon(
Icons.Default.Info,
contentDescription = null,
modifier = Modifier.size(18.dp),
tint = Color(0xFF6366F1)
)
Spacer(modifier = Modifier.width(4.dp))
Text("Lihat Detail", color = Color(0xFF6366F1), fontWeight = FontWeight.Bold)
}
Spacer(modifier = Modifier.width(8.dp))
TextButton(onClick = onUnpin) {
Icon(
Icons.Outlined.StarBorder,
contentDescription = null,
modifier = Modifier.size(18.dp),
tint = Color(0xFFFBBF24)
)
Spacer(modifier = Modifier.width(4.dp))
Text("Hapus Bintang", color = Color(0xFFFBBF24), fontWeight = FontWeight.Bold)
}
}
}
}
}
@Composable @Composable
fun EmptyState( fun EmptyState(
icon: ImageVector, icon: ImageVector,