* **Fitur search beranda** - Cari kategori berdasarkan nama

* **Search filtering real-time** - Kategori otomatis filter saat mengetik
* **Delete kategori dengan UI** - Tombol X di top-right corner setiap kategori
* **Confirmation dialog untuk delete** - Prevent accidental deletion dengan warning message
* **Search di kategori** - Cari catatan berdasarkan judul & isi (case-insensitive)
* **Search empty state** - Tampilkan pesan "Tidak ada hasil" saat search kosong
* **Gradle optimization** - Cleanup dependencies yang tidak diperlukan
This commit is contained in:
202310715051 DENDI YOGIA PRATAMA 2025-12-13 02:01:34 +07:00
parent a1e9cb612c
commit 14bf2f2f24
4 changed files with 122 additions and 25 deletions

View File

@ -4,6 +4,14 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-12-12T17:42:15.072692700Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\dendi\.android\avd\Medium_Phone.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>

View File

@ -1,5 +1,3 @@
# **AI Notes Changelog**
## **Tim Pengembang**
@ -25,7 +23,6 @@
* Penambahan validasi input form kategori
* Tampilan kategori Staggered Grid (2 kolom)
* Category Card (ikon folder, nama, jumlah catatan, gradient)
* Long press untuk menghapus kategori
* Empty state kategori
* Implementasi LazyVerticalStaggeredGrid
* Gradient preset 8 warna
@ -36,7 +33,6 @@
* Fitur pin untuk catatan penting
* Full-screen editable note view dengan auto-save
* Fitur arsip, hapus, dan pin di full-screen mode
* Long press untuk mengarsipkan catatan
* Fitur search catatan (judul + isi)
* Sorting catatan berdasarkan pin & timestamp
* Implementasi custom TextField dan date formatter
@ -84,15 +80,27 @@
* Halaman untuk Catatan Berbintang dan Ikon Pesan Berbintang
* Pemberitahuan Konfirmasi untuk Arsip dan Hapus Catatan
## **Sprint 2: Fitur Search & Delete Kategori (Hari Ini)**
* **Fitur search beranda** - Cari kategori berdasarkan nama
* **Search filtering real-time** - Kategori otomatis filter saat mengetik
* **Delete kategori dengan UI** - Tombol X di top-right corner setiap kategori
* **Confirmation dialog untuk delete** - Prevent accidental deletion dengan warning message
* **Search di kategori** - Cari catatan berdasarkan judul & isi (case-insensitive)
* **Search empty state** - Tampilkan pesan "Tidak ada hasil" saat search kosong
* **Gradle optimization** - Cleanup dependencies yang tidak diperlukan
---
## **Fitur Utama Aplikasi**
* Sistem kategori dengan gradient
* Buat/edit/hapus kategori dengan confirmation dialog
* Buat/edit/hapus catatan
* Pin catatan penting
* Full-screen editor
* Search catatan
* Search kategori di beranda
* Search catatan dalam kategori
* Arsip & Sampah dengan restore/delete permanen
* AI Chat powered by Gemini
* AI membaca & menganalisis catatan pengguna
@ -113,3 +121,4 @@
* Multi-language support
---

View File

@ -324,8 +324,10 @@ fun NotesApp() {
}
},
onCategoryLongClick = { category ->
// Delete kategori dan semua catatan di dalamnya
categories = categories.filter { it.id != category.id }
notes = notes.filter { it.categoryId != category.id }
selectedCategory = null
}
)
"starred" -> StarredNotesScreen(
@ -828,6 +830,7 @@ fun MainScreen(
) {
Column(modifier = Modifier.fillMaxSize()) {
if (selectedCategory == null) {
// Beranda: Tampilkan kategori dengan search filtering
if (categories.isEmpty()) {
EmptyState(
icon = Icons.Default.Create,
@ -835,20 +838,41 @@ fun MainScreen(
subtitle = "Tekan tombol + untuk memulai"
)
} else {
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalItemSpacing = 12.dp,
modifier = Modifier.fillMaxSize()
) {
items(categories) { category ->
CategoryCard(
category = category,
noteCount = notes.count { it.categoryId == category.id && !it.isDeleted && !it.isArchived },
onClick = { onCategoryClick(category) },
onLongClick = { onCategoryLongClick(category) }
)
// Filter kategori berdasarkan searchQuery
val filteredCategories = if (searchQuery.isEmpty()) {
categories
} else {
categories.filter {
it.name.contains(searchQuery, ignoreCase = true)
}
}
if (filteredCategories.isEmpty()) {
EmptyState(
icon = Icons.Default.Search,
message = "Kategori tidak ditemukan",
subtitle = "Coba kata kunci lain"
)
} else {
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalItemSpacing = 12.dp,
modifier = Modifier.fillMaxSize()
) {
items(filteredCategories) { category ->
CategoryCard(
category = category,
noteCount = notes.count { it.categoryId == category.id && !it.isDeleted && !it.isArchived },
onClick = { onCategoryClick(category) },
onLongClick = { onCategoryLongClick(category) },
onDelete = {
// Delete kategori dan semua catatan di dalamnya
onCategoryLongClick(category)
}
)
}
}
}
}
@ -898,8 +922,45 @@ fun CategoryCard(
category: Category,
noteCount: Int,
onClick: () -> Unit,
onLongClick: () -> Unit
onLongClick: () -> Unit,
onDelete: () -> Unit = {}
) {
var showDeleteConfirm by remember { mutableStateOf(false) }
// Delete confirmation dialog
if (showDeleteConfirm) {
AlertDialog(
onDismissRequest = { showDeleteConfirm = false },
title = { Text("Hapus Kategori?") },
text = {
Text("Kategori '$${category.name}' dan semua catatan di dalamnya akan dihapus. Tindakan ini tidak dapat dibatalkan.")
},
confirmButton = {
Button(
onClick = {
onDelete()
showDeleteConfirm = false
},
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFEF4444)
)
) {
Text("Hapus", color = Color.White)
}
},
dismissButton = {
Button(
onClick = { showDeleteConfirm = false },
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF64748B)
)
) {
Text("Batal", color = Color.White)
}
}
)
}
Card(
modifier = Modifier
.fillMaxWidth()
@ -945,6 +1006,21 @@ fun CategoryCard(
color = Color.White.copy(0.8f)
)
}
// Delete button di top-right corner
IconButton(
onClick = { showDeleteConfirm = true },
modifier = Modifier
.align(Alignment.TopEnd)
.size(40.dp)
) {
Icon(
Icons.Default.Close,
contentDescription = "Hapus kategori",
tint = Color.White.copy(0.7f),
modifier = Modifier.size(20.dp)
)
}
}
}
}
@ -972,7 +1048,11 @@ fun NoteCard(
),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
@ -1023,7 +1103,6 @@ fun NoteCard(
Spacer(modifier = Modifier.height(12.dp))
// Divider
Divider(
color = Color(0xFF334155),
thickness = 1.dp
@ -2443,3 +2522,4 @@ fun EmptyState(
}
}
}

View File

@ -1,5 +1,5 @@
[versions]
agp = "8.13.1"
agp = "8.13.2"
kotlin = "2.0.21"
coreKtx = "1.10.1"
junit = "4.13.2"