Menyesuaikan Tampilan Drawer Menu dan Halaman Catatan Berbintang
This commit is contained in:
parent
9c699767e9
commit
f2da1792b1
@ -9,6 +9,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
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.text.AnnotatedString
|
||||
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.TextOverflow
|
||||
import androidx.compose.ui.zIndex
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
// Data Classes
|
||||
@ -127,7 +131,7 @@ fun NotesApp() {
|
||||
var showFullScreenNote by remember { mutableStateOf(false) }
|
||||
var fullScreenNote by remember { mutableStateOf<Note?>(null) }
|
||||
|
||||
// Load data dari DataStore - dengan error handling
|
||||
// Load data dari DataStore
|
||||
LaunchedEffect(Unit) {
|
||||
try {
|
||||
dataStoreManager.categoriesFlow.collect { loadedCategories ->
|
||||
@ -172,268 +176,292 @@ fun NotesApp() {
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
if (!showFullScreenNote) {
|
||||
ModernTopBar(
|
||||
title = when(currentScreen) {
|
||||
"main" -> if (selectedCategory != null) selectedCategory!!.name else "AI Notes"
|
||||
"ai" -> "AI Helper"
|
||||
"archive" -> "Arsip"
|
||||
"trash" -> "Sampah"
|
||||
else -> "AI Notes"
|
||||
},
|
||||
showBackButton = (selectedCategory != null && currentScreen == "main") || currentScreen == "ai",
|
||||
onBackClick = {
|
||||
if (currentScreen == "ai") {
|
||||
currentScreen = "main"
|
||||
} else {
|
||||
selectedCategory = null
|
||||
}
|
||||
},
|
||||
onMenuClick = { drawerState = !drawerState },
|
||||
onSearchClick = { showSearch = !showSearch },
|
||||
searchQuery = searchQuery,
|
||||
onSearchQueryChange = { searchQuery = it },
|
||||
showSearch = showSearch && currentScreen == "main"
|
||||
)
|
||||
}
|
||||
},
|
||||
floatingActionButton = {
|
||||
AnimatedVisibility(
|
||||
visible = currentScreen == "main" && !showFullScreenNote,
|
||||
enter = scaleIn() + fadeIn(),
|
||||
exit = scaleOut() + fadeOut()
|
||||
) {
|
||||
FloatingActionButton(
|
||||
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
|
||||
)
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
if (!showFullScreenNote) {
|
||||
ModernTopBar(
|
||||
title = when(currentScreen) {
|
||||
"main" -> if (selectedCategory != null) selectedCategory!!.name else "AI Notes"
|
||||
"ai" -> "AI Helper"
|
||||
"starred" -> "Berbintang"
|
||||
"archive" -> "Arsip"
|
||||
"trash" -> "Sampah"
|
||||
else -> "AI Notes"
|
||||
},
|
||||
showBackButton = (selectedCategory != null && currentScreen == "main") || currentScreen == "ai" || currentScreen == "starred",
|
||||
onBackClick = {
|
||||
if (currentScreen == "ai" || currentScreen == "starred") {
|
||||
currentScreen = "main"
|
||||
} else {
|
||||
selectedCategory = null
|
||||
}
|
||||
},
|
||||
onMenuClick = { drawerState = !drawerState },
|
||||
onSearchClick = { showSearch = !showSearch },
|
||||
searchQuery = searchQuery,
|
||||
onSearchQueryChange = { searchQuery = it },
|
||||
showSearch = showSearch && currentScreen == "main"
|
||||
)
|
||||
}
|
||||
},
|
||||
floatingActionButton = {
|
||||
AnimatedVisibility(
|
||||
visible = currentScreen == "main" && !showFullScreenNote,
|
||||
enter = scaleIn() + fadeIn(),
|
||||
exit = scaleOut() + fadeOut()
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Add,
|
||||
contentDescription = if (selectedCategory != null) "Tambah Catatan" else "Tambah Kategori",
|
||||
tint = Color.White
|
||||
FloatingActionButton(
|
||||
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(
|
||||
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" }
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
if (!showFullScreenNote) {
|
||||
ModernBottomBar(
|
||||
currentScreen = currentScreen,
|
||||
onHomeClick = {
|
||||
currentScreen = "main"
|
||||
selectedCategory = null
|
||||
},
|
||||
onAIClick = { currentScreen = "ai" }
|
||||
)
|
||||
}
|
||||
}
|
||||
) { padding ->
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
if (showFullScreenNote && fullScreenNote != null) {
|
||||
EditableFullScreenNoteView(
|
||||
note = fullScreenNote!!,
|
||||
onBack = {
|
||||
showFullScreenNote = false
|
||||
fullScreenNote = null
|
||||
},
|
||||
onSave = { title, content ->
|
||||
notes = notes.map {
|
||||
if (it.id == fullScreenNote!!.id) it.copy(
|
||||
title = title,
|
||||
content = content,
|
||||
timestamp = System.currentTimeMillis()
|
||||
) { padding ->
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
if (showFullScreenNote && fullScreenNote != null) {
|
||||
EditableFullScreenNoteView(
|
||||
note = fullScreenNote!!,
|
||||
onBack = {
|
||||
showFullScreenNote = false
|
||||
fullScreenNote = null
|
||||
},
|
||||
onSave = { title, content ->
|
||||
notes = notes.map {
|
||||
if (it.id == fullScreenNote!!.id) it.copy(
|
||||
title = title,
|
||||
content = content,
|
||||
timestamp = System.currentTimeMillis()
|
||||
)
|
||||
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 }
|
||||
}
|
||||
)
|
||||
"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
|
||||
AnimatedVisibility(
|
||||
visible = drawerState,
|
||||
enter = fadeIn() + slideInHorizontally(),
|
||||
exit = fadeOut() + slideOutHorizontally()
|
||||
) {
|
||||
DrawerMenu(
|
||||
currentScreen = currentScreen,
|
||||
onDismiss = { drawerState = false },
|
||||
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
|
||||
// Dialogs
|
||||
if (showCategoryDialog) {
|
||||
CategoryDialog(
|
||||
onDismiss = { showCategoryDialog = false },
|
||||
onSave = { name, gradientStart, gradientEnd ->
|
||||
categories = categories + Category(
|
||||
name = name,
|
||||
gradientStart = gradientStart,
|
||||
gradientEnd = gradientEnd
|
||||
)
|
||||
showCategoryDialog = false
|
||||
}
|
||||
showNoteDialog = false
|
||||
editingNote = null
|
||||
},
|
||||
onDelete = if (editingNote != null) {
|
||||
{
|
||||
notes = notes.map {
|
||||
if (it.id == editingNote!!.id) it.copy(isDeleted = true)
|
||||
else it
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
showNoteDialog = false
|
||||
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()
|
||||
}) {
|
||||
Icon(
|
||||
if (note.isPinned) Icons.Default.Star else Icons.Default.Add,
|
||||
if (note.isPinned) Icons.Filled.Star else Icons.Outlined.StarBorder,
|
||||
contentDescription = "Pin Catatan",
|
||||
tint = if (note.isPinned) Color(0xFFFBBF24) else MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
@ -950,19 +978,22 @@ fun NoteCard(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.Top
|
||||
) {
|
||||
// Judul
|
||||
Text(
|
||||
note.title,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color.White,
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
IconButton(
|
||||
onClick = onPinClick,
|
||||
modifier = Modifier.size(24.dp)
|
||||
) {
|
||||
Icon(
|
||||
if (note.isPinned) Icons.Default.Star else Icons.Default.Add,
|
||||
if (note.isPinned) Icons.Filled.Star else Icons.Outlined.StarBorder,
|
||||
contentDescription = "Pin",
|
||||
tint = if (note.isPinned) Color(0xFFFBBF24) else Color.Gray,
|
||||
modifier = Modifier.size(18.dp)
|
||||
@ -970,18 +1001,37 @@ fun NoteCard(
|
||||
}
|
||||
}
|
||||
|
||||
// Deskripsi
|
||||
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(
|
||||
note.content,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
maxLines = 6,
|
||||
maxLines = 4,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = Color(0xFFCBD5E1),
|
||||
lineHeight = 20.sp
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
// Divider
|
||||
Divider(
|
||||
color = Color(0xFF334155),
|
||||
thickness = 1.dp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
// Timestamp
|
||||
Text(
|
||||
dateFormat.format(Date(note.timestamp)),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
@ -1000,20 +1050,32 @@ fun DrawerMenu(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Black.copy(alpha = 0.6f))
|
||||
.clickable(onClick = onDismiss)
|
||||
.statusBarsPadding() // Padding untuk status bar
|
||||
.background(Color.Black.copy(alpha = 0.5f))
|
||||
.clickable(
|
||||
onClick = onDismiss,
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
)
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(280.dp)
|
||||
.clickable(enabled = false) {},
|
||||
shape = RoundedCornerShape(0.dp),
|
||||
.width(250.dp)
|
||||
.align(Alignment.CenterStart)
|
||||
.clickable(
|
||||
onClick = {},
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
),
|
||||
shape = RoundedCornerShape(topEnd = 0.dp, bottomEnd = 0.dp),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = Color(0xFF1E293B)
|
||||
)
|
||||
),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 16.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
// Header Drawer dengan tombol close
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@ -1022,38 +1084,69 @@ fun DrawerMenu(
|
||||
colors = listOf(Color(0xFF6366F1), Color(0xFFA855F7))
|
||||
)
|
||||
)
|
||||
.padding(32.dp)
|
||||
.padding(24.dp)
|
||||
) {
|
||||
Column {
|
||||
Icon(
|
||||
Icons.Default.Create,
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(40.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(
|
||||
"AI Notes",
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
color = Color.White,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
"Smart & Modern",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = Color.White.copy(0.8f)
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column {
|
||||
Icon(
|
||||
Icons.Default.Create,
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(36.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(
|
||||
"AI Notes",
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
color = Color.White,
|
||||
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))
|
||||
|
||||
// Menu Items
|
||||
MenuItem(
|
||||
icon = Icons.Default.Home,
|
||||
text = "Beranda",
|
||||
isSelected = currentScreen == "main"
|
||||
) { onItemClick("main") }
|
||||
|
||||
MenuItem(
|
||||
icon = Icons.Default.Star,
|
||||
text = "Berbintang",
|
||||
isSelected = currentScreen == "starred"
|
||||
) { onItemClick("starred") }
|
||||
|
||||
MenuItem(
|
||||
icon = Icons.Default.Archive,
|
||||
text = "Arsip",
|
||||
@ -1065,6 +1158,21 @@ fun DrawerMenu(
|
||||
text = "Sampah",
|
||||
isSelected = currentScreen == "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
|
||||
) {
|
||||
if (!message.isUser) {
|
||||
// Ganti ikon bintang dengan ikon robot/sparkles
|
||||
Icon(
|
||||
Icons.Default.Star,
|
||||
Icons.Default.AutoAwesome, // Atau bisa diganti dengan ikon lain seperti AutoAwesome
|
||||
contentDescription = null,
|
||||
tint = Color(0xFFFBBF24),
|
||||
tint = Color(0xFF6366F1), // Warna ungu/biru untuk AI
|
||||
modifier = Modifier
|
||||
.size(32.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
|
||||
fun EmptyState(
|
||||
icon: ImageVector,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user