Berikan fungsi pada fitur pencarian pada halaman file berbintang, arsip, dan sampah

This commit is contained in:
202310715082 FAZRI ABDURRAHMAN 2025-12-25 01:35:21 +07:00
parent 2e3cb39244
commit f0e4396da1
3 changed files with 347 additions and 74 deletions

View File

@ -1,12 +1,30 @@
package com.example.notesai.presentation.screens.archive
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Archive
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
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.graphics.Color
import androidx.compose.ui.unit.dp
import com.example.notesai.data.model.Note
import com.example.notesai.data.model.Category
@ -20,18 +38,90 @@ fun ArchiveScreen(
onRestore: (Note) -> Unit,
onDelete: (Note) -> Unit
) {
if (notes.isEmpty()) {
var searchQuery by remember { mutableStateOf("") }
// Filter berdasarkan search query
val filteredNotes = if (searchQuery.isBlank()) {
notes
} else {
notes.filter { note ->
note.title.contains(searchQuery, ignoreCase = true) ||
note.content.contains(searchQuery, ignoreCase = true) ||
note.description.contains(searchQuery, ignoreCase = true) ||
categories.find { it.id == note.categoryId }?.name?.contains(searchQuery, ignoreCase = true) == true
}
}
Column(modifier = Modifier.fillMaxSize()) {
// Search Bar
OutlinedTextField(
value = searchQuery,
onValueChange = { searchQuery = it },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp),
placeholder = {
Text(
"Cari catatan arsip...",
color = Color(0xFF64748B)
)
},
leadingIcon = {
Icon(
Icons.Default.Search,
contentDescription = null,
tint = Color(0xFF64748B)
)
},
trailingIcon = {
if (searchQuery.isNotEmpty()) {
IconButton(onClick = { searchQuery = "" }) {
Icon(
Icons.Default.Clear,
contentDescription = "Clear",
tint = Color(0xFF64748B)
)
}
}
},
shape = RoundedCornerShape(12.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedContainerColor = Color(0xFF1E293B),
unfocusedContainerColor = Color(0xFF1E293B),
focusedBorderColor = Color(0xFF6366F1),
unfocusedBorderColor = Color(0xFF334155),
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
cursorColor = Color(0xFF6366F1)
),
singleLine = true
)
// Content
if (filteredNotes.isEmpty()) {
if (searchQuery.isNotEmpty()) {
EmptyState(
icon = Icons.Default.Search,
message = "Tidak ada hasil",
subtitle = "Coba kata kunci lain"
)
} else {
EmptyState(
icon = Icons.Default.Archive,
message = "Arsip kosong",
subtitle = "Catatan yang diarsipkan akan muncul di sini"
)
}
} else {
LazyColumn(
contentPadding = PaddingValues(16.dp),
contentPadding = PaddingValues(
start = 16.dp,
end = 16.dp,
bottom = 100.dp
),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
items(notes) { note ->
items(filteredNotes) { note ->
val category = categories.find { it.id == note.categoryId }
ArchiveNoteCard(
note = note,
@ -42,4 +132,5 @@ fun ArchiveScreen(
}
}
}
}
}

View File

@ -3,14 +3,32 @@ package com.example.notesai.presentation.screens.starred
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
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.graphics.Color
import androidx.compose.ui.unit.dp
import com.example.notesai.presentation.components.EmptyState
import com.example.notesai.presentation.screens.starred.components.StarredNoteCard
@ -25,27 +43,93 @@ fun StarredNotesScreen(
onNoteClick: (Note) -> Unit,
onUnpin: (Note) -> Unit
) {
val starredNotes = notes.filter { it.isPinned && !it.isArchived && !it.isDeleted }
var searchQuery by remember { mutableStateOf("") }
val starredNotes = notes
.filter { it.isPinned && !it.isArchived && !it.isDeleted }
.sortedByDescending { it.timestamp }
// Filter berdasarkan search query
val filteredNotes = if (searchQuery.isBlank()) {
starredNotes
} else {
starredNotes.filter { note ->
note.title.contains(searchQuery, ignoreCase = true) ||
note.content.contains(searchQuery, ignoreCase = true) ||
note.description.contains(searchQuery, ignoreCase = true)
}
}
Column(modifier = Modifier.fillMaxSize()) {
if (starredNotes.isEmpty()) {
// Search Bar
OutlinedTextField(
value = searchQuery,
onValueChange = { searchQuery = it },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp),
placeholder = {
Text(
"Cari catatan berbintang...",
color = Color(0xFF64748B)
)
},
leadingIcon = {
Icon(
Icons.Default.Search,
contentDescription = null,
tint = Color(0xFF64748B)
)
},
trailingIcon = {
if (searchQuery.isNotEmpty()) {
IconButton(onClick = { searchQuery = "" }) {
Icon(
Icons.Default.Clear,
contentDescription = "Clear",
tint = Color(0xFF64748B)
)
}
}
},
shape = RoundedCornerShape(12.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedContainerColor = Color(0xFF1E293B),
unfocusedContainerColor = Color(0xFF1E293B),
focusedBorderColor = Color(0xFF6366F1),
unfocusedBorderColor = Color(0xFF334155),
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
cursorColor = Color(0xFF6366F1)
),
singleLine = true
)
// Content
if (filteredNotes.isEmpty()) {
if (searchQuery.isNotEmpty()) {
EmptyState(
icon = Icons.Default.Search,
message = "Tidak ada hasil",
subtitle = "Coba kata kunci lain"
)
} else {
EmptyState(
icon = Icons.Default.Star,
message = "Belum ada catatan berbintang",
subtitle = "Catatan yang ditandai berbintang akan muncul di sini"
)
}
} else {
LazyColumn(
contentPadding = PaddingValues(
start = 16.dp,
end = 16.dp,
top = 16.dp,
bottom = 100.dp // Extra space untuk bottom bar
bottom = 100.dp
),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
items(starredNotes) { note ->
items(filteredNotes) { note ->
val category = categories.find { it.id == note.categoryId }
StarredNoteCard(
note = note,

View File

@ -1,15 +1,30 @@
// File: presentation/screens/trash/TrashScreen.kt
package com.example.notesai.presentation.screens.trash
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
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.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@ -28,33 +43,114 @@ fun TrashScreen(
onRestoreCategory: (Category) -> Unit,
onDeleteCategoryPermanent: (Category) -> Unit
) {
var searchQuery by remember { mutableStateOf("") }
// Filter kategori dan note yang dihapus
val deletedCategories = categories.filter { it.isDeleted }
val deletedNotes = notes.filter { it.isDeleted }
if (deletedCategories.isEmpty() && deletedNotes.isEmpty()) {
// Filter berdasarkan search query
val filteredCategories = if (searchQuery.isBlank()) {
deletedCategories
} else {
deletedCategories.filter { category ->
category.name.contains(searchQuery, ignoreCase = true)
}
}
val filteredNotes = if (searchQuery.isBlank()) {
deletedNotes
} else {
deletedNotes.filter { note ->
note.title.contains(searchQuery, ignoreCase = true) ||
note.content.contains(searchQuery, ignoreCase = true) ||
note.description.contains(searchQuery, ignoreCase = true) ||
categories.find { it.id == note.categoryId }?.name?.contains(searchQuery, ignoreCase = true) == true
}
}
Column(modifier = Modifier.fillMaxSize()) {
// Search Bar
OutlinedTextField(
value = searchQuery,
onValueChange = { searchQuery = it },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp),
placeholder = {
Text(
"Cari di sampah...",
color = Color(0xFF64748B)
)
},
leadingIcon = {
Icon(
Icons.Default.Search,
contentDescription = null,
tint = Color(0xFF64748B)
)
},
trailingIcon = {
if (searchQuery.isNotEmpty()) {
IconButton(onClick = { searchQuery = "" }) {
Icon(
Icons.Default.Clear,
contentDescription = "Clear",
tint = Color(0xFF64748B)
)
}
}
},
shape = RoundedCornerShape(12.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedContainerColor = Color(0xFF1E293B),
unfocusedContainerColor = Color(0xFF1E293B),
focusedBorderColor = Color(0xFF6366F1),
unfocusedBorderColor = Color(0xFF334155),
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
cursorColor = Color(0xFF6366F1)
),
singleLine = true
)
// Content
if (filteredCategories.isEmpty() && filteredNotes.isEmpty()) {
if (searchQuery.isNotEmpty()) {
EmptyState(
icon = Icons.Default.Search,
message = "Tidak ada hasil",
subtitle = "Coba kata kunci lain"
)
} else {
EmptyState(
icon = Icons.Default.Delete,
message = "Sampah kosong",
subtitle = "Kategori dan catatan yang dihapus akan muncul di sini"
)
}
} else {
LazyColumn(
contentPadding = PaddingValues(16.dp),
contentPadding = PaddingValues(
start = 16.dp,
end = 16.dp,
bottom = 100.dp
),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
// Section: Kategori Terhapus
if (deletedCategories.isNotEmpty()) {
if (filteredCategories.isNotEmpty()) {
item {
Text(
"Kategori Terhapus (${deletedCategories.size})",
"Kategori Terhapus (${filteredCategories.size})",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = Color(0xFF94A3B8)
color = Color(0xFF94A3B8),
modifier = Modifier.padding(vertical = 8.dp)
)
}
items(deletedCategories) { category ->
items(filteredCategories) { category ->
val notesInCategory = notes.count {
it.categoryId == category.id && it.isDeleted
}
@ -68,17 +164,18 @@ fun TrashScreen(
}
// Section: Catatan Terhapus
if (deletedNotes.isNotEmpty()) {
if (filteredNotes.isNotEmpty()) {
item {
Text(
"Catatan Terhapus (${deletedNotes.size})",
"Catatan Terhapus (${filteredNotes.size})",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = Color(0xFF94A3B8)
color = Color(0xFF94A3B8),
modifier = Modifier.padding(vertical = 8.dp)
)
}
items(deletedNotes) { note ->
items(filteredNotes) { note ->
val category = categories.find { it.id == note.categoryId }
TrashNoteCard(
note = note,
@ -90,4 +187,5 @@ fun TrashScreen(
}
}
}
}
}